当前位置:网站首页>8、【STM32】定时器(TIM)——中断、PWM、输入捕获实验(一文精通定时器)
8、【STM32】定时器(TIM)——中断、PWM、输入捕获实验(一文精通定时器)
2022-06-26 12:40:00 【追逐者-桥】
目录
前言
使用的是正点原子的探索者开发板进行学习,芯片:STM32F407ZGTx
学习说明此文档为本人的学习笔记,注重实践,关于理论部分会给出相应的学习链接。
本文参考了《正点原子的寄存器开发指南》、《STM32F4参考手册》
详细介绍的时钟的配置与,定时器时钟如何从时钟树而来的。
理论学习
包括TIM1和TIM8高级控制定时器、TIM2-5和TIM9-14通用定时器、TIM6和TIM7基本定时器。
一、定时器中断
1.1、时基单元包括:
- 计数器寄存器 (TIMx_CNT)
- 预分频器寄存器 (TIMx_PSC)
- 自动重载寄存器 (TIMx_ARR)
1.2、通用定时器功能
- 16 位/32 位(仅 TIM2 和 TIM5)向上、向下、向上/向下自动装载计数器(TIMx_CNT),注意:TIM9~TIM14 只支持向上(递增)计数方式。
- 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~65535 之间的任意数值。
- 4 个独立通道(TIMx_CH1~4,TIM9~TIM14 最多 2 个通道),这些通道可以用来作为:
- 4)可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
- 5)如下事件发生时产生中断/DMA(TIM9~TIM14 不支持 DMA):
1.3、计数器模式
- 递增计数模式
- 预分频器的缓冲区中将重新装载预装载值(TIMx_PSC 寄存器的内容)
- 自动重载影子寄存器将以预装载值进行更新

- 递减计数模式
- 预分频器的缓冲区中将重新装载预装载值(TIMx_PSC 寄存器的内容)。
- 自动重载活动寄存器将以预装载值(TIMx_ARR 寄存器的内容)进行更新。注意,自动重载寄存器会在计数器重载之前得到更新,因此,下一个计数周期就是我们所希望的新的周期长度。

- 中心对齐模式(递增/递减计数)
- 预分频器的缓冲区中将重新装载预装载值(TIMx_PSC 寄存器的内容)。
- 自动重载活动寄存器将以预装载值 (TIMx_ARR 寄存器的内容)进行更新。注意,如果更新操作是由计数器上溢触发的,则自动重载寄存器在重载计数器之前更新,因此,下一个计数周期就是我们所希望的新的周期长度(计数器被重载新的值)。

1.3 相关寄存器
- TIMx_CR1控制寄存器
- TIMx_DIER中断/DMA使能寄存器
- TIMx_PSC预分频器
- TIMx_CNT计数器(存储计数值)
- TIMx_ARR自动重装载寄存器
二、定时器PWM输出
2.1、PWM输入模式
- 两个 ICx 信号被映射至同一个 TIx 输入。
- 这两个 ICx 信号在边沿处有效,但极性相反。
- 选择两个 TIxFP 信号之一作为触发输入,并将从模式控制器配置为复位模式。

2.2、定时器PWM输出
STM32F4 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4路的 PWM 输出!这里我们仅使用 TIM14 的 CH1 产生一路 PWM 输出。
关于PWM在FPGA上的产生更加有助于理解
二、15【FPGA】呼吸灯实现_追逐者-桥的博客-CSDN博客_fpga 呼吸灯
- 比较结果发生改变,或 输出比较模式(TIMx_CCMRx 寄存器中的 OCxM 位)从“冻结”配置(不进行比较, OCxM=“000”)切换为任一 PWM 模式(OCxM=“110”或“111”)。
2.3、PWM输出相关寄存器
除了使用到了定时器中断的那几个寄存器外还用到了以下寄存器
- TIMx_CCMR1/2捕获/比较模式寄存器
- TIMx_CCER捕获/比较使能寄存器
- TIMx_CCR1~4捕获/比较寄存器
三、定时器输入捕获
3.1、简介
在 t1~t2 之间,可能产生 N 次定时器溢出,这就要求我们对定时器溢出,做处理,防止高电平太长,导致数据不准确。如图15.1.1所示,t1~t2之间,CNT计数的次数等于:N*ARR+CCRx2,有了这个计数次数,再乘以 CNT 的计数周期,即可得到 t2-t1 的时间长度,即高电平持续时间。
STM32F4 的定时器,除了 TIM6 和 TIM7,其他定时器都有输入捕获功能。
3.2、寄存器配置
- 选择有效输入:TIMx_CCR1 必须连接到 TI1 输入,因此向 TIMx_CCMR1 寄存器中的CC1S 位写入 01。只要 CC1S 不等于 00,就会将通道配置为输入模式,并且 TIMx_CCR1寄存器将处于只读状态。
- 根据连接到定时器的信号,对所需的输入滤波时间进行编程(如果输入为 TIx 输入之一,则对 TIMx_CCMRx 寄存器中的 ICxF 位进行编程)。假设信号变化时,输入信号最多在 5 个内部时钟周期内发生抖动。因此,我们必须将滤波时间设置为大于 5 个内部时钟周期。在检测到 8 个具有新电平的连续采样(以 fDTS 频率采样)后,可以确认 TI1上的跳变沿。然后向 TIMx_CCMR1 寄存器中的 IC1F 位写入 0011。
- 通过向 TIMx_CCER 寄存器中的 CC1P 位和 CC1NP 位写入 0,选择 TI1 通道的有效转换边沿(本例中为上升沿)。
- 对输入预分频器进行编程。在本例中,我们希望每次有效转换时都执行捕获操作,因此需要禁止预分频器(向 TIMx_CCMR1 寄存器中的 IC1PS 位写入 00)。
- 通过将 TIMx_CCER 寄存器中的 CC1E 位置 1,允许将计数器的值捕获到捕获寄存器中。
- 如果需要,可通过将 TIMx_DIER 寄存器中的 CC1IE 位置 1 来使能相关中断请求,并且/或者通过将该寄存器中的 CC1DE 位置 1 来使能 DMA 请求。
3.3、发生输入捕获时:
- 发生有效跳变沿时,TIMx_CCR1 寄存器会获取计数器的值。
- 将 CC1IF 标志置 1(中断标志)。如果至少发生了两次连续捕获,但 CC1IF 标志未被清零,这样CC1OF捕获溢出标志会被置 1。
- 根据 CC1IE 位生成中断。
- 根据 CC1DE 位生成 DMA 请求。
实战演练
一、定时器中断配置步骤
1.1、TIM3 时钟设置与使能
//设置时钟频率:HSE=8M M=8 N=336 P=2 Q=7
//PLL=HSE/M=1M PLLCLK=PLL*N/P=168M USB=PLL*N/Q=48M
Stm32_Clock_Init(336,8,2,7);
- RCC_CFGR RCC时钟配置寄存器
想CFGR[12:10]位写5,即4分频,因此APB1=PLLCLK/4=42M
RCC->CFGR|=(0<<4)|(5<<10)|(4<<13);
- TIM3 时钟使能
TIM3挂载在APB1时钟总线上,
TIM3由于在配置APB1的时候使用了4分频,所以定时器进行了2倍频,为84MHz。
RCC->APB1ENR |= 1<<1;
1.2、设置 TIM3_ARR 和 TIM3_PSC的值
时间计算公式:Tout = ( (arr+1) * (psc+1) ) / Tclk;
TIM3->ARR=arr; //设置TIM3的自动装载值
TIM3->PSC=psc; //预分频器设置
1.3、设置 TIM3_DIER 允许更新中断
TIM3->DIER|=1<<0;
1.4、允许 TIM3 工作(TIM3_CR1)



TIM3->CR1|=0x01;
使能定时计数器器,且为递增计数
1.5、TIM3 中断分组与中断服务函数设置
- 中断分组,TIM3优先级配置
MY_NVIC_Init(1,3,TIM3_IRQn,2);
- 编写中断服务函数
TIMX-SR状态寄存器:
void TIM3_IRQHandler(void)
{
if(TIM3->SR&0X0001) //中断发生,最低位由硬件置1
{
LED1=!LED1;
}
TIM3->SR&=~(1<<0); //必须将最低位软件置0,等待下次中断的到来
}
1.6、主函数的编写
TIM(定时器)=84MHz psc(分频系数)=8400 arr(重装在值)=5000
定时器计数频率 = 84MHz / 8400 =10KHz
Tout = 5000 / 10KHz = 0.5s
int main(void)
{
Stm32_Clock_Init(336,8,2,7); //pll=1M pllclk=168M
delay_init(168);
LED_Init();
TIM3_Int_Init(5000-1,8400-1); //arr psc
while(1)
{
LED0=!LED0;
delay_ms(200);
};
}
二、定时器PWM输出配置步骤
2.1、配置TIM14的输出端口
RCC->APB1ENR|=1<<8; //使能TIM13定时器的时钟
RCC->AHB1ENR|=1<<5; //使能端口FA9的端口时钟
GPIO_Set(GPIOF,PIN9,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_PU);
GPIO_AF_Set(GPIOF,9,9); //PF9,AF9
2.2、设置 TIM14 的 ARR 和 PSC
TIM14->ARR=arr; //重装载值
TIM14->PSC=psc; //分频系数
2.3、TIM14-CH1设置为PWM输出 模式
TIM14-CCMR1捕获比较寄存器1相关位描述
TIMx_CCER捕获/比较使能寄存器相关位描述
TIM14->CCMR1|=6<<4; //打开TIM14的CH1
TIM14->CCMR1|=1<<3; //使能与 TIM14_CCR1 相关的预装载寄存器
TIM14->CCER|=1<<0; //下降沿触发,低电平有效
TIM14->CCER|=1<<1; //使能CH1输出
2.4、TIMx_CR1控制寄存器 1,使能 TIM14
TIM14->CR1|=1<<7; //自动装载进行缓存
TIM14->CR1|=1<<0; //定时计数器使能
2.5、主函数的编写和占空比控制
#define LED0_PWM_VAL TIM14->CCR1
int main(void)
{
u16 led0pwmval=0; //TIM14-CCR1的值,及占空比的计数值
u8 dir=1;
Stm32_Clock_Init(336,8,2,7);
delay_init(168);
TIM14_PWM_Init(500-1,84-1); //1MHz的计数频率,PWM频率2KHz, T=0.5ms
while(1)
{
delay_ms(10); //10ms重载一次占空比,20次PWM的输出
if(dir)led0pwmval++; //占空比增加
else led0pwmval--; //占空比减小
if(led0pwmval>300)dir=0;
if(led0pwmval==0)dir=1;
LED0_PWM_VAL=led0pwmval; //重新装载占空比值
}
}
三、定时器输入捕获配置步骤
3.1、配置TIM5输入端口
RCC->APB1ENR|=1<<3;
RCC->AHB1ENR|=1<<0;
GPIO_Set(GPIOA,PIN0,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_PD);
GPIO_AF_Set(GPIOA,0,2); //PA0,AF2 (TIM5-CH1)
3.2、设置 TIM5 的 ARR 和 PSC
计数分频系数与计数器数设置,在定时器中断有相关描述
TIM5->ARR=arr;
TIM5->PSC=psc;
3.3、TIM5-CH1(TI1)设置为输入捕获模式
TIM5-CCMR1捕获比较寄存器1相关位描述
TIM5_CCER捕获/比较使能寄存器相关位描述
TIM5->CCMR1|=1<<0; //CCIS位,将CC1设置成输入且映射到TI1
TIM5->CCMR1|=0<<4; //IC1PSC,无分频
TIM5->CCMR1|=0<<10; //IC1F,无滤波器
TIM5->CCER|=0<<1; //CC1P,无反向,上升沿触发
TIM5->CCER|=1<<0; //CC1E,使能输入捕获
3.4、设置 TIM5->DIER,使能捕获和更新中断。
TIM5->DIER|=1<<1;
TIM5->DIER|=1<<0;
//设置软件控制产生更新事件,是载入PSC值立刻生效,否则要等到溢出后才生效
TIM5->EGR=1<<0;
3.5、TIMx_CR1控制寄存器 1,使能 TIM5
TIM5->CR1|=0x01;
3.6、设置中断分组及编写中断函数
MY_NVIC_Init(2,0,TIM5_IRQn,2)
u8 TIM5CH1_CAPTURE_STA=0; //捕获标志0x40上升沿捕获,0x80下降沿捕获
u32 TIM5CH1_CAPTURE_VAL; //捕获计数值存储空间
void TIM5_IRQHandler(void)
{
u16 tsr;
tsr=TIM5->SR; //定时器状态寄存器
if((TIM5CH1_CAPTURE_STA&0X80)==0) //捕获未完成
{
if(tsr&0X01) //定时器溢出标志
{
if(TIM5CH1_CAPTURE_STA&0X40) //上升沿被捕获到后
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F) //达到计数器溢出值
{
TIM5CH1_CAPTURE_STA|=0X80; //标记捕获到了一个定时计数器周期
TIM5CH1_CAPTURE_VAL=0XFFFFFFFF; //保存一个完成的计数周期
}else TIM5CH1_CAPTURE_STA++; //计数器未溢出
}
}
if(tsr&0x02) //发生上升沿捕获事件进入中断
{
if(TIM5CH1_CAPTURE_STA&0X40) //上升沿捕获已完成,下降沿捕获中断进入
{
TIM5CH1_CAPTURE_STA|=0X80; //已经捕获到下降沿标志
TIM5CH1_CAPTURE_VAL=TIM5->CCR1; //储存捕获计数器值
TIM5->CCER&=~(1<<1); //设置为上升沿捕获进入中断
}else //将计数器清零,重新计数
{
TIM5CH1_CAPTURE_STA=0;
TIM5CH1_CAPTURE_VAL=0;
TIM5CH1_CAPTURE_STA|=0X40; //已经捕获到上升沿标志
TIM5->CR1&=~(1<<0); //使能定时器
TIM5->CNT=0; //清空计数器
TIM5->CCER|=1<<1; //设置为下降沿捕获进入中断
TIM5->CR1|=0x01; //开启定时器
}
}
}
TIM5->SR=0;
}
3.7、输入捕获主函数
extern u8 TIM5CH1_CAPTURE_STA;
extern u32 TIM5CH1_CAPTURE_VAL;
int main(void)
{
long long temp=0;
Stm32_Clock_Init(336,8,2,7);
delay_init(168);
uart_init(84,115200);
TIM14_PWM_Init(500-1,84-1);
TIM5_CH1_Cap_Init(0XFFFFFFFF,84-1);
while(1)
{
delay_ms(10);
LED0_PWM_VAL++;
if(LED0_PWM_VAL==300)LED0_PWM_VAL=0;
if(TIM5CH1_CAPTURE_STA&0X80) //捕获到了一个定时器计数周期或者下降沿
{
temp=TIM5CH1_CAPTURE_STA&0X3F; //提取捕获值
temp*=0XFFFFFFFF; //计算捕获时间
temp+=TIM5CH1_CAPTURE_VAL; //加入定时器周期时间和下降沿捕获时间
printf("HIGH:%lld us\r\n",temp); //输出捕获总时间
TIM5CH1_CAPTURE_STA=0; //将捕获标志位清0,进入下一次捕获
}
}
}
输入捕获功能应用
电容触摸按键:电容按键是接触式的,点一下就松开(与微动开关类似),因此需要消除抖。在之前的微动开关使用时间延迟判断两次,状态相同时才认为是按下。这里同理,这里使用的是输入捕获即手指接触一定时间后到达B认为电容按键按下。
正点原子中的文档内容描述:
对于电容按键用的不是特别多,这里不进行实验,有需要的可以自己去看一下正点原子的相关实验。
边栏推荐
- 机器学习笔记 - 时间序列的季节性
- 心脏滴血漏洞(CVE-2014-0160)分析与防护
- Typescript
- QT .pri 的建立与使用
- Digital signal processing -- Design of linear phase type (Ⅰ, Ⅲ) FIR filter (1)
- [esp32-c3][rt-thread] run RT-Thread BSP minimum system based on esp32c3
- National standard gb28181 protocol easygbs cascaded universal vision platform, how to deal with live message 403?
- Processing polyhedron change
- D - skiing
- Electron official docs series: References
猜你喜欢
首批通过!百度智能云曦灵平台获信通院数字人能力评测权威认证
详细讲解C语言10(C语言系列)
opencv高速下载
倍福CX5130换卡对已有的授权文件转移操作
First pass! Baidu AI Cloud Xiling platform has obtained the authoritative certification of digital human ability evaluation from the Institute of information technology
Vivado 错误代码 [DRC PDCN-2721] 解决
Electron official docs series: Get Started
Deep parsing MySQL binlog
Processsing function random
National standard gb28181 protocol easygbs cascaded universal vision platform, how to deal with live message 403?
随机推荐
D - skiing
tauri vs electron
倍福NC轴状态转移图解析
scrapy——爬取漫画自定义存储路径下载到本地
Solution of Splunk iowait alarm
Processing function translate (mousex, mousey) learning
. Net Maui performance improvement
桥接模式(Bridge)
Beifu PLC passes MC_ Readparameter read configuration parameters of NC axis
Processing 多面体变化
机器学习笔记 - 时间序列的季节性
体现技术深度(无法速成)
C语言:练习题二
Fire warning is completed within 10 seconds, and Baidu AI Cloud helps Kunming Guandu build a new benchmark of smart city
[BSidesCF 2019]Kookie 1
Do you know the limitations of automated testing?
Appearance mode (facade)
Enjoy element mode (flyweight)
10秒内完成火灾预警,百度智能云助力昆明官渡打造智慧城市新标杆
Opencv high speed download