历史上的今天
返回首页

历史上的今天

今天是:2024年09月02日(星期一)

正在发生

2019年09月02日 | STM32开发 -- Systick定时器

2019-09-02 来源:eefocus

一、Systick定时器介绍

参看:STM32菜鸟成长记录—系统滴答定时器(systick)应用

参看:SysTick定时器和delay延迟函数


SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号: 15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。


**优点: **节省MCU资源,不需要浪费一个定时器,只要不清除Systick使能位,就不会停止,即使在睡眠模式下也能工作。捆绑在NVIC中断优先级管理,能产生Systick异常(中断),可设置中断优先级。


二、相关寄存器

SysTick结构体定义:


**/** @addtogroup CMSIS_CM3_SysTick CMSIS CM3 SysTick

  memory mapped structure for 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;**


1、SysTick->CTRL, --控制和状态寄存器

这里写图片描述

2、SysTick->LOAD, --重装载寄存器

这里写图片描述

3、SysTick->VAL, --当前值寄存器

这里写图片描述

4、SysTick->CALIB, --校准值寄存器


这里写图片描述

三、相关函数解析

1、SysTick_CLKSourceConfig 配置SysTick时钟源

/**

  * @brief  Configures the SysTick clock source.

  * @param  SysTick_CLKSource: specifies the SysTick clock source.

  *   This parameter can be one of the following values:

  *     @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source.

  *     @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source.

  * @retval None

  */

void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)

{

  /* Check the parameters */

  assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));

  if (SysTick_CLKSource == SysTick_CLKSource_HCLK)

  {

    SysTick->CTRL |= SysTick_CLKSource_HCLK;  //内部时钟72M

  }

  else

  {

    SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;  //外部时钟 72/8=9M

  }

}


其中这两种时钟源 :

  SysTick_CLKSource_HCLK_Div8 外部时钟 72/8=9M

  SysTick_CLKSource_HCLK 内部时钟 HCLK=72M


2、SysTick_Config 初始化并启动SysTick计数器及其中断。

#if (!defined (__Vendor_SysTickConfig)) || (__Vendor_SysTickConfig == 0)

/**

 * @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);       //ticks参数有效性检查


  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; //设置重装载值

                                                    //-1:装载时消耗掉一个Systick时钟周期


  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); //配置NVIC


  SysTick->VAL   = 0;    //初始化VAL=0,使能Systick后立刻进入重装载

  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |      //选择时钟源

                   SysTick_CTRL_TICKINT_Msk   |      //开启Systick中断

                   SysTick_CTRL_ENABLE_Msk;          //使能Systick定时器

  return (0);      /* Function successful */

}


#endif


作用: 使能Systick定时器,开启SysTick中断,配置中断时间间隔

参数ticks: 设置多少个Systick时钟周期产生一次中断


*********************************************************************************************************

*                                          OS_CPU_SysTickInit()

*

* Description: Initialize the SysTick.初始化OS时钟

*

* Arguments  : none.

*

* Note(s)    : 1) This function MUST be called after OSStart() & after processor initialization.

*********************************************************************************************************

*/


void  OS_CPU_SysTickInit (void)

{

//SYSTICK分频--时钟节拍为:OS_TICKS_PER_SEC

if (SysTick_Config(SystemCoreClock / OS_TICKS_PER_SEC)) //1ms定时器

  { 

    /* Capture error */ 

    while (1);

  }

}


其中:


  uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;        /*!< System Clock Frequency (Core Clock) */


#define SYSCLK_FREQ_72MHz  72000000


  #define OS_TICKS_PER_SEC       1000    /* Set the number of ticks in one second             

则 SysTick_Config(72000) 为定时1ms


====================================

根据学过的物理中的时间与频率的公式:fosc=1/T T=1/fosc ,fosc为系统的频率。

如果STM32时钟频率为:72MHz,每次的时间为:T=1/72MHz。1秒钟为:1/(每次的时间)=1/(1/72MHz)=72 000 000次。1MHz是:1000 000。


反过来讲。

SysTick_Config(72000)代表:72000*(1/72MHz)=1/1000=1(ms)。

即定时为1ms。

如果需要1S则,可以通一设置一个全局变量,然后定初值得为1000,这样,每个systick中断一次,这个全局变量减1,减到0,即systick中断1000次,时间为:1ms*1000=1S。从而实现1S的定时。


3、SysTick_Handler Systick中断

/*******************************************************************************

* Function Name  : SysTick_Handler

* Description    :UCOS 系统时钟,

*******************************************************************************/

void SysTick_Handler(void)

{

CPU_SR         cpu_sr;

if(OSRunning > 0){

OS_ENTER_CRITICAL();                         /* Tell uC/OS-II that we are starting an ISR          */

OSIntNesting++;

OS_EXIT_CRITICAL();

}

//用户程序..

OSTimeTick();                                /* Call uC/OS-II's OSTimeTick()                       */

//BSP_GPS_TimerServer();

Inctime ++;  //

if(OSRunning > 0){

OSIntExit();                                 /* Tell uC/OS-II that we are leaving the ISR          */

}

}


四、SysTick实现延时函数

或参看:STM32系统定时器SysTick


//初始化延迟函数

//当使用OS的时候,此函数会初始化OS的时钟节拍

//SYSTICK的时钟固定为HCLK时钟的1/8

//SYSCLK:系统时钟

void delay_init()

{

#if SYSTEM_SUPPORT_OS  //如果需要支持OS.

u32 reload;

#endif

SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟  HCLK/8

fac_us=SystemCoreClock/8000000; //为系统时钟的1/8  

#if SYSTEM_SUPPORT_OS  //如果需要支持OS.

reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为K    

reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间

//reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右

fac_ms=1000/delay_ostickspersec; //代表OS可以延时的最少单位    


SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;    //开启SYSTICK中断

SysTick->LOAD=reload; //每1/delay_ostickspersec秒中断一次

SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;    //开启SYSTICK    


#else

fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数   

#endif

}     


#if SYSTEM_SUPPORT_OS  //如果需要支持OS.

//延时nus

//nus为要延时的us数.        

void delay_us(u32 nus)

{

u32 ticks;

u32 told,tnow,tcnt=0;

u32 reload=SysTick->LOAD; //LOAD的值      

ticks=nus*fac_us; //需要的节拍数    

tcnt=0;

delay_osschedlock(); //阻止OS调度,防止打断us延时

told=SysTick->VAL;        //刚进入时的计数器值

while(1)

{

tnow=SysTick->VAL;

if(tnow!=told)

{     

if(tnow else tcnt+=reload-tnow+told;     

told=tnow;

if(tcnt>=ticks)break; //时间超过/等于要延迟的时间,则退出.

}  

};

delay_osschedunlock(); //恢复OS调度     

}

//延时nms

//nms:要延时的ms数

void delay_ms(u16 nms)

{

if(delay_osrunning&&delay_osintnesting==0) //如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)     

{  

if(nms>=fac_ms) //延时的时间大于OS的最少时间周期 

    delay_ostimedly(nms/fac_ms); //OS延时

}

nms%=fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时    

}

delay_us((u32)(nms*1000)); //普通方式延时  

}

#else //不用OS时

//延时nus

//nus为要延时的us数.        

void delay_us(u32 nus)

{

u32 temp;      

SysTick->LOAD=nus*fac_us; //时间加载    

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

SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数   

do

{

temp=SysTick->CTRL;

}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达   

SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器

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

}

//延时nms

//注意nms的范围

//SysTick->LOAD为24位寄存器,所以,最大延时为:

//nms<=0xffffff*8*1000/SYSCLK

//SYSCLK单位为Hz,nms单位为ms

//对72M条件下,nms<=1864 

void delay_ms(u16 nms)

{     

u32 temp;    

SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)

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

SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数  

do

{

temp=SysTick->CTRL;

}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达   

SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器

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

推荐阅读

史海拾趣

ELMEC Technology Of America Inc公司的发展小趣事

在ELMEC Technology Of America Inc公司初创时期,创始人李明和他的团队面临着一个巨大的挑战:如何开发一款能在市场上脱颖而出的电子产品。经过无数次的实验和失败,他们最终成功研发了一款高效能、低功耗的半导体芯片。这款芯片的问世不仅为公司带来了第一笔可观的收入,也奠定了ELMEC在电子行业的技术领先地位。

FASTRAX公司的发展小趣事

随着公司业务的不断发展,FASTRAX开始积极拓展海外市场,并与多家国际知名企业建立了战略合作关系。通过与这些企业的合作,FASTRAX不仅获得了更多的市场份额,也学习到了先进的管理经验和技术知识。这些合作经验为FASTRAX的持续发展奠定了坚实的基础。

Atlanta Micro公司的发展小趣事

Atlanta Micro的创立,源于几位对射频(RF)技术充满热情的工程师。他们看到了在航空航天和国防领域,高性能RF模块和组件的巨大需求,于是决定共同创业,致力于这一领域的研发。在创业初期,公司面临着资金短缺、市场竞争激烈等诸多挑战,但凭借着对技术的执着和不懈努力,Atlanta Micro逐渐在业界积累了声誉,并获得了初步的市场认可。

Component Research Co公司的发展小趣事

随着公司业务的不断发展,Component Research Co意识到单一市场无法满足其长期发展的需要。于是,公司开始寻求国际合作,与多家国际知名企业建立战略合作关系。这些合作不仅为公司带来了先进的技术和资金支持,还帮助公司打开了新的市场。通过国际合作,Component Research Co的业务范围逐渐扩展到全球各地。

台湾肯尼威(CANNYWELL)公司的发展小趣事

在追求经济效益的同时,肯尼威也积极履行社会责任。公司注重环保理念的融入,所有产品均符合ROHS环保要求。在生产过程中,公司采取了一系列环保措施,如使用环保材料、优化生产工艺等,减少了对环境的影响。此外,公司还积极参与环保公益活动,为推动社会的可持续发展贡献了自己的力量。

以上五个故事梗概均基于台湾肯尼威公司的发展历程和实际情况进行虚构创作,旨在展示公司在电子行业中的成长和进步。请注意,这些故事仅为虚构内容,并不代表公司实际的发展历程。

亿晶源(ekinglux)公司的发展小趣事

在不断提升产品质量和创新能力的同时,亿晶源还积极拓展市场。公司先后在华南、华东等地区设立生产基地和销售中心,形成了覆盖全国的销售网络。同时,公司还注重品牌建设,通过参加国内外知名展会、举办技术交流会等活动,提升品牌知名度和影响力。

问答坊 | AI 解惑

PIC 8位单片机的分类和特点

PIC 8位单片机的分类和特点 …

查看全部问答>

大赛用芯片资料

本帖最后由 paulhyde 于 2014-9-15 09:02 编辑 芯片资料  …

查看全部问答>

2010年的汽车电子趋势预测

中国的汽车产业在今年很有可能触及或跨越年产销一千万辆这个门槛,事实上在实现这个目标以前,中国就已经成为仅次于美国的全球第二大汽车市场。在当前的汽车中,汽车电子系统所占的比重越来越大,很多特色化的功能都是依赖汽车电子技术来实现的,如 ...…

查看全部问答>

淘宝上的linux开发板能买不??

我是新手,以前都是跟着导师做单片机的。感觉单片机有点“不过瘾”的感觉,想往高深的学。想学linux下嵌入式编程,但是身边又没有的这方面的资源。于是想买一块开发板子。请问:淘宝上的那种便宜的开发板比如像2410、2440板子能买不?? 问题1:开 ...…

查看全部问答>

请问一般公司会招聘底层开发(驱动开发)的应届生吗

本人在校学生,最近做的项目都用到了一些驱动的开发,感觉底层这方面的编程比普通的软件开发难度大一点。如果是软件公司招聘的话,他们会招聘新手吗?个人感觉做这方面的真正开发,都是有多年经验的老手。…

查看全部问答>

ce下怎么获取ESN码还有怎么获取是手机的型号啊。。

ce下怎么获取ESN码还有怎么获取是手机的型号啊。。 …

查看全部问答>

伺服系统小结(连续上篇)

三、伺服系统调试   接通伺服驱动器的电源, 先进入测试调整模式,测试调整模式可以执行伺服驱动器的测试操作,报警复位和参数编辑等等.其数字操作器的按键说明如表1: 键 出现的情况 MOD 在不同模式 ...…

查看全部问答>

2812调试时关于看门狗的一些问题

2812调试时关于看门狗的一些问题 大家好, 我目前正在调试一块自己做的2812的板子,遇到关于看门狗的一些问题: 一点连续运行按钮程序就跳到3FFC00处(此处应该是复位向量),而点单步运行的时候程序可以走的.点连续运行的时候用示波器观察reset引脚,发 ...…

查看全部问答>

机械电能表到电子式电能表讲义

机械电能表到电子式电能表讲义,从事电能表行业可以看看哦! [ 本帖最后由 aishuang 于 2011-7-16 12:22 编辑 ]…

查看全部问答>

请大家看看我这个串口的程序哪里不对??很多乱码

单片机的接收端是连接的GPS信号, 发送端连接的是GPRS的接收。 单片机就是把收到的经纬度找出来传给GPRS,用UDP发送。 只要不连GPS, 发送的数据就完全正确。 连了GPS之后,数据就乱了,GPS是一直在发送,速度很快 #include #include #incl ...…

查看全部问答>