STM32
1、keil的配置以及vscode的配置略
2、stm32的命名规则 todo 以下以stm32lf103ze为例。
3、点亮第一个小灯
开启时钟、设置输入/输出模式、给小灯的位赋值0。
- 开启时钟
- 开启时钟使用到的寄存器为RCC_APB2ENR,32位,高16位为保留位。
- 第二位IOPA控制IO端口A的输入输出使能。其他具体每一位什么功能看数据手册。
- 设置输入/输出模式
- 用到GPIOA_CRL / GPIOA_CRH。这两个寄存器每个都是32位,每个只能给8个输入/输出设置模式(每4bit给一个输入/输出位设置模式),两个加起来可以给16个输入/输出设置模式
- 具体使用以及复位值见参考手册。
- 给小灯的位赋值
- 用到GPIOA_ODR(输出寄存器)。32位,高16位保留。
我们可以使用方便的方法,比如引入 stm32f10x.h 库来让以上的设置更见名知意。
4、寄存器和引脚 todo
5、GPIO的8种工作模式
GPIO输入输出电路里有一个P-MOS管和一个N-MOS管。 P-MOS管栅极接低电平导通,N-MOS管栅极接高电平导通。 P-MOS管的符号可以在前面加上一个小圆圈,有的也不加。加小圆圈的就是说这个是低电平导通,方便记一下。
- 输入浮空
- 输入上拉
- 输入下拉
- 以上的三个输入状态是管无输入时的输入值。比如选择输入上拉时,没有往芯片中输入数据,则为输入被上拉拉为1。
- 模拟输入
- 输入模拟信号,即没有走内部的施密特触发器,输入为模拟信号。
- 开漏输出。
- 利用上拉电阻实现。
- 使用场景如 需要外部上拉电阻确定高电平、多个设备共用信号线…
- 推挽式输出。
- 使用场景如 todo
- 推挽式复用功能。暂略。
- 开漏复用功能。暂略。
6、时钟
-
HSI —- 高速内部时钟;
- RC振荡器产生。8MHz。
-
HSE —- 高速外部时钟;
- 在外部接的一个8MHz的晶振。
-
LSI —- 低速内部时钟;
- 大概40kHz。不能驱动系统时钟。
-
LSE —- 低速外部时钟;
- 32.768kHz。不能驱动系统时钟。
-
PLL —- 锁环器/倍频器。
7、中断
-
NVIC (嵌套向量中断控制器) 作用为协调中断。
- 来自内核的中断。如 系统滴答定时器。 直接由NVIC协调。
- 来自内部外设的中断。 如 串口、定时器、IIC等。直接由NVIC协调。
- 来自外部的中断。 如 PA-PG那112个引脚。 AFIO –> EXTI –> NVIC。
-
中断的优先级
- 中断的优先级占4个二进制位。
- 分为 抢占优先级 和 响应优先级。 两种优先级可以分这4个位。比如可以全部分给抢占。这个用3-7来配置。 从3开始,3表示4个位全给抢占;7表示4个位全给响应。
- 先比抢占,再比响应,再查表。(两个没执行的中断的比较。)
- 如果一个中断在执行,另一个中断只有抢占大于它时才能打断。
-
中断的配置。
-
开启时钟 (GPIO的复用引脚 和 AFIO)
-
配置GPIO模式 比如我们想要设置下拉输入(我们想要上升沿生效,则需要设置下拉输入),然后记得把ODR也设置一下才能实现下拉,ODR设置0位。
-
配置AFIO,用于将引脚复用为外部中断。比如 将外部中断10的位置指定上PF寄存器,也就是 将PF10引脚 指定为外部中断。
-
配置EXTI。 (1、EXTI->RTSR配置上升沿触发; 2、EXTI->IMR开放对应的屏蔽寄存器。)
-
配置NVIC。(1、优先级组; 2、优先级; 3、使能中断。)
-
中断服务函数。写中断触发后要实现的功能。记得 EXTI->PR 设置挂起寄存器(0没有触发请求,1触发了请求(1即清位,需要我们手动清))。
刚开始挂起寄存器EXTI->PR为0,有中断进来,对应的位变为1,进入中断后,我们再给它1让它再清零。
-
8、通讯
-
串行:一次传输一个bit。 通讯距离远(USB线就算远了)、抗干扰能力强、成本低。
-
并行:一次传输n个bit。 传输速率高。(一般设备内部间通讯用并行)
-
单工:只能一方发送数据。如收音机。
-
半双工:同一时间只能一方发送。如对讲机。
-
全双工共:两端可以同时接收数据。如手机。
-
同步:要求收发两端时钟保持一致。(共用同一个时钟,比如两个设备连接上SCL这一根时钟线。)
-
异步:不要求时钟一致。
stm32的串口通信是有三个支持同步通信,由于异步没有时钟的要求,所以需要通讯设备之间约定好波特率,即每秒传输/接收多少个bit。先发低位,后发高位。(USART串口同步异步接收器可以实现同步,UART就是同步)。一个设备的发送接另一个的接收,这要两个设备各两条线,再来个两设备共地的线。关于同步异步以及频率看后面记的时钟数和命名。 todo
stm32的IIC通信是同步串行半双工通讯。先发高位,后发低位。todo
IIC硬件实现代码:https://www.cnblogs.com/wangsiyaoa/p/17970700
9、定时器
-
系统滴答定时器。
- STK_CTRL寄存器。
- 第0位:ENABLE 控制能否计数的使能,为1能计数。放在初始化的最后一步。
- 第1位:TICKINT 控制能否产生中断的使能,为1能产生中断。当我们使用滴答定时器作延时函数使用时,置0不使用中断。
- 第2位:CLKSOURCE 时钟源,控制计数器的时钟频率。 为0进行一次8分频,为1不分频。
- 第16位:COUNTFLAG 控制计数是否完成,滴答定时器是向下计数,所以当计数为0时,此位变为1。 变为0的时机不能确定,大概变为0后很快就变成1了。
- 这个位在初始化时用不到,但作延时函数时需要用到,while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG)); 变为0时,时间到了,退出循环。补一句:我们作延时函数一定要把中断使能关掉。
- 作延时函数需要注意的是:如果这个延时的while时被一个中断打断了,这中断刚好也有用滴答定时器实现的延时函数,那么由于中断中的滴答定时器修改了寄存器中的值,所以导致程序卡死,如果中断中的滴答定时器没有关闭定时功能,则会产生很大的误差。具体细节回忆不上来也就算了,只要注意不要在中断中使用滴答定时器实现的延时。us级延时函数。
- hal库是使用滴答定时器中断的方式实现的延时函数,1ms产生一次中断,所以它的延时函数只能达到ms级别的,但是滴答定时器的中断优先级需要很高,否则会出现卡死。
- STK_LOAD寄存器。 需要配置到初始化中,说明是到啥时候定时器溢出,1HZ的上升沿计数器值加一,如果我们时钟为72MHz/s,我们想要1ms时溢出,我们需要设置此值为72000-1。因为1ms产生72000次脉冲,-1是因为溢出还需要一次。 这个需要设置到初始化中。
- STK_VAL寄存器。当前计数器值,延时函数可能会用到。
- STK_CTRL寄存器。
-
基本定时器
-
基本定时器的自动装载计数器只能向上计数。
-
基本定时器挂在在APB1上,最大时钟频率为36MHz,但是到定时器时硬件电路对频率又作了2倍频,所以当我们APB1的时钟频率使用36MHz时,定时器的频率为72MHz。
-
使用基本定时器的初始化步骤为:
-
1.开启时钟。 在RCC->APB1ENR寄存器里找。
-
2.设置预分频。 计数器的时钟频率。 这个分频范围选取 0-65535,实际是 分 1-65536。为了后面方便计算,我们在这里选用7200分频,设置值为7200-1,分频后是 72MHz/7200 = 10KHz/s,周期100us,即 1HZ/100us。 所以设置TIM6->PSC为7200-1。
-
3.设置自动重装载寄存器,即中断发生的频率,即几个HZ发生一次中断。(一个时钟(1HZ)计数器+1,计数器溢出时产生中断。) 溢出时多了一个时钟,所以设置这个值时需要-1。 比如当我们需要1s产生一次中断,按照上一步的设置得到的100us,可以得出 TIM6->ARR 为 1s/100us = 10000,再减一 即 9999 即是1s产生一次中断。
-
4.计数中断产生(溢出)的使能。设置TIM6->DIER的UIE位。
-
5.**NVIC设置优先级 NVIC_SetPriority(TIM6_IRQn, 3); 和 **
使能 NVIC_EnableIRQ(TIM6_IRQn);
-
6.设置总使能 TIM6->CR1 的 CEN 位。
-
-
服务中断函数写逻辑。 void TIM6_IRQHandler(void);
-
自动重装载寄存器(TIMx_ARR)和 预分频寄存器(TIMx_PSC) 都可以产生缓存。自动重装载寄存器的缓存叫做影子寄存器,https://www.cnblogs.com/wangsiyaoa/p/17973287
-
-
通用定时器
-
高级定时器
10、PWM(脉冲宽度调制)方波
-
一种可调占空比的方波(一般不改频率和周期,只改占空比)。普通方波占空比50%。
-
方波信号:一串高低电平。
-
三个参数
- 周期(T):单位为时间,可以是s等时间单位。 一个上升沿和一个下降沿所需的时间。也可以说是一个上升沿+一个下降沿的宽度,图像上,宽度也就是持续时间。
- 频率:周期的倒数。单位时间内产生上升沿+下降沿的个数。
- 占空比:高电平时间/周期。
x
1、stm32运算速度非常快,如果用循环当作延时,需要大概十万百万次空循环才能看到小灯闪烁的效果。
2、stm32是32位地址线。
3、寄存器的复位值即开机后或按下复位键之后寄存器或其对应引脚的初始默认值。查看数据手册时关注一下,因为这个有时能影响到写的逻辑。
4、不同型号的IO口数量不同。我们使用这个有总共144个引脚,112个IO引脚(A-G * 16)
5、关于ARM的应用及分类 略。
6、当我们驱动大电流设备时,不能使用芯片直接驱动,因为如果我们输出0时,会造成电流进入芯片,电流大时会烧掉芯片。但我们可以把芯片加一个驱动器,比如三极管,芯片放在基极位置。
7、上拉电阻拉高的原理是当我们电路为悬空状态(正负没有连通)时,没有电流经过上拉电阻,所以电阻两端的电压相同,电阻相当于导线。
8、设置输入模式时,将CNFx设置为 上拉/下拉模式,还需要额外在输出寄存器ODR中配置来区分到底是上拉还是下拉(0下拉;1上拉 )。
9、
-
桥1通过APB2连接到外设,APB2上的频率为最高72MHz;上面的外设有:ADC1、ADC2、ADC3、USART1、SPI1、TIM1、TIM8(这条线上的这两个定时器不会倍频,比如内部时钟72,就是72)、GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、EXTI、AFIO ;
-
桥2通过APB1连接到外设,APB1上的频率最高36MHz;上面的外设有:DAC、PWR、BKP、bxCAN、USB、I2C2、I2C1、UART5、UART4、USART3、USART2、SPI3/I2S、SPI2/I2S、IWDG、WWDG、RTC、TIM7、TIM6、TIM5、TIM4、TIM3、TIM2 (这条线上的几个计时器会2倍频处理,比如内部时钟是36,则这几个计时器就是72)
10、有次EEPROM忘了初始化,怎么也存不进去,找了半天bug
11、不要在.h里放全局变量,因为 .c引用.h,其他文件再引用.h,就会发生重复定义的错误,而.h不被其他文件引用基本上就没用了。