历史上的今天
今天是: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 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; //清空计数器
史海拾趣
|
中国的汽车产业在今年很有可能触及或跨越年产销一千万辆这个门槛,事实上在实现这个目标以前,中国就已经成为仅次于美国的全球第二大汽车市场。在当前的汽车中,汽车电子系统所占的比重越来越大,很多特色化的功能都是依赖汽车电子技术来实现的,如 ...… 查看全部问答> |
|
我是新手,以前都是跟着导师做单片机的。感觉单片机有点“不过瘾”的感觉,想往高深的学。想学linux下嵌入式编程,但是身边又没有的这方面的资源。于是想买一块开发板子。请问:淘宝上的那种便宜的开发板比如像2410、2440板子能买不?? 问题1:开 ...… 查看全部问答> |
|
本人在校学生,最近做的项目都用到了一些驱动的开发,感觉底层这方面的编程比普通的软件开发难度大一点。如果是软件公司招聘的话,他们会招聘新手吗?个人感觉做这方面的真正开发,都是有多年经验的老手。… 查看全部问答> |
|
三、伺服系统调试 接通伺服驱动器的电源, 先进入测试调整模式,测试调整模式可以执行伺服驱动器的测试操作,报警复位和参数编辑等等.其数字操作器的按键说明如表1: 键 出现的情况 MOD 在不同模式 ...… 查看全部问答> |
|
2812调试时关于看门狗的一些问题 大家好, 我目前正在调试一块自己做的2812的板子,遇到关于看门狗的一些问题: 一点连续运行按钮程序就跳到3FFC00处(此处应该是复位向量),而点单步运行的时候程序可以走的.点连续运行的时候用示波器观察reset引脚,发 ...… 查看全部问答> |
|
单片机的接收端是连接的GPS信号, 发送端连接的是GPRS的接收。 单片机就是把收到的经纬度找出来传给GPRS,用UDP发送。 只要不连GPS, 发送的数据就完全正确。 连了GPS之后,数据就乱了,GPS是一直在发送,速度很快 #include #include #incl ...… 查看全部问答> |




