1、系统滴答定时器
参考资料《Cortex M3与M4权威指南.pdf》中的9.5 The SysTick timer小节,里面详细讲解了
1、为什么要用SysTick计时器;
2、SysTick定时器的操作情况;
3、如何使用SysTick定时器;
4、使用SysTick定时器。
2、简介
系统定时器【SysTick】它挂载在AHB时钟线上,是一个24bit的向下递减的计数器,计数器每计数一次的时间为1/SystemCoreClock,当前我们的开发板选用的是8M的外部晶振,倍频至120M。当重装载数值寄存器的值递减到0的时候,系统定时器就产生一次中断,以此循环往复。
3、SysTick寄存器
SysTick寄存器:
CTRL:SysTick控制及状态寄存器
LOAD:SysTick重装载数值寄存器
VAL:SysTick当前数值寄存器
CALIB:SysTick校准数值寄存器
SysTick控制及状态寄存器:
COUNTFLAG:如果在上次读取本寄存器后 SysTick已经计到了0,则该位为 1;
CLKSOURCE:时钟源选择位 ,0=AHB/8,1=处理器时钟AHB
TICKINT:1=SysTick倒数计数到 0时产生 SysTick异常请求,0=数到 0 时无动作。也可以通过读取COUNTFLAG标志位来确定计数器是否递减到0
ENABLE:SysTick 定时器的使能位
思路
SysTick->VAL寄存器的值每一个时钟周期就会递减1,当它递减到0时候,SysTick->LOAD的值将会进入SysTick->VAL中,并且SysTick->CTRL的COUNTFLAG位将会置1,如果还使能了中断,将还会进入中断。
延时原理就是通过使能中断,并设定SysTick->LOAD的值以及时钟周期的数值(通常设定为1kHz = 1ms)来实现的。
4、SysTick代码如下:
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
SysTick->LOAD = ticks - 1; /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */
SysTick->VAL = 0; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
M4手册解说
如果你只想产生一个周期性的SysTick中断,最简单的方法是使用systick.c中的函数“SysTick_Config”:
SysTick_Config(uint32_t ticks);
该函数将SysTick中断间隔设置为“ticks”,启用使用处理器时钟的计数器,并启用异常优先级最低的SysTick异常。
例如,如果你有一个120MHz的时钟频率,你想要触发一个1KHz的SysTick异常,则ticks=120000;触发一个1MHz的SysTick异常,则ticks=120;
个人理解
AHB为120MHz,则计数周期为(1/120)us,1ms/(1/120)us=10^3*120=120000,也就是计数1ms要递减120000次,也就是SysTick->VAL递减120000次,所以SysTick->LODA是120000,也可以说ticks参数必须是120000;
5、SysTick库函数添加延时函数
先初始化SysTick配置函数:将SysTick函数配置成ms级中断,如果配置成us级中断,中断就会频繁的进入,将会占用cpu的使用资源。
volatile static uint32_t delay;
/*!
\brief configure systick
\param[in] none
\param[out] none
\retval none
*/
void systick_config(void)
{
/* setup systick timer for 1000Hz interrupts */
if(SysTick_Config(SystemCoreClock / 1000U)) {
/* capture error */
while(1) {
}
}
/* configure the systick handler priority */
NVIC_SetPriority(SysTick_IRQn, 0x00U);
}
/*!
\brief delay a time in milliseconds
\param[in] count: count in milliseconds
\param[out] none
\retval none
*/
void delay_1ms(uint32_t count)
{
delay = count;
while(0U != delay) {
}
}
/*!
\brief delay decrement
\param[in] none
\param[out] none
\retval none
*/
void delay_decrement(void)
{
if(0U != delay) {
delay--;
}
}
其中SystemCoreClock定义为120000000;
在中断函数运行void delay_decrement(void)函数,实现1ms递减一次。
void SysTick_Handler(void)
{
delay_decrement();
}
us计数器原理:由于SysTick->VAL 的计数范围120000~0就是1ms,递减计数器,每变化120就是1us。
void delay_1us(uint32_t count)
{
register uint32_t us_tcnt, cycle_cnt;
us_tcnt = count*120; //SysTick->VAL 的计数120~0就是1us,递减计数器,最大值不超过1ms
cycle_cnt = SysTick->VAL;
if(cycle_cnt>=us_tcnt) //在计数到0前,满足计数要求
{
while(cycle_cnt-us_tcnt<SysTick->VAL);
}
else //需要计数到第二次转载值后
{
while(cycle_cnt>SysTick->VAL);
while(cycle_cnt-us_tcnt<SysTick->VAL);
}
}
—SystemCoreClock———————————————
版权声明:本文为CSDN博主「极术社区」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_47569031/article/details/128954917
SysTick_Config函数的输入参数不能装进大于24位加载值(大于OxFFFFFF),
否则SysTick_Config函数返回1失败。
/* SysTick Reload Register Definitions */
#define SysTick_LOAD_RELOAD_Pos 0 /*!< SysTick LOAD: RELOAD Position */
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL << SysTick_LOAD_RELOAD_Pos) /*!< SysTick LOAD: RELOAD Mask */
6、函数测试
示波器测试IO口电平,100us反转一次
500ms反转一次
版权声明:本文为CSDN博主「极术社区」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_47569031/article/details/128954917