内部构成模块
自动重装载寄存器:TIMx_ARR
预分频器:TIMx_PSC
这是TIM6、TIM7的主要内部构成(TIM2~5多了一个捕获/比较寄存器TIMx_CCR)
核心部分由自动重装载寄存器TIMx_ARR和CNT计数器构成
来自RCC的时钟信号TIMxCLK(通常是72MHZ)经过预分频器分频后,计数器开始计数(TIM6、TIM7只能从0开始向上计数),直到计数值达到TIMx_ARR中存放的值后,重新回到0,继续重复这一过程。
由此得出3个配置步骤:
- 选择时钟源
TIMxCLK
频率 - 预分频系数(注意要-1,比如要选择分频系数为72,那么放入的值应该是71)
- 确定需要延时多长时间,进而确定自动重装载的值
TIMx_ARR
(注意也要-1)
延时时间 = (TIMx_ARR+1) * (TIMx_PSC+1) / TIMxCLK
三种定时器
大家都具有的功能或特点
- 内部预分频器位数:16
- 内部计数器位数:16
- 可以更新中断和DMA
基本定时器
基本定时器包括TIM6、TIM7,只具备基本的定时功能,即累计时钟脉冲数超过装载值后,产生溢出;如果使能了中断或者DMA事件,则使能中断或者DMA操作;
另外,基本定时器可以作为通用定时器的时基,可以为数模转换器DAC提供时钟(事实上,TIM6、TIM7被直接连接到DAC并通过触发直接驱动DAC);
其它特性:
-
时钟源:APB1输出
-
计数模式:向上计数
通用定时器
通用定时器包括TIM2~TIM5共四个
特性:
- 相比基本定时器添加了 捕获/比较寄存器:TIMx_CCRx (注意每个通用定时器都有4个捕获比较寄存器,因为有4个输出口OCx)
- 时钟源:APB1(通常提供72MHz)、ITRx、TIx(外部时钟模式1)、ETR(外部时钟模式2);[初学只需要掌握第一种即可]
- 计数模式:向上、向下、双向均可
PWM输出模式
PWM即脉冲宽度调制(废话就不多说,不懂的可以去百度等查找相关介绍),通用定时器因为拥有捕获/比较寄存器,所以可以配置PWM输出模式
通用定时器如何配置PWM输出模式?
- 配置计数模式(此处设置为向上计数)
- 配置TIMx_ARR预设值为N(记得要-1),配置捕获/比较寄存器预设值A
- 配置输出方式:假设配置为当计数值X<A时, 输出高电平;当X>=A时,输出低电平。这样输出波形占空比为
A/(N+1)
PWM输出模式
- 模式1
TIM_OCMode_PWM1
:- 向上计数时,当计数值<CCR存放的值时,输出有效电平,否则为无效电平(之后可以设置低电平有效还是高电平有效)
- 向下计数时,与向上计数一样
- 模式2
TIM_OCMode_PWM2
:- 向上计数时,当计数值<CCR存放的值时,输出无效电平,否则为有效电平(之后可以设置低电平有效还是高电平有效)
- 向下计数时,与向上计数一样
这是配置PWM输出的主要步骤,如图:
配置PWM输出详细步骤:
例如配置TIM3的CH2通道为PWM输出,输出重映射到PB5端口
1 | void TIM3_CH2_PWM_Init(u16 per,u16 psc){ |
PWM输入模式
PWM输入模式用于测量外部输入信号的脉宽,流程是:
- 从外部输入一个(方波)信号TI,当从输入端第一次捕获到TI的上升沿时,计数器TIMx_CNT复位为0,然后开始不断向上计数(TIMx_ARR足够大);
- 当捕获到下降沿时,TIMx_CRR2寄存器记录下当前计数器的计数值;(得出:高电平期间计数次数=CRR2+1,加1是因为计数是从0开始的)
- 当再次捕获到上升沿时,TIMx_CRR1寄存器记录当前计数器的计数值。(得出:一个周期内计数器计数次数=CRR1+1)
- 计算得出:
占空比=(CRR2+1)/(CRR1+1)
高级定时器
高级定时器包括TIM1、TIM8
功能特性:
- 时钟源:APB2(72MHz)
- 计数模式:向上、向下、双向
- 具备通用定时器所有功能
- 是6个通道的三相PWM发生器
- 整体结构和基本、通用定时器相同(多出BPK、DTG两个结构),配置方法差不多
- 死区时间控制(源于BPK、DTG的结构)
定时器相关库函数
定时器库函数存放在标准外设库的 stm32f10x_tim.h
和 stm32f10x_tim.c
文件中,使用时要在用户程序中导入(#include stm32f10x_tim.h
,或者在 stm32f10x_conf.h
中去除掉相关注释);
常用库函数:
1 | TIM_DeInit(); |
定时器中断
当定时器计数值溢出时,可以让其产生中断信号,然后配置中断服务函数(即产生中断后该做些什么,通常是PPP_IRQHandler()
形式的函数)
以定时器TIM2为例,如何初始化让其产生中断
1 | void TIM2_init(u16 arr, u16 psc){ |
color:blue 中断相关知识
优先级:数字越小优先级越高
抢占优先级:优先级越高(数字越小)越先被执行,优先级高的可以打断优先级低的,优先级相同时看子优先级
子优先级(也叫响应优先级):
- 两个中断同时到达,抢占优先级相同,子优先级高的先执行;
- 当子优先级高的中断到来时,遇到子优先级低的中断正在执行(两者抢占优先级一样),那子优先级高的中断也要等待子优先级低的中断先执行完;
优先级分组:
既然每个中断源都需要被指定这两种优先级,就需要有相应的寄存器位记录每个中断的优先级(指优先级这个数字,不能超过分配给它的最大存储值);
在Cortex-M3中定义了8个比特位用于设置中断源的优先级,这8个比特位可以有8种分配方式,如下:
- 所有8位用于指定响应优先级
- 最高1位用于指定抢占式优先级,最低7位用于指定响应优先级
- 最高2位用于指定抢占式优先级,最低6位用于指定响应优先级
- 最高3位用于指定抢占式优先级,最低5位用于指定响应优先级
- 最高4位用于指定抢占式优先级,最低4位用于指定响应优先级
- 最高5位用于指定抢占式优先级,最低3位用于指定响应优先级
- 最高6位用于指定抢占式优先级,最低2位用于指定响应优先级
- 最高7位用于指定抢占式优先级,最低1位用于指定响应优先级
这就是优先级分组的概念。
Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32把指定中断优先级的寄存器位减少到4位,这4个寄存器位的分组方式如下:
第0组:所有4位用于指定响应优先级,此时不会发生中断嵌套
第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级
第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级
第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级
第4组:所有4位用于指定抢占式优先级
可以通过调用STM32的固件库中的函数NVIC_PriorityGroupConfig()
选择使用哪种优先级分组方式,这个函数的参数有下列5种:
1 | NVIC_PriorityGroup_0 //选择第0组 |
如何指定中断源的抢占式优先级和响应优先级:
1 | // 选择使用优先级分组第1组 |