好用的Systick
在core_cm3.h和core_cm4.h头文件里边都有Systick滴答定时器的配置函数。
/**
* @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 */
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 = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
该函数的功能是初始化滴答定时器的定时时间,还有使能本身的中断功能,其形式参数tick是自动重装载值。拿STM32F103c8t6举个例子,比如设置该单片机的系统时钟是48MHz(通俗的讲每秒钟时钟线能够波动48000000个脉冲,那么一个脉冲时间就是1/48000000),而入口参数ticks如果为48000的话,那么就是滴答定时器要运行48000个1/48000000秒后才会中断一次,就是中断周期1ms。
只要使用了上面的函数,就能使用滴答定时器来实现任务的调度切换,相比其他定时器,是不是很方便呢?!
讲究时间精确,中断服务函数尽量少程序。这里滴答定时器中断函数里只实现将一个变量加1操作
//uint32_t sysTickUptime=0;
void SysTick_Handler(void)
{
sysTickUptime++;
}
在做一些设计过程中,可能会遇到一些算法需要时间变量,这时可以写下面的函数获取程序运行的时间。
1.获取当前的工程(程序)运行时间
uint32_t GetSysTime_us(void)
{
uint32_t ms, cycle_cnt;//register
do {
ms = sysTickUptime;
cycle_cnt = SysTick->VAL;
} while (ms != sysTickUptime);
return (ms * 1000) + (usTicks * 1000 - cycle_cnt) / usTicks;
}
其中的usTicks可以在系统初始化的时候算出来,函数可以是:
static void cycleCounterInit(void)
{
RCC_ClocksTypeDef clocks;
RCC_GetClocksFreq(&clocks);
usTicks = clocks.SYSCLK_Frequency / 1000000;
}
比如Sysclk为48MHz,那么usTicks等于48,即1us。上面的函数GetSysTime_us无非就是ms加上不足ms的us,最后得到的就是us级别的时间。
解释(usTicks * 1000 - cycle_cnt) / usTicks:usTicks1000是滴答定时器的自动重装载值,usTick1000/usTick就是1ms。而滴答定时器是一个24位的递减计数器,所以要得到不足ms的us时间应该写成(usTicks * 1000 - cycle_cnt) / usTicks。
2.获取时间间隔(或是周期)
有些控制算法需要用到时间变量dt,比如数字滤波算法和PID算法,所以这里介绍下如何获取一个函数或者一段程序的执行周期dt,函数如下:
float Get_DeltaT(uint32_t currentT)
{
static uint32_t previousT;
volatile float deltaT;
deltaT= (currentT - previousT) * 1e-6;
previousT = currentT;
return deltaT;
}
//调用方式:dt = Get_DeltaT(GetSysTime_us());