当前位置:   article > 正文

详细SysTick定时器(+对寄存器段位的解释)_systick寄存器

systick寄存器

1。       首先,systick定时器(嘀嗒定时器)隶属于CM4内核的一个外设,内嵌在NVIC中,所以一些函数在core_cm4.c中,系统定时器是一个24bit向下递减的计数器,计数器每次计数时间为1/SYSCLK。        (SYSCLK->系统时钟,通常设定为100MHZ。公式:f=100MHZ,则T=1/f=1/SYSCLK)。                                                          

当重装载数值寄存器的值减到0时,系统定时器就产生一次中断(这个中断需要配置并使能),以此循环往复

频率与周期对照表:(f与T)。 1Hz:1s        1Khz=1ms       1Mhz:1us        100Mhz:10ns                

 对原理图:首先对SysTick->CTRL的第16位置1后,使能LODA(LODA->装载),对SysTick->VAL进行赋值,(VAL当前数值,对应递减的数值,随着数字递减,数值在变化),之后可以选择不分频或者8分频,重装载计数器每1/SYSCLK计数一次,也就是1/100Mhz,10ns计数一次,计数100次就是1us。

2。SysTick定时器寄存器

定时器配置时,只需要配置前三个,最后一个校准寄存器不用配置。 

 

 位段16:计数标志位,意思是:读了该位,他自己清0,如果读过一次,并且他还是0,则该位变成1

 位段2:选择分频

 位段1:置1后,计数器计到0就产生请求,为0没啥作用,

位段0:使能位

段位:把内存分为很多段,每一段有一个段基址,当然段基址也是一个20位的内存地址。不过段寄存器仍然是16位的,它的内容代表了段基址的高16位,这个16位的地址后面再加上4个0就构成20位的段基址。

这个简单,意思是计数到0自己会重新装载数值再倒计时 

 可读可写位。读的时候,就是把寄存器当前倒计的数值进行读取

                        写的时候,意思只是把它置位写状态,这个不是设定数值的寄存器,写不进去实际数值,置写位后,还会清除COUNTFLAG的标志位。

SysTick->VAL寄存器的值每一个时钟周期就会递减1,当他递减到0时候, SysTick->LOAD的值将会进入SysTick->VAL中,并且SysTick->CTRL的COUNTFLAG位将会置1,如果还使能了中断,将还会进入中断。

延时原理就是通过设定SysTick->LOAD的值以及时钟周期的数值(通常设定为100MHz)来实现的

定时器的配置代码如下:(在core_cm4.h中)                                                                                                                                                                                     

  1. __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
  2. {
  3. if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) { return (1UL); } /* Reload value impossible */
  4. SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
  5. NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  6. SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
  7. SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
  8. SysTick_CTRL_TICKINT_Msk |
  9. SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
  10. return (0UL); /* Function successful */
  11. }

        对于SysTick_Config(uint32_t ticks);这个函数,要知道他已经将定时器配置为AHB(100MHZ) 时钟为 SysTick 定时器的时钟频率,并且使能了计数中断。也就是说,计数ticks(变量参数)次,就会产生一次SysTick中断。

        因此,我们就可以根据这个进行配置我们想要的ticks参数。例如:我们配置1ms的SysTick中断,我们可以调用SysTick_Config(uint32_t ticks);这个函数,首先,因为我们的计数周期为10ns(1/100MHZ),1ms/10ns=10*-3  /  10*-8=100000,也就是要递减10 0000次,也就是SysTick->VAL递减10 0000次,所以SysTick->LODA是10 0000,也可以说ticks参数必须是10 0000

SysTick_Config(SystemCoreClock/1000);    //设置SysTick定时器1ms中断一次

参数ticks=SystemCoreClock/1000(SystemCoreClock为系统时钟100Mhz,100Mhz/1000=10 0000)。也可以直接填10 0000.

3。利用SysTick定时器设计程序,运行计时器

        在此,我们定义一个全局变量volatile uint32_t sysTickUptime=0;在之后,每一次产生中断sysTickUptime++;(volatile修饰符表示sysTickUptime变量是一个易变的变量,它告诉编译器不要优化内容,直接读取变量内容)。

        SysTick定时器中断在文件stm32f4xx_it.c,它中不仅有SysTick定时器中断,其他所有中断都在其中。

         SysTick定时器中断代码如下:

  1. extern unit32_t sysTickUptime;
  2. void SysTick_Handler(void)
  3. {
  4. sysTickUptime++;
  5. }

        通过这段简单的代码可知:每1ms产生中断后sysTickUptime会进行加1。就是说,如果我们想知道一段代码运行了多长时间,可以在代码前面,后面分别读一下sysTickUptime的值:StartTime=sysTickUptime; 代码运行时间;EndTime=sysTickUptime;最终代码运行的时间为EndTime-StartTime(ms)

        但是,在32系统时钟中,都是以兆级别的,所以一个程序运行时间很短,一般以微妙级,所以毫秒对于一些代码,可能太大,不适合,不满足要求,所以也有微妙的计数器,以下是微妙级函数:

  1. //延时初始化
  2. void Delay_init(void)
  3. {
  4. RCC_ClocksTypeDef clocks;
  5. //选择系统时钟HCLK作为Systick定时器的时钟,开Systick中断1ms一次
  6. SysTick_Config(SystemCoreClock/1000);
  7. RCC_GetClocksFreq(&clocks);//获取当前时钟
  8. usTicks = clocks.SYSCLK_Frequency/1000000;//100M/1M=100次 也就是计数100次为1us
  9. }
  10. //微妙计数器
  11. uint32_t micros(void)
  12. {
  13. //register请求编译器尽可能的将变量存在CPU内部寄存器,而不是通过内存寻址访问。
  14. register uint32_t ms, cycle_cnt;
  15. do
  16. {
  17. ms = sysTickUptime;
  18. cycle_cnt = SysTick->VAL;//SysTick->VAL 的计数范围10 0000~0就是1ms,递减计数器
  19. }while (ms != sysTickUptime);
  20. return (ms*1000)+ (usTicks * 1000 - cycle_cnt)/usTicks;
  21. }

        我们配置SysTick定时器的计数时钟为系统时钟,也就是100Mhz,也可以说SysTick->VAL每10ns递减1,1us也就是递减100次,1ms也就是10 0000次,其实我们也可以把上面的程序改为微妙级的中断,但是这样比较消耗资源,中断频率太高对程序运行也不太友好 。因此,我们可以进行毫秒中断微秒计时的方法。usTicks表示1微秒的计数次数,usTicks=100Mhz/1Mhz=100次,那么,在我们没进毫秒中断前进行循环读取sysTickUptime和SysTick->VAL的值(毫秒级别大嘛,没产生中断前可以读很多次),SysTick->VAL是从10 0000递减到0进行一次中断sysTickUptime才加1。

        所以在函数micros(void);在调用的时候,do{},while()里面的函数先进行一次执行,把两个值分别赋给ms,cycle_cnt,因为刚赋完,ms肯定=sysTickUptime,所以条件不满足,立即返回微妙计数值。等待sysTickUptime更新后,就再进入函数。就是说:do{},while()​​​​​​​里面的循环体只有在sysTickUptime更新时才执行两次,其他情况执行一次就返回了微妙计数。

4。​​​​​​​利用SysTick定时器设置精准延时

        上面我们写出了毫秒计数器millis();i和微妙计数器micros();也知道了怎么计算程序运行时间,其实延时函数就简单为:延时多长时间计多少次数。

  1. //毫秒延时
  2. void delay_ms(unit32_t nms)
  3. {
  4. uint32_t mStart = 0;
  5. mStart = mills();//毫秒开始值
  6. while(mills()-mStart<nms)
  7. {}
  8. }
  9. //微妙延时
  10. void delay_us(uint32_t nus)
  11. {
  12. uint32_t uStart =0
  13. uStart = micros();
  14. while(micros()-uStart<nus)
  15. {}
  16. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/285169
推荐阅读
相关标签
  

闽ICP备14008679号