一位萌新为参加robomaster所做的前期准备–stm32基础(三)(定时器中断)
前段时间,由于在调试步兵车的底盘以及云台代码,调pid参数,研读新规则,小组开会,有些忙,没有及时更新,现在抽空更新文档 (嘿嘿)
一、实验完成目的:利用stm32中的定时器来进行中断程序,从而对led灯的闪灭进行控制(有点类似用延时函数对led灯进行重复亮暗),利用定时器中断控制led灯目的在于控制系统是内部的,到达一定时间可以自行产生中断,在此期间可以做其他的任务。
二、方案:
①该实验要用到led,故要运用到gpio等函数(打开led端口时钟,配置gpio等)
②需要运用led相关函数,熄灭led,点亮led,翻转led亮暗
③需要运用到通用定时器tim3,需对其进行打开相关时钟,设置分频系数,计数溢出值,计数模式以及对中断优先级的设置
④需要编写中断服务函数
三、流程图
四、主要代码
int main(void)
{
leds_init(); //初始化gpio,将led灯熄灭
TIM3_Init(); //初始化TIM并进行相关配置
while(1) {
sw_delay_ms(200);; //(自行加入的,控制led1,定时器中断控制的led2作比较,可以不要)
led_toggle(LED_1) ;
}
}
本实验需要掌握的关键代码:
void TIM3_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
//初始定时器(与配置io口类似,定时器的初始化也是给一个结构体变量赋值,把参数传送给初始化函数.)
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3 , ENABLE); //打开时钟
TIM_DeInit(TIM3);
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1 ; //时钟分割
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up ;
//配置计数模式(向上计数)
TIM_TimeBaseInitStruct.TIM_Period = 9999 ;
//设置在下一个更新事件装入活动的自动重装载寄存器周期的值arr
TIM_TimeBaseInitStruct.TIM_Prescaler = 7199 ;
//设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct ) ;
TIM_ClearFlag(TIM3, TIM_FLAG_Update);
TIM_ITConfig(TIM3, TIM_IT_Update,ENABLE);
//使能TIM3的更新中断
TIM_Cmd(TIM3, ENABLE);
//中断优先级NVIC设置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//中断服务函数
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET){
//检查TIM3更新中断发生与否
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
//清除TIM3更新中断标志
led_toggle(LED_2);
}
}
//实验现象可以看到led1是由延时函数控制的,led2是由定时器内部中断控制的,由于给的参数不一样于是它们的亮暗时间不一样。如果不要led1,则主函数中的while函数可以为空
四、中断相关知识:
①定时器的溢出公式为:溢出时间(秒)= ((ARR+1)*(PSC+1))/ TIMx时钟CK_INT(MHz)
(程序中的溢出时间就为1s,TIMx时钟CK_INT(MHz)为72)
②定时器中断的一般步骤
1-配置时基初始化结构体
2-开启定时器更新中断(即定时时间到了)
3-配置中断优先级(开启定时器中断,配置NVIC)
4-使能定时器
5-编写中断服务函数
6-编写main函数
③计数器模式
通用定时器可以向上计数、向下计数、向上向下双向计数模式。
向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
④STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。
五、总结
本次实验已经大体掌握中断的原理及对led闪烁的编程思路,理解各个代码意思。一开始对void TIM3_IRQHandler(void)函数不理解,认为主函数及其他中并没有调用该函数,为什么会执行?(现理解为中断后就会自动执行该函数),到现在对中断优先级的制配不太理解(即红色标注的代码),不明白该如何制配及运用。
对于通用定时器的配置:
① 定义定时器结构体
② 打开TIM3定时器时钟RCC_APB1PeriphClockCmd()
③ 对结构体中的相关变量进行配置(TIM_ClockDivision-时钟分割;TIM_CounterMode-设置计数模式;TIM_Period-设置重装值;TIM_Prescaler-设置预分频值)
④ 根据 TIM_TimeBaseInitStruct 中指定的参数初始化 TIMx 的时间基数单位 TIM_TimeBaseInit()
⑤ 清除待处理标志位TIM_ClearFlag()
⑥ 使能TIMx中断TIM_ITConfig()
⑦ 使能TIMx外设TIM_Cmd()
设置中断后就要配置NVIC
⑧ 定义NVIC结构体
⑨ 配置NVIC优先级VIC_PriorityGroupConfig()
⑩ 对结构体中的相关变量进行配置(NVIC_IRQChannel-配置为TIMx的中断;NVIC_IRQChannelPreemptionPriority-配置抢占优先级;VIC_IRQChannelSubPriority-配置从优先级;NVIC_IRQChannelCmd-使能中断通道)
⑪ 根据 NVIC_InitStruct 中指定的参数初始化外设 NVIC 寄存NVIC_Init()
⑫编写服务中断函数TIM3_IRQHandler()