STM32系统滴答_及不可不知的延时技巧上
注:中断分组我在实验中,最初初始化设置为如下:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
设为第二组。
在
voidSysTick_Handler(void) { EXTI_GenerateSWInterrupt(EXTI_SWIER_SWIER1); LED_1=ON; Delay(); }
系统滴答中断里触发外部中断事件,并点亮LED1 。
外部中断处理函数如下
voidEXTI1_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line1)!=RESET) { EXTI_ClearITPendingBit(EXTI_Line1); LED_0=ON; Delay(); } }
此延时函数为阻塞延时如下:
voidDelay(void) { u32i; for(i=0;i<0xFFFFF;i++){} }
加入延时是为了看出来哪个灯先亮。
当外部中断优先级比较高时,它可以抢占Systick中断先执行,以上代码实验结果为,LED0先点亮后,再回到LED1再点亮。
当把外部中断设置为与systick相同的优先级时,则systick优先级就会相对较高,例如把上面的优先级改为
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;
则会LED1先亮,执行完SysTick_Handle函数后才轮到EXTI1_IRQHandler执行。
个人认为,若要实现systick精确延时,最好把systick优先级设置高一些,例如
NVIC_SetPriority(SysTick_IRQn,0);
即把SCB->SHP[11] = 0x00;则可达到systick优先级高于任合外部中断的效果,此时延时会比较精准。
另外对于SysTick的时钟源的选择,要注意它的时钟源可选择内部时钟(FCLK,CM3上的自由运行时钟,STM32中对应是AHB),或者是外部时钟( CM3处理器上的STCLK信号,STM32中对应是AHB/8)
可参考如下图
它是在SysTick->CTRL第二位CLKSOURCE时钟源选择中设置。
有关systick延时函数的编写可参考野火《零死角玩转stm32-初级篇》。
至此我们可以简单的实现一流水灯程序
while(1) { LED_0=OFF; LED_1=ON; Delay_ms(500); LED_0=OFF; LED_1=ON; Delay_ms(500); }
然而这样做真的好吗?这里用的是阻塞延时哦,CPU的效率很大一部分就耗在了空转上了,太浪费资源。
假设系统时钟频率为72MHZ或者几十上百MHZ时,当完成一个循环只需要几十或十几纳秒级或者更短,而在这个循环之中阻塞延时个几十至几百毫秒的话,就像是在高速公路上突然横出一条坑坑洼洼的泥泞路,那可想整条路都会因此而慢下来,甚至会出现灾难性的后果,个人认为,一般在系统初始化过程中,各芯片的时序对时间有要求,可以用下阻塞延时,只需要系统启动时运行一下,当系统跑起来之后,最好就别再傻呼呼的这么做了。
这时主要采用的是在定时器里计数,在外部循环中对变量查询,达到某个值时再执行某个动作,达到延时的效果,而在时间未到时,系统还可以不停的跑圈圈,做别的事情去。
gticks在定时中断里每毫秒计数一次
while(1) { if(500==gticks) { LED_0=OFF; LED_1=ON; } if(1000==gticks) { LED_0=OFF; LED_1=ON; gticks=0 } Do_others(); }
以上需要在事件处理过程中对gticks进行处理,增加了代码的耦合度,更容易出错,如果在一个事件处理中对gticks清除了,而下个事件中又需要查询它,这样就可能导致处理时序的错乱,相互干扰。
能否在事件处理中只提供查询功能,而定时的事情就交给定时自己去做?
下节高手将登场了,为大家介绍个我曾在一项目中学到的,非阻塞延时的精妙设计。
STM32系统滴答延时技 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)