zoukankan      html  css  js  c++  java
  • SysTick定时器的一个简单应用

     

    SysTick即为系统定时器,又称嘀嗒定时器,是Cortex-M3内核的一个外设,集成在NVIC中。SysTick是一个24bit的向下递减的计数器,每计数一次的时间为1/SYSCLK(SYSCLK一般为72MHz)。

    操作系统需要执行多任务管理,用SysTick产生中断,确保单个任务不会锁定整个系统。同时SysTick还可用于闹钟定时、时间测量等。

    由于Cortex-M3芯片都有SysTick,所以软件可以很容易地在Cortex-M3的产品间移植。

    我们待会儿将利用SysTick产生1s的时基,让LED一秒钟闪烁一次,以完成SysTick的定时实验。

    注:本文所用芯片为stm32f103。

    SysTick寄存器

    SysTick定时器由四个寄存器控制,如图7-1所示。

    图7-1

    上图是对四个寄存器各个位的描述。其中最后一个校准值寄存器(STK_CALIB)在定时实验中并没有用到,这里暂且不介绍,有兴趣的读者可以自行查找其他资料阅读。


    编程要点

    1. 向SysTick重装载值寄存器(STK_LOAD)写入新的重装载值;
    2. 配置中断优先级;
    3. 写SysTick当前值寄存器(STK_VAL),将当前值清0;
    4. 写SysTick控制及状态寄存器(STK_CTRL),启动SysTick。

    SysTick属于内核外设,其相关的寄存器定义和库函数都在core_cm3.h中。如图7-2为core_cm3.h头文件里配置SysTick的源码截图。

    图7-2

    SysTick_Config()库函数即是按照上述的编程要点完成SysTick配置的。我们在实际项目中时可以直接调用这个库函数来完成配置。而形参ticks用来设置STK_LOAD的值,最大不超过2^24。然后配置中断优先级,清空STK_VAL,最后配置STK_CTRL。其中,在配置中断优先级时调用了NVIC_SetPriority()库函数,传入的优先级实参为(1<<__NVIC_PRIO_BITS) - 1,其中宏__NVIC_PRIO_BITS为4,则可得其优先级为15,则可以看出其默认设置的优先级在内核外设中是最低的。

    那么如果我们同时设置了内核外设和片上外设的优先级,该如何判断孰高孰低呢?

    专栏(stm32):stm32中断初识与实践(上)里说过,在配置外设中断优先级时,需要先分组,再设置抢占优先级及子优先级,那么我们把内核外设的优先级也用同一配置方式分解为这三个部分。

    假设配置一个外设的中断优先级分组为3,抢占优先级为2,子优先级为1,而SysTick优先级为4。则将SysTick优先级4转换为二进制,为0100(0b),在分组为3时,SysTick抢占优先级为010(0b),即为2,子优先级为0。我们先比较抢占优先级,发现相同,那么比较子优先级,此时SysTick子优先级为0,而我们假设的外部中断子优先级为1,所以SysTick优先级大于假设的外设优先级(数值越小,优先级越高)。

    中断时间计算

    SysTick的计数器执行的是倒计时,我们要计算中断计数时间,需要知道计数总量(STK_LOAD的值)、时钟源频率等两个参数。打个比方,这相当于我们要计算运动时间,需要知道距离和速度,那么STK_LOAD的值即为距离,时钟源频率即为速度。则中断计数时间为(假设STK_LOAD的值为VALUE,时钟源频率为CLK,中断计数时间为T):

    T = VALUE / CLK(其中,CLK为72MHz)

    当STK_LOAD的值VALUE减到0时,即可产生中断。如果设置VALUE=72000,那么中断一次的时间T = 72000 / 72MHz = 1ms。

    定时时间计算

    得出中断一次的时间后,我们可以设置一个变量n,用来记录中断次数,那么最终的定时时间即为T*n。

    回到开头的实验说明中,我们需要产生1s时基,来实现LED灯1s闪烁一次,则n为1000时满足要求。

    #define SysTick_CTRL_ENABLE_Pos     0                     
    #define SysTick_CTRL_ENABLE_Msk     (1ul << SysTick_CTRL_ENABLE_Pos)
    
    /**
      * @brief  毫秒级的定时函数
      * @param  n:毫秒数,如n为1000,则计时1000*1ms=1s
      * @retval 无
      */
    void SysTick_Delay_ms(uint32_t n){
        uint32_t i;
        SysTick_Config(72000);    // 产生1ms的中断(72000 / 72MHz = 1ms)
    	
        for(i=0; i<n; i++){
    	while(!((SysTick->CTRL)&(1<<16)));
        }
    	
        SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;     // 失能SysTick
    }
    

    由于SysTick不会自动停止,所以我们需要在异常/中断处理中将其停止,即失能SysTick。

    到这里为止,一个简单的SysTick定时实验完成了,之后只要在main函数中调用SysTick_Delay_ms(1000)函数,即可实现1s的精确SysTick定时,而不是使用普通的不精确延时函数。

  • 相关阅读:
    【酷熊科技】工作积累 ----------- 随机数 (带权重的随机数)
    【酷熊科技】工作积累 ----------- unity scrollview 点击后会有偏移问题(有图片)
    cocos2dx混合模式应用———制作新手引导高亮区域 (2.2.0)
    3.20 内存及效率的一些总结 3.21 设置竖屏 3.22 CCLOG与CCLog区别
    3.18 CCProgressTo 进度计时器
    3.16 draw 3.17 更新函数
    3.15 获取当前设备语言
    CCControlSwitch 、CCControlSlider、CCControlButton
    CCEditBox
    CCTextFieldTTF 与 5种常用CCMenuItem
  • 原文地址:https://www.cnblogs.com/fire909090/p/8875420.html
Copyright © 2011-2022 走看看