3.7节 定时器实验
在上一节我们使用SysTick实现了延时,本节介绍使用定时器实现延时。
a.实验准备:USB转串口模块,ST-Llink下载器,CHEAPX机器人控制板
b.实验目的:使用定时器延时检验上一节SysTick延时函数的准确度
c.相关知识点:
STM32定时器和串口一样,具有中断函数。但我们打开定时器时,定时器就会按我们设置好的频率开始计数直到溢出,溢出会产生溢出中断。同样的,我们可以通过计数的数值转化为时间。STM32F1系列芯片的定时器的分辨率可以达到1/72us。
d.编程及运行
(1)初始化定时器TIM4,编写中断函数
void initTimeStamp(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//开启TIM4时钟 //TIM4 TIM_TimeBaseStruct.TIM_ClockDivision = 0; //时钟分割,不分割,即为该定制器时钟最大值72M TIM_TimeBaseStruct.TIM_Prescaler = 0; //预分频值,不分频,即为该定制器时钟值72M TIM_TimeBaseStruct.TIM_Period = 65000-1; //最大计数值,也是计数周期=1/72M*65000s=65000/72us TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStruct);//传入结构TIM_TimeBaseStruct,配置TIM4 TIM_ClearFlag(TIM4, TIM_FLAG_Update); //清除更新中断 TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //开启更新中断,计数器到达最大值65000-1,从该值转变至0时,会产生一次更新中断 NVIC_InitStruct.NVIC_IRQChannel = TIM4_IRQn; //通道值:定时器4 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级 0,最高 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //子优先级 1,次高 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //使能 NVIC_Init(&NVIC_InitStruct); //传入结构体NVIC_InitStruct,配置NVIC TIM_ARRPreloadConfig(TIM4, ENABLE);//开启自动装载 TIM_Cmd(TIM4, ENABLE); } void TIM4_IRQHandler(void) { if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //判断是否为更新中断 { timerTSCount++; TIM_ClearITPendingBit(TIM4, TIM_IT_Update ); //清除更新中断标志 } }
(2)编写SysTick测试函数。我们只需要记录SysTick实现的延时函数前后的TIM4计数值即可。
void testTimestamp(void) { u32 T=0; u32 lastT=0; u32 deltaT=0; printf("Timestamp Test\n"); while(1) { lastT=getTimestampUS(); T=getTimestampUS(); deltaT=T-lastT; lastT=getTimestampUS(); delay_us(1); T=getTimestampUS(); printf("cmd=1us,Real:%6fus;",((T-lastT-deltaT)/72.0f)); lastT=getTimestampUS(); delay_ms(1); T=getTimestampUS(); printf("cmd=1000us,Real:%6fus\r\n",((T-lastT-deltaT)/72.0f)); delay_ms(1000); } }
volatile static u32 timerTS=0; //TimeStamp(unit:1/72us) volatile static u32 timerTSH=0; //TimeStamp(unit:65000/72us) volatile static u8 timerTSCount=0; //TimeStamp(unit:65000/72us) /*** unit:1/72us ***/ u32 getTimestampUS(void) { timerTSH+=timerTSCount; timerTS=timerTSH*65000+TIM4->CNT; timerTSCount=0; return timerTS; }
(3)主函数
//定时器实验 int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //PriorityGroupConfig NVIC中断分组设置 组2(2位抢占优先级,2位响应优先级) initDebugSerial(500000);//初始化调试串口USART1,波特率500000 initSysTick();//初始化滴答定时器和TIM4定时器 showVersion();//显示版本 while(1) { ; } }
(4)实验结果:
e.实验总结:TIM定时器除了定时外还可以用于输出PWM等,是STM32芯片中很重要的外设资源。因此,我们常用SysTick系统滴答定时器实现延时。