跳转到主要内容

STM32单片机systick使用注意事项

<font color="blue"><strong>1、前言</strong></font>

CM4内核的处理和CM3一样,内部都包含了一个SysTick定时器,SysTick 是一个24 位的倒计数定时器,当计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息。这样可以用systick来实现延时定时功能,不用再占用系统定时器。systick也多用做系统的时钟节拍,如freeRTOS等OS,再启动调度器的时候,就会将systick配置成其系统时钟,给系统提供心跳。systick中有4个寄存器CTRL、LOAD、VAL、CALIB

<center><img width="600" src="http://mcu.eetrend.com/files/2020-11/wen_zhang_/100059004-113290-33.png…; alt=""></center><br>

<font color="blue"><strong>2、systick配置注意事项</strong></font>

使用CubeMX配置生成的代码中,会自动生成一个 SystemClock_Config() 的函数,用于配置单片机时钟,其中就会配置systick

<pre style="overflow-x:auto; background-color:#e9e9e9;">void SystemClock_Config()
{
...........
LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
LL_SetSystemCoreClock(32000000);
#ifndef SYSTICK_IRQ
LL_Init1msTick(32000000); //使能systick但是不开启systick中断
#else
SysTick_Config(SystemCoreClock / 1000);//使能systick同时开启systick中断
#endif
}</pre>

但是这里 需要注意的是,是不是需要开启 systick 中断!!!!

1、如果只是想用systick来作为延时用,程序不想被中断打断,就只需要使能systick而不用开启systick中断,调用 LL_Init1msTick 即可

<pre style="overflow-x:auto; background-color:#e9e9e9;">void LL_Init1msTick(uint32_t HCLKFrequency)
---&gt; LL_InitTick(HCLKFrequency, 1000U);
---&gt; __STATIC_INLINE void LL_InitTick(uint32_t HCLKFrequency, uint32_t Ticks)
{
/* Configure the SysTick to have interrupt in 1ms time base */
SysTick-&gt;LOAD = (uint32_t)((HCLKFrequency / Ticks) - 1UL); /* set reload register */
SysTick-&gt;VAL = 0UL; /* Load the SysTick Counter Value */
SysTick-&gt;CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable the Systick Timer */
}</pre>

但是需要自己编写延时函数,不能使用HAL库提供的HAL_Delay()。原因如下:HAL_Delay的实现是依靠一个uwTickFreq变量,uwTickFreq是在HAL_IncTick中累加的,需要在 SysTick_Handler中断函数中周期调用,这样HAL_Delay才会有一个基准

<pre style="overflow-x:auto; background-color:#e9e9e9;">__weak void HAL_IncTick(void)
{
uwTick += uwTickFreq;
}
__weak uint32_t HAL_GetTick(void)
{
return uwTick;
}
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;

/* Add a period to guaranty minimum wait */
if (wait &lt; HAL_MAX_DELAY)
{
wait += (uint32_t)(uwTickFreq);
}

while((HAL_GetTick() - tickstart) &lt; wait)
{
}
}</pre>

自定义的us延时

<pre style="overflow-x:auto; background-color:#e9e9e9;">void my_delay_us(uint32_t nus)
{
uint32_t temp;
uint32_t fac_us = SystemCoreClock/1000000; //为系统时钟的1/1000000
SysTick-&gt;LOAD = nus*fac_us; //时间加载
SysTick-&gt;VAL = 0x00; //清空计数器
SysTick-&gt;CTRL |= SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp = SysTick->CTRL;
}
while((temp & 0x01) &&! (temp&(1 &lt;&lt; 16))); //等待时间到达
SysTick-&gt;CTRL &= ~ SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick-&gt;VAL = 0X00; //清空计数器
}</pre>

2、如果想用systick座系统的时钟节拍,需要开启systick中断,可以直接调用 SysTick_Config 来配置,也可以使用 HAL_Init 来配置,HAL_Init 配置最终也会调用 SysTick_Config 函数

<pre style="overflow-x:auto; background-color:#e9e9e9;"> HAL_Init(void)
---&gt; HAL_InitTick(uint32_t TickPriority)
---&gt; SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) &gt; SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}

SysTick-&gt;LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL &lt;&lt; __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick-&gt;VAL = 0UL; /* Load the SysTick Counter Value */
SysTick-&gt;CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0UL); /* Function successful */
}</pre>

这样配置完成之后,还需要再systick的中断中调用 osSystickHandler 和 HAL_IncTick

<pre style="overflow-x:auto; background-color:#e9e9e9;">void SysTick_Handler(void)
{
osSystickHandler();//为OS提供系统时钟节拍
HAL_IncTick();//为HAL库提供时钟基准
}</pre>

版权声明:本文为CSDN博主 hurryddd 的原创文章,
遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/m0_37845735/article/details/108439464