STM32学习之基本定时器
U事件指的是计数器溢出的时候发生的事件,U是update event的简称,意思就是说只有计数器溢出的时候才会将PSC和ARR的值写入对应的影子寄存器中,同时注意到图片的右下角除了事件以外还有中断和DMA输出,这俩是UI事件,UI是update interrupt的简称,U事件和UI事件的相同点是都是在计数器溢出的时候产生,不同点是U事件默认产生,可配置不产生,UI事件是默认不产生,可配置产生。定
1.1. STM32定时器分类
定时器的核心就是计数器,计数周期由单片机的晶振频率进行一系列的分频以后决定,之前学的看门狗本质就是计数器。STM32的定时器按照功能的不同可以分为三个大类,常规定时器,专用定时器和内核定时器,常规定时器就是平时提到的广义上的定时器;专用定时器是给特定外设使用的定时器,比如独立看门狗和窗口看门狗;而内核定时器就是为内核提供的计数器,用来给芯片内部的各模块提供时钟信息。具体分类如下图:
目前要学习的就是常规定时器中的基本定时器,这三类定时器的功能区别是真子集的关系,通用定时器包含基本定时器的所有功能,额外增加输入输出捕获,高级定时器包含通用定时器的所有功能以外额外增加死区控制的互补信号输出以及刹车输入等功能。
| 定时器类型 | 主要功能 |
|---|---|
| 基本定时器 | 没有输入输出通道,常用作时基,即定时功能 |
| 通用定时器 | 除可用作定时功能外还具有多路独立通道,可用于输入输出捕获 |
| 高级定时器 | 除具备通用定时器所有的功能外,还具备带死区控制的互补信号输出、刹车输入等功能 |
通用定时器和高级定时器的特有功能等学到了再说。
1.2. STM32定时器计数模式与溢出条件
定时器有三种计数模式,递增计数模式,递减计数模式和中心对齐模式,他们的溢出条件如下表所示,其中ARR可以暂时理解为计数器的最大值:
| 计数模式 | 溢出条件 |
|---|---|
| 递增计数模式 | CNT == ARR |
| 递减计数模式 | CNT == 0 |
| 中心对齐模式 | CNT == ARR -1 and CNT == 1 |
具体的计数图像如下图,当计数器是递增模式的时候,达到最大值以后计数器回到起点重新递增计数;当计数器是递减模式的时候,达到0以后计数器回到起点重新递减计数;当计数器是中心对齐模式的时候,一开始是递增计数,达到最大值减1的时候,原来的起点变成终点,原来的终点变成起点,然后开始递减计数,减到1以后继续起点和终点互换,开始递增计数。
1.3. 基本定时器的框图
STM32的基本定时器只有TIM6和TIM7,所以这里提到基本定时器就是特指这两个了。 STM32F103系列的基本定时器框图
① 时钟源
STM32F103 有两个基本定时器 TIM6 和 TIM7,时钟源来自TIMxCLK,它们都是APB1总线的外设,所以TIMxCLK是APB1总线时钟经过一个倍频器以后的时钟信号(通过参考手册的时钟框图可以看到),当APB1总线的预分频系数为1的时候,TIMxCLK等于APB1总线时钟,其他情况TIMxCLK等于2倍的APB1总线时钟频率,之前设置的APB1总线的预分频系数为2,所以TIMxCLK等于2倍的APB1总线时钟频率等于系统时钟频率,也就是说这里基本定时器的时钟频率选择为72MHz。
② 控制器
控制器主要对定时器进行控制,决定定时器何时开始工作、何时停止、以何种方式计数、如何处理计数溢出以及如何与其他功能来进行协同工作,比如图中的DAC转换,时钟信号从时钟源进入到控制器,控制器根据时钟信号来对计数器进行控制。
③ 计数器( 时基单元 )
计数器部分由三个寄存器组成组成,第一个是预分频器PSC,时钟信号经过预分频器后产生计数器的真正工作的时钟信号,第二个是自动重装载寄存器ARR,这是两个寄存器,这两个寄存器分别有两个“影子寄存器”,图片里面也画出来了阴影部分表示影子寄存器,影子寄存器待会再说。第三个就是计数器了,根据配置的时钟来按照递增计数模式进行计数,基本定时器只有递增计数一种计数模式。
影子寄存器是实际起作用的寄存器,但是我们无法通过程序直接访问,只有先配置PSC和ARR,然后这俩寄存器把值更新到他们对应的影子寄存器中我们配置的东西才会起作用,图片下面的那行字:发生U事件后预装载寄存器内容转移到有效寄存器。预装载寄存器就是PSC和ARR,有效寄存器就是对应的影子寄存器,PSC和ARR就是起一个缓存的作用。U事件指的是计数器溢出的时候发生的事件,U是update event的简称,意思就是说只有计数器溢出的时候才会将PSC和ARR的值写入对应的影子寄存器中,同时注意到图片的右下角除了事件以外还有中断和DMA输出,这俩是UI事件,UI是update interrupt的简称,U事件和UI事件的相同点是都是在计数器溢出的时候产生,不同点是U事件默认产生,可配置不产生,UI事件是默认不产生,可配置产生。
可以看出来,使用影子寄存器的主要作用就是防止相关寄存器的修改直接生效,所以只有当计数器的一个计数周期走完以后修改才会生效,也就是说如果计数器的中断里面做一些和计数周期有关的事情的话,在修改相关寄存器的前后做的是完整的两件事情,否则有可能修改前后的事情会相互耦合,产生一些意想不到的意外的事情。
1.4. 基本定时器的寄存器
控制寄存器 1(TIMx_CR1)
这个寄存器第7位和低4位有效,各个位作用如下:
第7位: APRE位 (Auto-reload preload enable),这个位是用来设置TIMx_ARR寄存器的影子寄存器的,使能该位则TIMx_ARR具有缓冲作用,影子寄存器生效,失能影子寄存器不生效;
第3位: OPM位 (One-pulse mode),这个位是单脉冲模式,也就是说计数器不管当前的工作状态是咋样的,溢出一次,溢出之后就把计数器的功能关掉了;
第2位: URS位(Update request source),更新事件的触发源选择位,通过配置该位来选择计数器更新事件的触发源;
第1位: UDIS位(Update disable),这个位如果置1,那么会禁止更新事件的产生,不产生更新事件那么定时器的影子寄存器的值也就不会改变,但是如果TIMx_EGR寄存器的UG位被置1或者从模式控制器产生了硬件复位,那么整个定时器都会被初始化,包括影子寄存器的内容都会被清除。
第0位: CEN位(Counter enable),定时器使能位 ,置1使能定时器,置0失能定时器。
控制寄存器 2(TIMx_CR2)
这个计数器只有第6到4位有效,3位一起实现对从计数器的控制,配置000,当前定时器的复位信号发给从定时器;配置001,当前计数器的使能信号发给从定时器;配置010,当前计数器的更新事件作为触发输出。这个寄存器目前都用不到,在pwm输出的时候会用到。
DMA/中断使能寄存器(TIMx_DIER)
这个寄存器第8位和第0位有效,
第8位:更新DMA请求使能位(Update DMA request enable),置0禁止更新DMA请求,置1使能更新DMA请求;
第0位:更新中断使能位(Update interrupt enable),置0禁止更新中断,置1使能更新中断;
状态寄存器(TIMx_SR)
这个寄存器只有第0位有效,用来表示当前是否产生了更新中断,下列两种情况下这一位会被硬件置1,并且需要软件清零:
- 计数器产生上溢或下溢并且TIMx_CR1中的UDIS=0;
- 如果TIMx_CR1中的URS=0并且UDIS=0,当使用TIMx_EGR寄存器的UG位重新初始化计数
器CNT时。
事件产生寄存器(TIMx_EGR)
这个寄存器也只有1位有效,这一位置1的话,重新初始化定时器并产生一次更新事件。
计数器(TIMx_CNT)
这个寄存器低16位有效,用来存储计数器所记录的数值。
预分频器(TIMx_PSC)
这个寄存器低16位有效,用来配置计数器的预分频器数值,计数器的时钟频率CK_CNT=fCK_PSC(PSC[15:0]+1)CK\_CNT=\frac{f_{CK\_PSC}}{(PSC[15:0]+1)}CK_CNT=(PSC[15:0]+1)fCK_PSC。
在每一次更新事件时, PSC的数值被传送到实际的预分频寄存器(影子寄存器)中。
自动重装载寄存器(TIMx_ARR)
这个寄存器低16位有效,ARR的数值将传送到实际的自动重装载寄存器中。
1.5. 基本定时器代码
定时器的初始化代码如下,这部分也很简单,按部就班来就可以了
void btim_timx_int_init(uint16_t arr, uint16_t psc)
{
RCC->APB1ENR |= 1 << 4; /* TIM6 时钟使能 */
BTIM_TIMX_INT->ARR = arr; /* 设定计数器自动重装值 */
BTIM_TIMX_INT->PSC = psc; /* 设置预分频器 */
BTIM_TIMX_INT->DIER |= 1 << 0; /* 使能更新中断 */
BTIM_TIMX_INT->CR1 |= 1 << 0; /* 使能定时器TIMX */
sys_nvic_init(1, 3, BTIM_TIMX_INT_IRQn, 2); /* 抢占1,子优先级3,组2 */
}
下面这个是官方的中断函数,我觉得还是一进入中断就请标志位比较好,而且已经进入中断服务函数了,再进行一次标志位的判断有点多此一举,所以我觉得if判断也可以不写。
void BTIM_TIMX_INT_IRQHandler(void)
{
if (BTIM_TIMX_INT->SR & 0X0001) /* 溢出中断 */
{
LED1_TOGGLE();
}
BTIM_TIMX_INT->SR &= ~(1 << 0); /* 清除中断标志位 */
}
总的来说定时器虽然是很重要的东西,但是基本定时器内容少,难度也不大,后面的通用定时器和高级定时器内容应该会多很多。
更多推荐



所有评论(0)