STM32使用Systick 实现精确定时

来源:互联网 发布:淘宝店招链接怎么做 编辑:程序博客网 时间:2024/04/30 12:51

实实在在学会使用Systick请看:

这篇学习笔记,完全是基于《STM32不完全手册》而言的,我没有买Alientek的开发板,买的是ARMFly的,其实都差不多,只不过安福莱的板载资源非常丰富罢了,应用起来其实都差不都。

《STM32不完全手册》的51到56页就是要这次笔记学习的内容,请自己参考,我不再粘帖,主要讨论的内容其实就几行:

void delay_init(u8 SYSCLK)
 {
 SysTick->CTRL&=0xfffffffb;  //SysTick->CTRL能配置的只有0/1/2/3/16,其他是保留的.b=1011  1:计数比较标志,0:HCLK/8,1:开启systick中断,1:开启systick功能

fac_us=SYSCLK/8;                      
 fac_ms=(u16)fac_us*1000;
 }

Systick主要的作用就是拿来计时,其原理和应用简述一下就是这样的:通过配置寄存器SysTick->CTRL来设定Systick的计时频率并Enable使Systick开始计数,这里的SysTick->CTRL&=0xfffffffb应该很好理解,把第2位设定为0,查找应用手册可以知道这是把Systick的计时频率设定为CPU主频(SYSCLK)的1/8。

假定我们板子默认的晶振频率是8Mhz,默认CPU工作频率(SYSCLK)是9倍频,即72M,那Systick的频率就是72/8=9Mhz。

知道了Systick的频率,下一步就是确定倒时计数器的数值,即SysTick->LOAD这个寄存器的配置。上面已经知道了,Systick的工作频率F=9Mhz=SYSCLK/8,即每秒钟计数器自减900万次,也就是说,SYSCLK/8次的自减耗时1秒,那么(8/SYSCLK)/1000,000次自减就耗时1微秒了,这也就是fac_us的值了。那么上面函数中的fac_us为什么是SYSCLK/8呢?这里先搞清楚一点,函数中SYSCLK的单位是Mhz,所以SYSCLK的值是72(这个以Mhz为单位应该是STM32基础库里面做过宏定义的),否则也不可能用一个8位整形去表示一个7200万的数值;而我们这里计算的SYSCLK是以Hz为单位的,即72Mhz/1000,000=72,所以这个SYSCLK/8是对的。

第一遍看是否有点无奈?其实,你只要看调用函数就知道了:delay_init(72);SYSCLK就是72而已;函数中fac_us=SYSCLK/8;  虽然SYSCLK可能被你误解为72M,但这也是从规范性的角度讲还是合理的!

你可能还没搞清楚fac_us到底是干嘛的。很简单,fac_us就是要写入SysTick->LOAD寄存器的值,Systick的工作原理是这个寄存器的值在Systick被Enable之后就开始以设定的工作频率自减,减到0的时候就发出中断,实现定时。所以,写入fac_us到SysTick->LOAD寄存器,就是要Systick在自减了fac_us次以后发出中断,自减fac_us所耗的时间已经说了,1微秒。

下面的fac_ms应该很好理解了,就是1毫秒的计数次数,刚好是1微妙的1000倍,注意9×1000超出了8位整形的表示范围,所以要用(u16)先把fac_us转成16位变量,以保证计算的正确。

具体的应用函数是用来做延时,如下:

void delay_us(u32 nus)
 {             
 u32 temp;                         
 SysTick->LOAD=nus*fac_us; //时间加载                    
SysTick->VAL=0x00;                //清空计数器
SysTick->CTRL=0x01 ;           //Enable Systick,开始倒数    
do
 {
 temp=SysTick->CTRL;
 }
 while(temp&0x01&&!(temp&(1<<16)));//等待时间到达     
SysTick->CTRL=0x00;              //Disable Systick

SysTick->VAL =0X00;              //清空计数器       
}

具体的寄存器配置只要看手册就知道了,这里只需要理解一句:

do
 {
 temp=SysTick->CTRL;
 }
 while(temp&0x01&&!(temp&(1<<16)));//等待时间到达

核心就是while(temp&0x01&&!(temp&(1<<16)));//等待时间到达

temp已经是Systick控制寄存器的值了,temp&0x01就是把该寄存器的值读出并且把除第一位之外位都清零(当然要通过temp变量来传递值而不是直接修改寄存器),第一位就是Systick的Enable配置信息,写入1就是Enable,写入0就是Disable,读这一位是判断Systick是否仍然处于Enable状态(可能被其他中断禁用掉),temp&(1<<16)就是读取第16位的值,这一位如果为0就表示计数器的值不是0(即还在计数),如果是1就表示计数器已经自减到0了。

那么这段就很好理解了,即判断,如果Systick还在Enable的状态,并且计数器还没数到0,就不停的循环把当前的SysTick->CTRL寄存器值写入变量temp,继续下一次判断。当Systick被Disable或者计数器数到0了,就停止循环。因为只是做延时,也不需要跳到任何中断服务那边去处理什么,只要这个循环的耗时过程完成就可以了。

以上转自:http://www.eefocus.com/djnxqc/blog/12-08/284143_2b6b3.html

 

有关寄存器的说明请看:http://www.360doc.com/content/11/1114/21/7736891_164374659.shtml

如果你想用固件库写请看:http://xiaozhekobe.blog.163.com/blog/static/175646098201181982338806/

当然用固件库这篇文章说的是有小问题,不过不妨碍使用,通过上面的学习你也会一目了然看到问题所在。

 

原创粉丝点击