赞
踩
以应用为中心、以计算机技术为基础、软件硬件可裁剪、适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。
以应用为中心
以计算机技术为基础
计算机系统由软件和硬件构成
专用于特定任务
多类型处理器和处理器系统支持
通常极其关注(系统)成本
一般是实时系统
可裁剪性好
可靠性高
大多有功耗约束
嵌入式微控制器(Micro Controller Unit,MCU)/ 单片机
嵌入式微处理器(Embedded Micro Processor Unit,EMPU)
各公司产品
ARM 微处理器
ARM 公司提供 IP 授权生产的芯片,占据 32 位市场份额 90% 以上
MIPS 微处理器
面向高性能、高档次的 32 位和 64 位处理器市场
PowerPC
品种良多,覆盖范围广
x86
源自 Intel 8080,最早的嵌入式芯片,良好的兼容性限制了其性能发展
Motorola 68000
CISC 架构,面向通信应用
嵌入式DSP处理器(Embedded Digital Signal Processor,EDSP)
嵌入式片上系统(System on Chip,SoC)
ARM微处理器采用 RISC 架构
设字数据W1=0x12345678,W1_3=0x12,W1_2=0x34,W1_1=0x56,W1_0=0x78
数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中
数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中
Cortex-M3基础.ppt
线程模式
在复位时处理器进入线程模式,异常返回时也会进人该模式,特权模式和用户(非特权)模式代码能够在线程模式下运行。
处理模式
出现异常时处理器进入处理模式,在处理模式下,所有代码都是特权访问的。
Thumb 状态
16位和32位半字对齐的 Thumb 和 Thumb-2 指令状态
调试状态
处理器停止并进入调试
GPT-4
字节 (8 位):Cortex-M3 支持 8 位字节存储格式,用于存储较小的数据,如字符。
半字 (16 位):Cortex-M3 支持 16 位半字存储格式,用于存储较大的数据,如短整数。
字 (32 位):Cortex-M3 支持 32 位字存储格式,用于存储更大的数据,如整数和浮点数。
Cortex-M3 对半字和字的访问要求进行对齐。对于半字访问,地址必须是 2 的整数倍;对于字访问,地址必须是 4 的整数倍。不对齐的访问可能导致硬件异常。
嵌套向量中断控制器( NVIC )是 ARM Cortex -M3处理器中一个完整的部分。 ARM Cortex -M3的所有中断机制都由 NVIC 实现。 NVIC 可以被高度配置,为处理器提供出色的中断处理能力。在 NVIC 的标准执行中,它提供了一个非屏蔽中断( NMI )和32个通用物理中断,这些中断带有8级的抢占优先权。 NVIC 可以通过综合选择配置为1到240个物理中断中的任何一个,并带有多达256个优先级。
在连续两次中断时,将上一次的返回指令和下一次的调用指令执行所花费的时间,由42个Circles降低到6个Circles。
在两个寄存器间传递数据
MOV R8, R3
在寄存器与存储器间传递数据
在寄存器与特殊功能寄存器间传递数据
MRS <gp_reg>, <special_reg>
功能:读特殊功能寄存器的值到通用寄存器。
MSR <special_reg>, <gp_reg>
功能:写通用寄存器的值到特殊功能寄存器。
把一个立即数加载到寄存器
示例 | 功能描述 |
---|---|
ADD Rd, Rn, Rm ; Rd = Rn+Rm ADD Rd, Rm ; Rd += Rm ADD Rd, #imm ; Rd += imm | 常规加法 imm |
ADC Rd, Rn, Rm ; Rd = Rn+Rm+C ADC Rd, Rm ; Rd += Rm+C ADC Rd, #imm ; Rd += imm+C | 带进位的加法 imm |
ADDW Rd, #imm12 ; Rd += imm12 | 带 |
SUB Rd, Rn ; Rd -= Rn SUB Rd, Rn, #imm3 ; Rd = Rn-imm3 SUB Rd, #imm8 ; Rd -= imm8 SUB Rd, Rn, Rm ; Rd = Rm-Rm | 常规减法 |
SBC Rd, Rm ; Rd -= Rm+C SBC.W Rd, Rn, #imm12 ; Rd= Rn-imm12-C SBC.W Rd, Rn, Rm ; Rd = Rn-Rm-C | 带借位的减法 |
RSB.W Rd, Rn, #imm12 ; Rd = imm12-Rn RSB.W Rd, Rn, Rm ; Rd = Rm-Rn | 反向减法 |
MUL Rd, Rm ; Rd = Rm MUL.W Rd, Rn, Rm ; Rd = RnR | 常规乘法 |
MLA Rd, Rm, Rn, Ra ; Rd = Ra+RmRn MLS Rd, Rm, Rn, Ra ; Rd = Ra-RmR | 乘加与乘减 |
UDIV Rd, Rn, Rm ; Rd = Rn/Rm SDIV Rd, Rn, Rm ; Rd = Rn/Rm | 硬件支持的除法 |
示例 | 功能描述 |
---|---|
AND Rd, Rn ; Rd &= Rn AND.W Rd, Rn, #imm12 ; Rd = Rn & imm12 AND.W Rd, Rm, Rn ; Rd = Rm & Rn | 按位与 |
ORR Rd, Rn ; Rd |= Rn ORR.W Rd, Rn, #imm12 ; Rd = Rn | imm12 ORR.W Rd, Rm, Rn ; Rd = Rm | Rn | 按位或 |
BIC Rd, Rn ; Rd &= ~Rn BIC.W Rd, Rn, #imm12 ; Rd = Rn & ~imm12 BIC.W Rd, Rm, Rn ; Rd = Rm & ~Rn | 位段清零 |
ORN.W Rd, Rn, #imm12 ; Rd = Rn | ~imm12 ORN.W Rd, Rm, Rn ; Rd = Rm | ~Rn | 按位或反码 |
EOR Rd, Rn ; Rd ^= Rn EOR.W Rd, Rn, #imm12 ; Rd = Rn ^ imm12 EOR.W Rd, Rm, Rn ; Rd = Rm ^ Rn | (按位)异或,异或总是按位的 |
最基本的无条件跳转指令
B Lable;跳转到Lable处对应的地址
BX reg;跳转到由寄存器reg给出的地址
在BX中,reg的最低位指示出在转移后将进入的状态,必须保证reg的LSB=1
调用子程序时,使用的指令的助记符为BL。如:
BL Lable; 跳转到Lable对应的地址,并且将跳转前的下条指令地址保存到LR
BLX reg; 跳转到由寄存器reg给出的地址,并根据reg的LSB切换处理器状态,还要将跳转前的下条指令地址保存到LR
BLX还带有改变状态的功能。因此,reg的LSB必须是1,以确保不会试图进入ARM状态,否则会出现Fault。
BX LR ;从子程序返回
选择题34题:记住寄存器名称
低寄存器,R0~R7。
可以被指定通用寄存器的所有指令访问,复位后的初始值是不可预知的。
高寄存器,R8~R12。
可以被指定通用寄存器的所有32位指令访问,但不能被16位指令访问,复位后的初始值是不可预知的。
堆栈指针,R13( SP )。
链接寄存器,R14( LR )。
程序计数器,R15(PC)
程序状态字寄存器组PSRs
这3 个寄存器既可以单独访问,也可以组合访问(2 个组合,3 个组合都可以),当使用三合一的方式访问时,应使用名字“xPSR”或者“PSRs”。
中断屏蔽寄存器组PRIMASK, FAULTMASK, BASEPRI
控制寄存器CONTROL
Cortex-M3基础.ppt
选择题40:记住两端别名地址区
映射分区:
定义:位带别名技术是一种常用的操作内存的方法,可以将一个位的访问转化为对内存的访问,以便更方便地对单个位进行操作。在STM32中,位带别名技术可以通过位带映射区域来实现。
公式:位带别名地址 = 位带映射区域起始地址 + (原始地址 - 0x20000000) × 32 + 位在字节中的偏移量 × 4
其中,位带映射区域起始地址为0x22000000,原始地址每个位所占的地址空间为32位,位在字节中的偏移量指的是位在8位字节中的偏移量,范围为0到7。
举例:第2位的别名地址应该是0x22000000 + 2x4 = 0x22000008。
例题:[选择题 40 题](…/嵌入式选择题-from hqh.md#题目列表)
正常程序执行流程发生暂时停止的情形
外部事件导致的程序执行流程改变
中断是一种特殊的异常
ARM Cortex-M3的所有中断机制都由[NVIC](###嵌套向量中断控制器 NVIC)实现。NVIC除了支持240 个外部中断之外,还支持11个内部异常源。ARM Cortex-M3 处理器和嵌套向量中断控制器(NVIC)对所有异常按优先级进行排序并处理。
编号是指异常入口相对于向量起始表处以字为单位的偏移量
数字越小,优先级越高
0~15号异常中有5个是保留的(11个内部异常源)。1~15号为系统异常的编号,没有编号为0的异常,一般该地址设置MSP的初始值。
主堆栈指针(Main Stack Pointer,MSP)
从16开始的所有编号为外部中断对应的异常的编号。
向量表的每个入口地址都是32位整数
分组配置是在SCB->AIRCR中断分组设置
组 | AIRCR[10:8] | IP bit[7:4] 分配情况 | 分配结果 |
---|---|---|---|
0 | 111 | 0:4 | 0位抢占优先级,4位响应优先级 |
1 | 110 | 1:3 | 1位抢占优先级,3位响应优先级 |
2 | 101 | 2:2 | 2位抢占优先级,2位响应优先级 |
3 | 100 | 3:1 | 3位抢占优先级,1位响应优先级 |
4 | 011 | 4:0 | 4位抢占优先级,0位响应优先级 |
STM32F103VBT6 是 STM32F103xxx 系列 ARM Cortex-M3 处理器中的一种
选择题70题
STM32 103系列有76个中断,16个内核中断,60个可屏蔽中断,16级可编程的中断优先级。
简称 | 名称 | 频率 | 作用 | 来源 | 相关的重要寄存器(位) | 特点 |
---|---|---|---|---|---|---|
HSE | 高速外部时钟 | 4~16MHz | 驱动系统时钟 | 外部晶体/陶瓷振荡器,或用户外部时钟 | RCC_CR中的HSEON、HSERDY、HSEBYP位。 | 时钟频率精度高 |
LSE | 低速外部时钟 | 32.768kHz | 驱动RTC | 外部晶体或陶瓷谐振器,或外部时钟 | RCC_BDCR中的LSEON、LSERDY、LSEBYP位 | 为实时时钟或者其他定时功能提供低功耗且精确的时钟源 |
HSI | 高速内部时钟 | 8MHz | 驱动系统时钟 | 内部8MHz的RC振荡器 | RCC_CR中的HSION、HSIRDY、HSITRIM[4:0]位。 | 启动时间比HSE晶体振荡器短,但时钟频率精度较差。可在HSE晶体振荡器失效时作为备用时钟源。 |
LSI | 低速内部时钟 | 约40kHz (30kHz ~ 60kHz) | 为独立看门狗、RTC和自动唤醒单元提供时钟 | 内部RC振荡器 | RCC_CSR中的的LSION、LSIRDY | 可以在停机和待机模式下保持运行 |
PLL | 锁相环时钟 | <=72MHz | 驱动系统时钟 | HIS或HSE |
位于片上外设存储区,地址范围是0x4002_1000-0x4002_13FF
通用输入/输出口(General Purpose I/O,GPIO)是一个灵活的由软件控制的数字信号,每个GPIO都代表一个连接到CPU特定引脚的一个位。STM32F103VBT6一共有5组I/O口,每组有16个I/O口。
0态
在0态下,GPIO输出低电平;
1态。
在1态下,GPIO输出高电平。
高阻态
在高阻状态下,既不输出高电平也不输出低电平;
- 选择题58:全选
- 选择题59:最好记住
32 位
16 位
复位寄存器:GPIOx_BRR
STM32的GPIO端口的每一位都可以由软件配置成多种模式
选择题65
在STM32中,有许多I/O端口,同时也内置了许多外设,为了节约引出管脚,这些内置外设引出管脚是与通用I/O管脚公用的,当I/O管脚作为这些外设模块的功能引脚时就叫端口复用功能。
一个外设的引脚除了具有默认的引脚位外,还可以通过配置重映射寄存器的方式,把这个外设的引脚映射其他的引脚位。
交叉编译(Cross-Compilation)是指在某个平台上(如PC)用交叉编译器编译出可在其他平台(如ARM)运行的代码的过程
在主机平台上安装对应的交叉编译工具链(cross compilation tool chain),然后用它编译程序源代码,最终生成可在目标平台上运行的代码
#include "led.h" #include "stm32f10x_map.h" //STM32 GPIO TEST //set GPIO Register #define GPIOB_CRL ((unsigned long int *)0x40010C00) #define GPIOB_ODR ((unsigned long int *)0x40010C0C) #define GPIOE_CRH ((unsigned long int *)0x40011804) #define GPIOE_ODR ((unsigned long int *)0x4001180C) //u32 *PE08 = (u32 *)(0x42000000 +(0x4001180D-0x40000000)*32 + 0*4); u32 *PEO8 = (u32 *)(0x42000000 +(0x4001180C-0x40000000)*32 + 8*4);// 对应L0 //延迟Time秒 int delay(int Time) { unsigned short t,i,j; for(t=0;t<Time;t++) for(i=0;i<1000;i++) for(j=0;j<1000;j++) ; return 0; } int main(void) { //LED_Init(); RCC->APB2ENR|=1<<0; //使能AFIO RCC->APB2ENR|=1<<3; //使能PORTB时钟 RCC->APB2ENR|=1<<6; //使能PORTE时钟 AFIO->MAPR |= 0x02000000; //设置PB.3为I/O口可用,且可以SW仿真 *GPIOB_CRL &= 0xFFFF0FFF; *GPIOB_CRL = *GPIOB_CRL | 0x00003000; //PB.3推挽输出 *GPIOB_ODR |= 0x00000008; //PB.3输出高 *GPIOE_CRH &=0X00000000; *GPIOE_CRH |= 0X33333333; //PE.8-15推挽输出 // L0至L7都亮 *GPIOE_ODR |= 0x0000FF00; //PE.8-15输出高 delay(5);//延迟5s while(1) { *GPIOE_ODR = 0x00000100; //LED1亮 delay(2); *PEO8 = 0;//LED1不亮 delay(2); *PEO8 = 1;//LED1亮 delay(2); *GPIOE_ODR = 0x00000200; //LED2 delay(2); *GPIOE_ODR = 0x00000400; //LED3 delay(2); *GPIOE_ODR = 0x00000800; //LED4 delay(2); *GPIOE_ODR = 0x00001000; //LED5 delay(2); *GPIOE_ODR = 0x00002000; //LED6 delay(2); *GPIOE_ODR = 0x00004000; //LED7 delay(2); *GPIOE_ODR = 0x00008000; //LED8 delay(2); } return 0; }
/******************************流水灯************************ * 流水灯 * 现象:二极管从左至右依次全部点亮 *************************************************************/ #include "sys.h" #include "delay.h" #include "led.h" u8 light; int main( void ) { Stm32_Clock_Init( 6 ); //6倍频 delay_init( 72 ); //12M外部晶振 LED_Init(); GPIOE->ODR &= ~(0xff<<8); LED_SEL = 1; //选择二极管 light = 0x01; while( 1 ) { GPIOE->ODR |= (light<<8); delay_ms( 300 ); light = light<<1; if( light==0x00 ) { GPIOE->ODR &= ~(0xff<<8); delay_ms( 300 ); light = 0x01; } } }
/*********************二极管及数码管初始化或实现******************** * 湖南科技大学 ******************************************************************/ #include "led.h" /***************************数码管段选***************************/ u8 segTable[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; u8 segTablePortation[] = {0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef}; /**************************************************** * 初始化二极管LED灯的引脚端口 ******************************************************/ void LED_Init(void) { RCC->APB2ENR|=1<<0; //使能AFIO RCC->APB2ENR|=1<<3; //使能PORTB时钟 RCC->APB2ENR|=1<<6; //使能PORTE时钟 AFIO->MAPR |= 0x02000000; //设置PB.3为I/O口可用,且可以SW仿真 GPIOB->CRL &= 0xFFFF0FFF; GPIOB->CRL |= 0x00003000; //PB.3推挽输出 GPIOB->ODR |= 0x00000008; //PB.3输出高 GPIOE->CRH&=0X00000000; GPIOE->CRH|=0X33333333; //PE.8-15推挽输出 //L0-L7都显示 GPIOE->ODR|=0x0000ff00; //PE.8-15输出高 } /*************************************** * 流水灯选择,或数码管段选 * value:显示的数值对应的段选二进制值 ****************************************/ void LedValue(u8 value) { LED0 = (value&0x01)?1:0; LED1 = (value&0x02)?1:0; LED2 = (value&0x04)?1:0; LED3 = (value&0x08)?1:0; LED4 = (value&0x10)?1:0; LED5 = (value&0x20)?1:0; LED6 = (value&0x40)?1:0; LED7 = (value&0x80)?1:0; } /*************************************** * 数码管显示不带小数点的数值 * 参数 w:显示的位置,即位选,左-右:0-7 * value:要显示的数值 ****************************************/ void SetLed(u8 w, u8 value) { SEL0 = w%2; SEL1 = w/2%2; SEL2 = w/4; LedValue(segTable[value]); } /*************************************** * 数码管显示带小数点的数值 * 参数 w:显示的位置,即位选,左-右:0-7 * value:要显示的数值 ****************************************/ void PortationDisplay(u8 w, u8 value) { SEL0 = w%2; SEL1 = w/2%2; SEL2 = w/4; LedValue( segTablePortation[value] ); }
#include <stm32f10x_map.h> #include <stm32f10x_nvic.h> #include "delay.h" //************************************************************** static u8 fac_us=0;//us延时倍乘数 static u16 fac_ms=0;//ms延时倍乘数 //初始化延迟函数 //SYSTICK的时钟固定为HCLK时钟的1/8 //SYSCLK:系统时钟 void delay_init(u8 SYSCLK) { SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟 HCLK/8 fac_us=SYSCLK/8; fac_ms=(u16)fac_us*1000; } //延时nms //注意nms的范围 //SysTick->LOAD为24位寄存器,所以,最大延时为: //nms<=0xffffff*8*1000/SYSCLK //SYSCLK单位为Hz,nms单位为ms //对72M条件下,nms<=1864 void delay_ms(u16 nms) { u32 temp; SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit) SysTick->VAL =0x00; //清空计数器 SysTick->CTRL=0x01 ; //开始倒数 do { temp=SysTick->CTRL; } while(temp&0x01&&!(temp&(1<<16)));//等待时间到达 SysTick->CTRL=0x00; //关闭计数器 SysTick->VAL =0X00; //清空计数器 } //延时nus //nus为要延时的us数. void delay_us(u32 nus) { u32 temp; SysTick->LOAD=nus*fac_us; //时间加载 SysTick->VAL=0x00; //清空计数器 SysTick->CTRL=0x01 ; //开始倒数 do { temp=SysTick->CTRL; } while(temp&0x01&&!(temp&(1<<16)));//等待时间到达 SysTick->CTRL=0x00; //关闭计数器 SysTick->VAL =0X00; //清空计数器 }
选择题67:最好记住
位 0: a (顶部水平段)
位 1: b (右上角垂直段)
位 2: c (右下角垂直段)
位 3: d (底部水平段)
位 4: e (左下角垂直段)
位 5: f (左上角垂直段)
位 6: g (中间水平段)
位 7: dp (小数点)
unsigned char code table[] = { //共阴极 0—F 数码管编码
0x3f, 0x06, 0x5b, 0x4f, //0~3
0x66, 0x6d, 0x7d, 0x07, //4-7
0x7f, 0x6f, 0x77, 0x7c, //8~b
0x39, 0x5e, 0x79, 0x71 //c~f
//0x00//数码管不显示
//0x40//显示-(中间水平段)
}
/******************************8位数码管动态扫描************************ * 8位数码管动态扫描 * 每位数码管显示的数字从0加到9 ***********************************************************************/ #include "sys.h" #include "delay.h" #include "led.h" #define uchar unsigned char uchar show_w1,show_w2,show_w3,show_w4,show_w5,show_w6,show_w7,show_w8,flag,count; uchar seg[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; /***************************主函数*****************************/ int main() { //uchar i; Stm32_Clock_Init( 6 ); delay_init( 72 ); LED_Init(); LED_SEL = 0; show_w1=0; show_w2=1; show_w3=2; show_w4=3; show_w5=4; show_w6=5; show_w7=6; show_w8=7; while(1) { SetLed(0, show_w1%10); delay_ms(100); SetLed(1, show_w2%10); delay_ms(100); SetLed(2, show_w3%10); delay_ms(100); SetLed(3, show_w4%10); delay_ms(100); SetLed(4, show_w5%10); delay_ms(100); SetLed(5, show_w6%10); delay_ms(100); SetLed(6, show_w7%10); delay_ms(100); SetLed(7, show_w8%10); delay_ms(100); show_w1++; show_w2++; show_w3++; show_w4++; show_w5++; show_w6++; show_w7++; show_w8++; } }
/****************LED灯有关实现函数******************** * 作者:宁晓兰 ******************************************************************/ #include "led.h" /***************************数码管段选***************************/ u8 segTable[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; u8 segTablePortation[] = {0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};//带小数点 /**************************************************** * 初始化二极管LED灯的引脚端口 ******************************************************/ void LED_Init() { RCC->APB2ENR|=1<<0; //使能AFIO RCC->APB2ENR|=1<<3; //使能PORTB时钟 RCC->APB2ENR|=1<<6; //使能PORTE时钟 AFIO->MAPR |= 0x02000000; //复用口设置 设置PB.3为I/O口可用,且可以SW仿真 GPIOB->CRL &= 0xFFFF0000; GPIOB->CRL |= 0x00003333; //PB.3推挽输出 GPIOB->ODR |= 0x000000FF; //PB.3输出高 GPIOE->CRH&=0X00000000; GPIOE->CRH|=0X33333333; //PE.8-15推挽输出 GPIOE->ODR|=0x0000FF00; //PE.8-15输出高 } /*************************************** * 流水灯选择,或数码管段选 * 将传入的数值value转换成对应的段选二进制值,再通过GPIOE寄存器写入到对应的引脚上,从而实现数码管的控制。 * value:显示的数值对应的段选二进制值 ****************************************/ void LedValue(u8 value) { GPIOE->ODR &= ~(0xff<<8);//置为0,清空显示 GPIOE->ODR |= value<<8;//对应位置位 // LED0 = (value&0x01)?1:0; // LED1 = (value&0x02)?1:0; // LED2 = (value&0x04)?1:0; // LED3 = (value&0x08)?1:0; // LED4 = (value&0x10)?1:0; // LED5 = (value&0x20)?1:0; // LED6 = (value&0x40)?1:0; // LED7 = (value&0x80)?1:0; } /*************************************** * 数码管显示不带小数点的数值 * 参数 w:显示的位置,即位选,左-右:0-7 * value:要显示的数值 ****************************************/ void SetLed(u8 w, u8 value) { //SEL0、SEL1、SEL2分别是控制数码管位选的引脚。 SEL0 = w%2;//最低位 SEL1 = w/2%2;//第二位 SEL2 = w/4;//最高位 LedValue(segTable[value]); } /*************************************** * 数码管显示带小数点的数值 * 参数 w:显示的位置,即位选,左-右:0-7 * value:要显示的数值 ****************************************/ void PortationDisplay(u8 w, u8 value) { SEL0 = w%2; SEL1 = w/2%2; SEL2 = w/4; LedValue( segTablePortation[value] ); }
#include "sys.h" #include "delay.h" #include "led.h" #include "key.h" //按键输入实验 int main(void) { u8 t; Stm32_Clock_Init(9); //系统时钟设置 delay_init(72); //延时初始化 LED_Init(); //初始化与LED连接的硬件接口 KEY_Init(); //初始化与按键连接的硬件接口 while(1) { t=KEY_Scan();//得到键值 if(t) { switch(t) { case 1: LED0=!LED0; break; case 2: LED3=!LED3; break; case 3: LED7=!LED7; break; } }else delay_ms(10); } }
/*********************二极管及数码管初始化或实现******************** * ******************************************************************/ #include "led.h" /***************************数码管段选***************************/ u8 segTable[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; u8 segTablePortation[] = {0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef}; /**************************************************** * 初始化二极管LED灯的引脚端口 ******************************************************/ void LED_Init(void) { RCC->APB2ENR|=1<<0; //使能AFIO RCC->APB2ENR|=1<<3; //使能PORTB时钟 RCC->APB2ENR|=1<<6; //使能PORTE时钟 AFIO->MAPR |= 0x02000000; //设置PB.3为I/O口可用,且可以SW仿真 GPIOB->CRL &= 0xFFFF0FFF; GPIOB->CRL |= 0x00003000; //PB.3推挽输出 GPIOB->ODR |= 0x00000008; //PB.3输出高 GPIOE->CRH&=0X00000000; GPIOE->CRH|=0X33333333; //PE.8-15推挽输出 GPIOE->ODR|=0x00000000; //PE.8-15输出低 } /*************************************** * 流水灯选择,或数码管段选 * value:显示的数值对应的段选二进制值 ****************************************/ void LedValue(u8 value) { LED0 = (value&0x01)?1:0; LED1 = (value&0x02)?1:0; LED2 = (value&0x04)?1:0; LED3 = (value&0x08)?1:0; LED4 = (value&0x10)?1:0; LED5 = (value&0x20)?1:0; LED6 = (value&0x40)?1:0; LED7 = (value&0x80)?1:0; } /*************************************** * 数码管显示不带小数点的数值 * 参数 w:显示的位置,即位选,左-右:0-7 * value:要显示的数值 ****************************************/ void SetLed(u8 w, u8 value) { SEL0 = w%2; SEL1 = w/2%2; SEL2 = w/4; LedValue(segTable[value]); } /*************************************** * 数码管显示带小数点的数值 * 参数 w:显示的位置,即位选,左-右:0-7 * value:要显示的数值 ****************************************/ void PortationDisplay(u8 w, u8 value) { SEL0 = w%2; SEL1 = w/2%2; SEL2 = w/4; LedValue( segTablePortation[value] ); }
#include "key.h" #include "delay.h" //按键输入 驱动代码 //PC0.1.2 设置成输入 void KEY_Init(void) { RCC->APB2ENR|=1<<4; //使能PORTC时钟 GPIOC->CRL&=0XFFFFF000;//PC0-2设置成输入 GPIOC->CRL|=0X00000888; } //按键处理函数 //返回按键值 //0,没有任何按键按下 //1,KEY1按下 //2,KEY2按下 //3,KEY3按下 //注意此函数有响应优先级,KEY1>KEY2>KEY3!! //如果同时按下了多个按键,只有优先级最高的按键会被响应,其他的将被忽略。 u8 KEY_Scan(void) { static u8 key_up=1;//按键按松开标志 //当key_up为1且任意一个按键被按下时,说明有按键被按下,此时进行去抖动处理并将key_up置为0,表示按键被按下。 if(key_up && (KEY1==0 || KEY2==0 || KEY3==0)) { delay_ms(10);//去抖动 key_up=0; if(KEY1==0) { return 1; } else if(KEY2==0) { return 2; } else if(KEY3==0) { return 3; } } else if(KEY1==1 && KEY2==1 && KEY3==1) key_up=1; //当所有按键都没有被按下时,将key_up置为1,以便下一次按键扫描。 return 0;// 无按键按下 }
#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" int main( void ) { /*u8 i = 1; Stm32_Clock_Init( 6 ); //9倍频 delay_init( 72 ); //12M外部晶振 uart_init( 72, 9600 ); while( 1 ) { //printf( "i = %d\r\n", i ); i++; delay_ms( 500 ); } */ u8 t; u8 len; u16 times=0; Stm32_Clock_Init(6); //系统时钟设置 delay_init(72); //延时初始化 uart_init(72,9600); //串口初始化为9600 LED_Init(); //初始化与LED连接的硬件接口 while(1) { if(USART_RX_STA&0x80) { len=USART_RX_STA&0x3f;//得到此次接收到的数据长度 printf("\n Your MSG: \n"); for(t=0;t<len;t++) { USART1->DR=USART_RX_BUF[t]; while((USART1->SR&0X40)==0);//等待发送结束 } printf("\n\n");//插入换行 USART_RX_STA=0; }else { times++; if(times%5000==0) { printf("\nSTM32A Usart\n"); } if(times%200==0) printf("Please Input end with return\n"); if(times%30==0) LED0=!LED0;//闪烁LED,提示系统正在运行. delay_ms(10); } } }
#include "sys.h" #include "usart.h" // //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //******************************************************************************** //V1.3修改说明 //支持适应不同频率下的串口波特率设置. //加入了对printf的支持 //增加了串口接收命令功能. //修正了printf第一个字符丢失的bug // // //加入以下代码,支持printf函数,而不需要选择use MicroLIB #if 1 #pragma import(__use_no_semihosting) //标准库需要的支持函数 struct __FILE { int handle; /* Whatever you require here. If the only file you are using is */ /* standard output using printf() for debugging, no file handling */ /* is required. */ }; /* FILE is typedef’ d in stdio.h. */ FILE __stdout; //定义_sys_exit()以避免使用半主机模式 _sys_exit(int x) { x = x; } //重定义fputc函数 int fputc(int ch, FILE *f) { while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 USART1->DR = (u8) ch; return ch; } #endif //end // #ifdef EN_USART1_RX //如果使能了接收 //串口1中断服务程序 //注意,读取USARTx->SR能避免莫名其妙的错误 u8 USART_RX_BUF[64]; //接收缓冲,最大64个字节. //接收状态 //bit7,接收完成标志 //bit6,接收到0x0d //bit5~0,接收到的有效字节数目 u8 USART_RX_STA=0; //接收状态标记 void USART1_IRQHandler(void) { u8 res; if(USART1->SR&(1<<5))//接收到数据 { res=USART1->DR; if((USART_RX_STA&0x80)==0)//接收未完成 { if(USART_RX_STA&0x40)//接收到了0x0d { if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始 else USART_RX_STA|=0x80; //接收完成了 }else //还没收到0X0D { if(res==0x0d)USART_RX_STA|=0x40; else { USART_RX_BUF[USART_RX_STA&0X3F]=res; USART_RX_STA++; if(USART_RX_STA>63)USART_RX_STA=0;//接收数据错误,重新开始接收 } } } } } #endif //初始化IO 串口1 //pclk2:PCLK2时钟频率(Mhz) //bound:波特率 //CHECK OK //091209 //串口初始化 void uart_init(u32 pclk2,u32 bound) { float temp;//浮点型临时变量 u16 mantissa;//分频器除法因子的整数部分 u16 fraction;//分频器除法因子的分数部分 temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV mantissa=temp; //得到整数部分 fraction=(temp-mantissa)*16; //得到小数部分 mantissa<<=4; mantissa+=fraction; //得到分频器除法因子 RCC->APB2ENR|=1<<2; //使能PORTA口时钟 RCC->APB2ENR|=1<<14; //使能串口时钟 GPIOA->CRH&=0XFFFFF00F; GPIOA->CRH|=0X000008B0;//IO 口状态设置 RCC->APB2RSTR|=1<<14; //复位串口1 RCC->APB2RSTR&=~(1<<14);//停止复位 //波特率设置 USART1->BRR=mantissa; // 波特率设置 USART1->CR1|=0X200C; //1位停止,无校验位. #ifdef EN_USART1_RX //如果使能了接收 //使能接收中断 USART1->CR1|=1<<8; //PE中断使能 USART1->CR1|=1<<5; //接收缓冲区非空中断使能 //初始化串口中断 MY_NVIC_Init(3,3,USART1_IRQChannel,2);//组2,最低优先级 #endif }
/******************************温度与光照测量************************ * 温度与光照 * 温度显示与左边,光照显示在右边 ******************************************************************/ #include "sys.h" #include "led.h" #include "delay.h" #include "adc.h" /***************************主函数*****************************/ int main() { float adcx = 0.0; u16 adcValue = 0; u8 i = 0; Stm32_Clock_Init( 6 ); delay_init( 72 ); TemperatureAndLightAdcInit(); LED_Init(); LED_SEL = 0; adcx = GetTemperature(); //使用PC5 ADC1, 通道15 adcValue = GetLightAdc(14); //使用PC4 ADC1, 通道14 while(1) { i++; if( i > 50 ) //大约每隔100个循环周期重新扫描一次ADC的值 { adcx = GetTemperature(); //使用PC5 ADC1, 通道15 adcValue = GetLightAdc(14); //使用PC4 ADC1, 通道14 i = 0; } //温度 SetLed(0, adcx/10); delay_ms(1); PortationDisplay(1,(u8)adcx%10); delay_ms(1); SetLed(2, (u8)(adcx*10)%10); delay_ms(1); //光照 SetLed(4, adcValue/1000); delay_ms(1); SetLed(5, adcValue%1000/100); delay_ms(1); SetLed(6, adcValue%100/10); delay_ms(1); SetLed(7, adcValue%10); delay_ms(1); } }
/****************************************************** * 双ADC通道测电压值 * 测量电压应<3.3 PA0或PA1接正极,负极接地 * PA0测量的电压显示与左边,PA1测量的电压值显示与右边 ******************************温度与光照测量************************ * 温度与光照 * 温度显示与左边,光照显示在右边 ***********************************END****************************** 作者:宁晓兰 ******************************************************************/ #include "adc.h" #include "math.h" /****************初始化函数******************** * 初始化 * IO口初始化、ADC1初始化、ADC2初始化 ******************************************************/ void VoltageAdcInit(void) { //初始化IO口 RCC->APB2ENR |= 1<<2; //使能PORTA口时钟 GPIOA->CRL &= 0xffffff00; //PA0 1 模拟输入 RCC->CFGR &= ~(3<<14); //分频因子清零 RCC->CFGR |= 2<<14; //6分频 SYSCLK/DIV2=12M ADC时钟设置为12M,ADC1最大时钟不能超过14M! VoltageAdc1Init(); VoltageAdc2Init(); } /****************初始化函数******************** * ADC1初始化 ******************************************************/ void VoltageAdc1Init(void) { RCC->APB2ENR |= 1<<9; //ADC1时钟使能 RCC->APB2RSTR |= 1<<9; //ADC1复位 RCC->APB2RSTR &= ~(1<<9); //复位结束 ADC1->CR1 &= 0xf0ffff; //工作模式清零 ADC1->CR1 |= 0<<16; //独立工作模式 ADC1->CR1 &= ~(1<<8); //非扫描模式 ADC1->CR2 &= ~(1<<1); //单次转换模式 ADC1->CR2 &= ~(7<<17); ADC1->CR2 |= 7<<17; //SWSTART:软件控制转换 ADC1->CR2 |= 1<<20; //使用外部触发(SWSTART),必须使用一个事件来触发 ADC1->CR2 &= ~(1<<11); //右对齐 ADC1->SQR1 &= ~(0xf<<20); ADC1->SQR1 &= 0<<20; //1个转换在规则序列中,也就是只转换规则序列1 ADC1->SMPR2 &= 0xfffffff0; //通道0采样时间清空 ADC1->SMPR2 |= 7<<0; //通道0 239.5周期,提高采用时间可以提高精确度 ADC1->CR2 |= 1<<0; //开启AD转换器 ADC1->CR2 |= 1<<3; //使能复位校准 while( ADC1->CR2 & 1<<3 ) ; //等待校准结束 ADC1->CR2 |= 1<<2; //开启AD校准 while( ADC1->CR2 & 1<<2 ) ; //等待校准结束 } /****************初始化函数******************** * ADC2初始化 ******************************************************/ void VoltageAdc2Init(void) { RCC->APB2ENR |= 1<<10; //ADC1时钟使能 RCC->APB2RSTR |= 1<<10; //ADC1复位 RCC->APB2RSTR &= ~(1<<10); //复位结? ADC2->CR1 &= 0xf0ffff; //工作模式清零 ADC2->CR1 |= 0<<16; //独立工作模式 ADC2->CR1 &= ~(1<<8); //非扫描模式 ADC2->CR2 &= ~(1<<1); //单次转换模式 ADC2->CR2 &= ~(7<<17); ADC2->CR2 |= 7<<17; //SWSTART:软件控制转换 ADC2->CR2 |= 1<<20; //使用外部触发(SWSTART),必须使用一个事件来触发 ADC2->CR2 &= ~(1<<11); //右对齐 ADC2->SQR1 &= ~(0xf<<20); ADC2->SQR1 &= 0<<20; //1个转换在规则序列中,也就是只转换规则序列1 ADC2->SMPR2 &= ~(7<<3); //通道1采样时间清空 ADC2->SMPR2 |= 7<<3; //通道1 239.5周期,提高采用时间可以提高精确度 ADC2->CR2 |= 1<<0; //开启AD转换器 ADC2->CR2 |= 1<<3; //使能复位校准 while( ADC2->CR2 & 1<<3 ) ; //等待校准结束 ADC2->CR2 |= 1<<2; //开启AD校准 while( ADC2->CR2 & 1<<2 ) ; //等待校准结束 } /****************获取ADC值函数******************** * 获取ADC的值,测量的电压应<3.3 PA0或PA1接正极,负极接地 * adcx: 1表示ADC1; 2表示ADC2 * ch: 通道值 * 返回得到的ADC的值 ******************************************************/ u16 GetAdc(u8 adcx, u8 ch) { u16 adcValue = 0; if( adcx==1 ) { //设置转换序列 ADC1->SQR3 &= 0xffffffe0; //规则序列1 通道ch ADC1->SQR3 |= ch; ADC1->CR2 |= 1<<22; //启动规则转换通道 while( !(ADC1->SR & 1<<1) ) ; //等待转换结束 adcValue = ADC1->DR; } else if( adcx==2 ) { //设置转换序列 ADC2->SQR3 &= 0xffffffe0; //规则序列1 通道ch ADC2->SQR3 |= ch; ADC2->CR2 |= 1<<22; //启动规则转换通道 while( !(ADC2->SR & 1<<1) ) ; //等待转换结束 adcValue = ADC2->DR; } return adcValue; //返回ADC的值 } /****************获取电压值函数******************** * ADC转化为电压值 * adcx: 1表示ADC1; 2表示ADC2 * ch: 通道值 * 返回电压值 ******************************************************/ float GetVoltage(u8 adcx, u8 ch) { u16 adcValue = 0; float vol = 0; adcValue = GetAdc( adcx, ch ); vol = 3.3*(float)adcValue/4096; return vol; } /****************显示对应端口的电压值函数******************** * 显示,占三位 * adcx: 1表示ADC1; 2表示ADC2 * vol: 电压值 * PA0测量的电压显示与左边,PA1测量的电压值显示与右边 ******************************************************/ void VoltageDisplay(u8 adcx, float vol) { u8 baiWei, shiWei, geWei; baiWei = (u8)vol % 10; shiWei = (u8)(vol*10)%10; geWei = (u8)(vol*100)%10; if( adcx==1 ) { PortationDisplay(0, baiWei); delay_ms(1); SetLed(1, shiWei); delay_ms(1); SetLed(2, geWei); delay_ms(1); } else if( adcx==2 ) { PortationDisplay(5, baiWei); delay_ms(1); SetLed(6, shiWei); delay_ms(1); SetLed(7, geWei); delay_ms(1); } } /***************温度和光照ADC的初始化函数******************** * 初始化ADC1,通道14 15 ******************************************************/ void TemperatureAndLightAdcInit(void) { //初始化IO口 RCC->APB2ENR |= 1<<4; //使能PORTC口时钟 GPIOA->CRL &= 0xff00ffff; //PC4 5 模拟输入 RCC->CFGR &= ~(3<<14); //分频因子清零 RCC->CFGR |= 2<<14; //6分频 SYSCLK/DIV2=12M ADC时钟设置为12M,ADC1最大时钟不能超过14M! RCC->APB2ENR |= 1<<9; //ADC1时钟使能 RCC->APB2RSTR |= 1<<9; //ADC1复位 RCC->APB2RSTR &= ~(1<<9); //复位结束 ADC1->CR1 &= 0xf0ffff; //工作模式清零 ADC1->CR1 |= 0<<16; //独立工作模式 ADC1->CR1 &= ~(1<<8); //非扫描模式 ADC1->CR2 &= ~(1<<1); //单次转换模式 ADC1->CR2 &= ~(7<<17); ADC1->CR2 |= 7<<17; //SWSTART:软件控制转换 ADC1->CR2 |= 1<<20; //使用外部触发(SWSTART),必须使用一个事件来触发 ADC1->CR2 &= ~(1<<11); //右对齐 ADC1->SQR1 &= ~(0xf<<20); ADC1->SQR1 &= 0<<20; //1个转换在规则序列中,也就是只转换规则序列1 ADC1->SMPR1 &= 0xfffc0fff; //通道14,15采样时间清空 ADC1->SMPR1 |= 7<<12; //通道14 239.5周期,提高采用时间可以提高精确度 ADC1->SMPR1 |= 7<<15; //通道15 239.5周期,提高采用时间可以提高精确度 ADC1->CR2 |= 1<<0; //开启AD转换器 ADC1->CR2 |= 1<<3; //使能复位校准 while( ADC1->CR2 & 1<<3 ) ; //等待校准结束 ADC1->CR2 |= 1<<2; //开启AD校准 while( ADC1->CR2 & 1<<2 ) ; //等待校准结束 } /***************获取温度的ADC的值函数******************** * 获取ADC1的ADC值 * ch为通道值 * 返回ADC1的ADC值 ******************************************************/ u16 GetTemperatureAdc(u8 ch) { u16 adcValue = 0; adcValue = GetAdc( 1,ch ); return adcValue; } /***************ADC值转换成温度值函数******************** * 通过ADC值计算温度值 * 返回温度值 ******************************************************/ float GetTemperature( void ) { u16 temperatureAdc = 0; float temperature = 0.0; temperatureAdc = GetTemperatureAdc( 15 ); //通道15注入的AD值 temperature = (float)temperatureAdc*(3.3/4096); //当前温度电压值 temperature = temperature *10000/(3.3-temperature)/1000; //温度电阻阻值 temperature = (float)1.0/( (float)log(temperature*1000/10000)/3950 + 1.0/(273.16+25) ) - 273.16; //计算温度 return temperature; } /***************光照强度的ADC值函数******************** * 光照强度的ADC值 * ch为通道值 * 返回光照的ADC值 ******************************************************/ u16 GetLightAdc(u8 ch) { u16 adcValue = 0; adcValue = GetAdc(1, ch); return adcValue; }
高级定时器
通用定时器
TIME2~5
基本定时器
看门狗定时器
/******************************定时中断实现数字钟************************ * 数字钟 * 通过控制定时中断实现数字钟 ******************************************************************/ #include "timer.h" /***************************主函数*****************************/ int main() { Stm32_Clock_Init( 6 ); delay_init( 72 ); TimerxInit( 9999,7199 ); 10Khz的计数频率,计数到10000表示1s LED_Init(); LED_SEL = 0; while(1) { DisplayDigitalClock(); } }
/****************定时器实现******************** * * 作者:宁晓兰 ***************************************************/ #include "timer.h" //数字钟的时,分、秒 u8 hour = 0, minute = 0, second = 0; /****************普通按键初始化函数******************** * 通用定时器中断初始化 * 这里时钟选择为APB1的2倍,而APB1为36M * arr:自动重装值。 * psc:时钟预分频数 * 这里使用的是定时器3! ******************************************************/ void TimerxInit(u16 arr, u16 psc) { RCC->APB1ENR |= 1<<1; //TIM3(定时器3)时钟使能 TIM3->ARR = arr; //设定计数器自动重装值,10为1ms TIM3->PSC = psc; //预分频器7200,得到10KHZ的计数时钟 TIM3->DIER |= 1<<0; //允许更新中断 TIM3->CR1 |= 0x01; //使能定时器3 MY_NVIC_Init(1, 3, TIM3_IRQChannel, 2); //抢占1,子优先级(响应优先级)3,组2 /* 注意,优先级数值越小,越优先。在设置中断优先级时,要确保优先级不能超过设定的组的范围,否则可能会导致意想不到的错误。 组0:0位抢占优先级,4位响应优先级; 组1:1位抢占优先级,3位响应优先级; 组2:2位抢占优先级,2位响应优先级; 组3:3位抢占优先级,1位响应优先级; 组4:4位抢占优先级,0位响应优先级。 */ } /****************定时器3的中断函数******************** * 定时器3的中断函数 * 每次中断,second加一 ******************************************************/ void TIM3_IRQHandler( void ) { if( TIM3->SR & 0x0001) //溢出中断 { second++; if( second>59 ) { second = 0; minute++; if( minute>59 ) { minute = 0; hour++; if( hour>23 ) hour = 0; } } } TIM3->SR &= ~(1<<0); //清除中断标志位 } /***************************************************** * 数字钟显示函数 ******************************************************/ void DisplayDigitalClock(void) { //从左到右 SetLed(0, hour/10);//小时的高位 delay_ms(1); SetLed(1, hour%10);//小时的低位 delay_ms(1); SetLed(2, 10);//0x40//显示-(中间水平段) delay_ms(1); SetLed(3, minute/10); delay_ms(1); SetLed(4, minute%10); delay_ms(1); SetLed(5, 10); delay_ms(1); SetLed(6, second/10); delay_ms(1); SetLed(7, second%10); delay_ms(1); }
嵌入式操作系统(Embedded Operating System,简称:EOS)是指用于嵌入式系统的操作系统。嵌入式操作系统是一种用途广泛的系统软件,通常包括与硬件相关的底层驱动软件、系统内核、设备驱动接口、通信协议、图形界面、标准化浏览器等。嵌入式操作系统负责嵌入式系统的全部软、硬件资源的分配、任务调度,控制、协调并发活动。它必须体现其所在系统的特征,能够通过装卸某些模块来达到系统所要求的功能。
通用操作系统可运行在不同的硬件平台,而嵌入式操作系统与一般的Windows操作系统不同,其是一种专用、可定制的操作系统。
μC/OS-II已经在世界范围内得到广泛应用,包括很多领域, 如手机、路由器、集线器、不间断电源、飞行器、医疗设备及工业控制上。
复杂性:随着嵌入式系统的功能越来越复杂,系统的设计、开发和测试也变得越来越困难。嵌入式系统需要支持多种功能和通信协议,同时还需要考虑功耗、安全、可靠性等因素,这使得系统的设计和开发变得更加复杂。
安全性:嵌入式系统通常需要处理敏感数据和控制重要设备,因此需要具备高度的安全性。嵌入式系统需要采用安全的通信协议和加密算法,以保护数据的机密性和完整性。同时,嵌入式系统还需要具备防护措施,以防止恶意攻击和非法访问。
资源限制:嵌入式系统通常具有资源限制,如处理器速度、存储容量和功耗等。这使得系统的设计和开发需要更加注重资源的优化和利用,以实现系统的高效运行和长时间的使用寿命。
chatGPT-3.5
物联网(IoT):随着物联网技术的发展,越来越多的设备和系统需要嵌入式系统来实现智能化和互联互通。嵌入式系统需要支持多种通信协议和网络连接方式,如 Wi-Fi、蓝牙、ZigBee、LoRa 等,以实现设备之间的数据交换和远程控制。
人工智能(AI):人工智能技术的发展为嵌入式系统带来了新的机遇和挑战。嵌入式系统需要支持高效的计算和数据处理能力,以实现机器学习、图像识别、语音识别等 AI 应用。
安全性:随着嵌入式系统的广泛应用,安全性问题也越来越受到关注。嵌入式系统需要具备安全性能,包括数据加密、身份认证、访问控制等功能,以保护系统和数据的安全。
低功耗:嵌入式系统通常需要长时间运行,因此需要具备低功耗的特点,以延长系统的使用寿命。嵌入式系统需要采用低功耗的处理器、传感器和通信模块,以及优化的电源管理技术,以实现长时间的运行和待机。
自动化:嵌入式系统需要支持自动化和智能化的特点,以提高系统的效率和可靠性。嵌入式系统需要具备自动化控制、自适应调节、故障检测和自我修复等功能,以实现自动化运行和维护。
文心一言
嵌入式处理器的选型原则通常包括以下几个方面:
在选择嵌入式处理器时,还需要考虑以下因素:
综上所述,嵌入式处理器的选型需要考虑多个因素,需要根据系统需求、性能、成本、开发工具和已有资源等因素进行选择。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。