历史上的今天
返回首页

历史上的今天

今天是:2024年10月18日(星期五)

正在发生

2021年10月18日 | stm32专题九:SysTick(一)系统嘀嗒定时器原理

2021-10-18 来源:eefocus

SysTick是存在于stm32内核的定时器,嵌套在NVIC中,24位,只能递减。在stm32中文参考手册中,对于SysTick的描述其实很少,主要如下。systick的时钟可以为AHB时钟,或者是AHB时钟8分频=9M。而校准值固定为9000,也就是说,当时钟频率为9M时,9000的固定值对应1ms时间基准,9000 000对应1s时间。

在core-CM3编程手册中,有配置systick的寄存器描述。

SysTick控制和状态寄存器STK_CTRL

位描述:


COUNTFLAG:如果上一次计数到0,则返回1,为计数标志。


CLKSOURCE:选择时钟源,为0时即为AHB时钟8分频,为1时直接就等于AHB总线时钟。


TICKINT:SysTick异常请求使能,该位为1则计数值减到0时发起系统异常请求,为0时不响应。


ENABLE:该位为1时,计数值从重装载值寄存器开始往下递减,当减到0,会设置COUNTFLAG标志位为1,并根据TICKINT的值来选择是否发起系统异常请求,然后重新装初始值,开始计数。


STK_LOAD重装载值寄存器,设置计数初值。值得注意的是,SysTick是减到0,一次完整的计数过程是0 - 99 - 98 -... -0共100个数,这是循环计数过程。因此,如果我们希望的计数值为N,实际上要写入到LOAD寄存器的值必须为N-1,这个非常重要。

另外,如果是希望计数只触发一次,则填入的值还是N,因为少了一个0-N的一次记数,这些都有寄存器描述,最常用的循环计数还是初始值为N-1

还有一个当前计数值寄存器,该寄存器一旦写入就会将当前寄存器的所有位清零,并还会把CPUNTFLAG标志位清0,所以我们不要鬼这个寄存器进行写入操作。

野火给出的框图如下,也是在说明上述意义。

SysTick定时时间的计算:


时间t   单词执行的时间,和reload CLK有关;

CLK  9M或72M,由CTRL寄存器配置;

reload值,24位,用户配置;

所以就有下面的配置:


t = reload * (1 / CLK)


CLK = 72M时,t = (72) * (1 / 72M) = 1us,此时reload = 72


CLK = 72M时,t = (72000) * (1 / 72M) = 1ms,此时reload = 72000


注意,这是单次计数,所以reload = N,就是从N到0,实际上计数N次。而循环计数时,reload要设置为N-1,因为从N-1到0计数N-1次,再从0到N-1计数一次,这才是一个完整的循环周期。


如果产生中断的延时是微妙级别,那么系统会频繁的进入中断,很多事情就做不了了,与系统的时间相冲突,因此意义不大,通常使用的中断都是ms级别。


标准固件库中对SysTick有非常详细的描述


这个时初始化结构体


typedef struct

{

  __IO uint32_t CTRL;                         /*!< Offset: 0x00  SysTick Control and Status Register */

  __IO uint32_t LOAD;                         /*!< Offset: 0x04  SysTick Reload Value Register       */

  __IO uint32_t VAL;                          /*!< Offset: 0x08  SysTick Current Value Register      */

  __I  uint32_t CALIB;                        /*!< Offset: 0x0C  SysTick Calibration Register        */

} SysTick_Type;

然后看系统默认对SysTick的配置,这里有几个值得注意的地方,1 输入嘀嗒数不能超过2^24;2 嘀嗒数就是要定时的数N,因为代码里自动实现了N-1;默认将时钟配置为AHB时钟72M;默认中断优先级位最低优先级15。


/**

 * @brief  Initialize and start the SysTick counter and its interrupt.

 *

 * @param   ticks   number of ticks between two interrupts

 * @return  1 = failed, 0 = successful

 *

 * Initialise the system tick timer and its interrupt and start the

 * system tick timer / counter in free running mode to generate 

 * periodical interrupts.

 */

static __INLINE uint32_t SysTick_Config(uint32_t ticks)

  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */

                                                               

  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */

  // 设置SysTick 中断优先级,默认为最低的优先级(1 << 4) - 1 = 16 - 1 = 15

  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */

  SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */

  // 这里的SysTick_CTRL_CLKSOURCE_Msk = 1 << 2,默认会将时钟配置为AHB时钟源72M

  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 

                   SysTick_CTRL_TICKINT_Msk   | 

                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */

  return (0);                                                  /* Function successful */

}


固件库设置中断优先级的标准函数,首先判断中断标号<0(内核)还是>=0(外设),如果是外设的中断非常简单,直接设置IP寄存器的高4位(priority << 4),如果是内核的中断,不是设置NVIC_IP寄存器,而是设置SCB_SHPR寄存器。

/**

 * @brief  Set the priority for an interrupt

 *

 * @param  IRQn      The number of the interrupt for set priority

 * @param  priority  The priority to set

 *

 * Set the priority for the specified interrupt. The interrupt 

 * number can be positive to specify an external (device specific) 

 * interrupt, or negative to specify an internal (core) interrupt.

 *

 * Note: The priority cannot be set for every core interrupt.

 */

static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)

{

  if(IRQn < 0) {

    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */

  else {

    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */

}


当SysTick和外设同时产生中断时,根据4位数的数值大小来解析中断优先级的高低。

推荐阅读

史海拾趣

aconno公司的发展小趣事

随着公司实力的增强,aconno开始积极拓展国内外市场。通过与各大电商平台和分销商建立合作关系,aconno的产品迅速覆盖了更广泛的地域和用户群体。此外,公司还积极参与国际电子展和技术交流会,与全球合作伙伴建立紧密的合作关系,共同推动电子行业的发展。

EPCOS (TDK)公司的发展小趣事

面对数字化转型和能源转型的市场趋势,TDK-EPC公司积极调整战略方向,加大在传感器系统、新能源技术等领域的研发投入。通过与全球各大高校和研究机构的紧密合作,公司成功开发出了多款高性能的传感器系统和新能源产品,为客户提供了更加全面、高效的解决方案。这些成果不仅彰显了TDK-EPC公司的技术实力和市场竞争力,也为公司的未来发展奠定了坚实的基础。

EUCHNER公司的发展小趣事

随着全球化的发展,EUCHNER公司开始实施国际化战略,加强在全球市场的布局。公司在世界各地设立了多个分销处和办事处,以便更好地满足不同国家和地区的市场需求。同时,公司还积极与国际知名企业建立合作关系,共同推动工业自动化领域的进步。通过国际化战略和全球布局,EUCHNER公司的品牌影响力得到了进一步提升。

Allied Wire & Cable Inc公司的发展小趣事

Allied公司深知客户是公司发展的核心动力。因此,公司始终将客户服务放在首位,为客户提供全方位、个性化的服务支持。无论是产品咨询、技术支持还是售后服务,Allied公司都力求做到最好,赢得了客户的信任和好评。同时,公司还积极与合作伙伴建立长期稳定的合作关系,共同开拓市场,实现互利共赢。

General Electric Solid State公司的发展小趣事

为了保持市场竞争力,Allied公司始终注重技术升级和品质提升。公司投入大量资金引进先进的生产设备和技术,不断提高产品的技术含量和附加值。同时,公司还建立了严格的质量管理体系,从原材料采购到产品出厂的每一个环节都进行严格把控,确保产品的品质和性能达到最高标准。

H&D Wireless公司的发展小趣事

高创始终坚持研发为核心的发展路线,不断加大对新技术、新产品的投入。近年来,其研发投入占营收比例持续保持在较高水平,有时甚至超过15%。这种高强度的研发投入使得高创能够不断推出具有市场竞争力的新产品,如高性能多轴运动控制器、伺服系统等,满足了市场对于高精度、高速度、高性能运动控制解决方案的需求。

问答坊 | AI 解惑

关于80c51定时计数器

#define SYSTEM_OSC                 12000000        //定义晶振频率12000000HZ Sound_Temp_TH1 = (65535-(1/1200)*SYSTEM_OSC)/256;        // 计算TL1应装入 ...…

查看全部问答>

新手,询问pda与远程的数据库(oracle)同步问题,急!!!

原来没有做过嵌入式的开发,现在想在pda下做二次开发,系统是wince的,pda上的数据需要跟远程服务器的数据库做数据同步,远程的数据库为oracle,系统为b/s结构的,pda需要连接到pc机上在做同步,pc机可以连接系统,请教思路或者是有什么资料,万分 ...…

查看全部问答>

电子琴单片机仿真能否有一个美丽的界面

用单片机仿真做个电子琴  我想有一个电子琴的界面 不知道怎么整 有人说用vb做上位机 单片机做下位机    单这种方法只能用实物做吧 只用仿真软件怎么才能有界面呢? 大家看看可行不 不可行帮我想想其他想法 本人做毕业设计&n ...…

查看全部问答>

液晶显示模块

哪位高人帮我指点一下L046R4这个四位八段的液晶显示屏怎么用C语言编程,它好像没有时钟,下边是它的PDF资料,急求。谢谢! [ 本帖最后由 烟雨 于 2011-4-18 10:29 编辑 ]…

查看全部问答>

常用集成电路引脚识别

常用集成电路引脚识别:各种不同的集成电路引脚有不同的识别标记和不同的识别方法,掌握这些标记及识 别方法,对于使用、选购、维修测试是极为重要的。⒈缺口 在IC的一端有一半圆形或方形的缺口。⒉凹坑 色点或金属片 在IC一角有一凹坑、色 ...…

查看全部问答>

基于2407的逆变电源

比较老的设计,但是还是可以借鉴的…

查看全部问答>

<SPI> 控制 数字电位器 出问题了!!!

TPL0501具有256抽头的数字电位器,SPI控制,问题就是控制不了,就写一个字节就能控制电阻了啊,居然不行,还有波特率设多少比较合适,我用的外部6MHz晶振,程序贴上#include   void main(void) {   WDTCTL = WDTPW + WDTHOLD;& ...…

查看全部问答>