系统滴答定时器概述(SysTick)
系统滴答定时器在M4内核里
他提供给单片机一个时间轴,捆绑在内核中,给操作系统提供一个时间片。
其它片上外设–定时器概述(TIM1-14)
定时器:
系统滴答定时器:定时/计时 系统级 给单片机提供一个时间轴 提供操作系统的时间片
所有的ST的单片机都有系统滴答定时器 捆绑与核心 在内核中
基本定时器:定时/计时 触发D/A转换
一般标号为TIM6/7—基本定时器
通用定时器:包含了基本定时器的所有功能 除此之外还有: 比较输出 、捕获输入功能
比较输出:调节输出高低电平的时长(PWM)例如: 呼吸灯 电机转速 舵机 红外发送……
捕获输入:捕获外来高低电平的时长 例如: 红外接收 小车接收端 超声波测速 超声波测距……
除了TIM1/6/7/8剩下全部为通用定时器
高级定时器:包含了通用定时器的所有功能 除此之外还有死区操作 刹车功能…
TIM1/8----高级定时器
计数器:独立看门狗 RTC等等
定时器的计数方式
预分频寄存器、计数器寄存器、重装载值寄存器这三个一般称为时基单元
系统滴答定时器代码配置
找到关于系统滴答定时器的相关参数
1.psc预分频系数–系统滴答定时器不需要分频,STM32F407VG系列为168MHz。
2.CLK可选择系统时钟或外部参考时钟–
根据系统滴答控制与状态寄存器的第二位可知:
1—内核时钟 168MHz 最长延时时长T= ((2^24)/168)=99864.375us
根据数据手册系统时钟经过8分频后提供21MHz时钟给系统滴答定时器
0—外部参考时钟 21MHz 最长延时时长T= ((2^24)/168)*8=798915us
所以延时范围在99~798ms左右。
3.arr寄存器–重装载值(0- 16777215) 2的24次方-1
因为STM32F407系列系统滴答定时器是24位递减计数器
由权威指南9.5章节可知
SysTick定时器是一个简单的递减24位定时器,可以在处理器时钟频率或参考时钟频率(通常是片上时钟源)上运行。
系统滴答定时器需要配置的寄存器
其实,我们只需要操作控制寄存器,自动重装载寄存器写入重装载值,当前值寄存器为写清零即可。
滴答定时器的流程图
系统滴答定时器程序设计
代码流程:
1.选择时钟
2.配置重装载值
3.清空当前值寄存器
4.使能
5.判断等待标志位
禁止使能
1.首先让系统滴答定时器初始化
//系统滴答定时器初始化
u8 SysTick_Init(u32 delay_time)
{
if(SysTick_Config(delay_time))
{
return 0;//如果传参大于0xFFFFFF结束函数
}
}
//下面是在系统文件中,搜索SysTick_Config找到的系统滴答定时器配置函数
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); //这里可知,传参的延迟时间不得大于0XFFFFFF(16777215ms),否则程序结束 /* Reload value impossible */
}
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* 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 (0UL); /* Function successful */
}
配置相关寄存器
void systick_ms(u32 time)//实现毫秒延时
{
SysTick->CTRL &= ~(1<<2);//选择外部参考时钟
SysTick->LOAD = time*21000-1;//计时传参
SysTick->VAL = 0;//写清除
SysTick->CTRL |= (1<<0);//使能计数器
while(!(SysTick->CTRL & (1<<16)));//计数标志位来临
SysTick->CTRL &= ~(1<<0);//关闭计数器
}
//利用全局变量+时间片的思想,对系统滴答做精准延时
u32 time1[3] = {0,500,1000};//数组存放数据用作延迟
void SysTick_Handler(void)
{
time1[1]--;
time1[2]--;
}
如果不用时间片的思想就会一直卡CPU,代码如下:
//定义一个全局变量,让中断服务函数执行时做递减操作即可
void SysTick_Handler(void)
{
delay_time--;
}
u32 delay_time = 0;
void delay_mstime(u32 time)
{
delay_time = time;
while(delay_time);//CPU将一直死等这个值减到0
}
主函数验证是否能做到精准延迟
主函数内没有使用卡死CPU的方法,而是用到时间片的思想,可以让CPU同时处理多件事情,例如让LED1在1秒内翻转一次,LED2在2秒才翻转一次。大家各自执行不会互相干扰
#include "main.h"
int main()
{
led_config();
Usart2_Config(115200);
SysTick_Init(168000);//初始化1ms
while(1)
{
// delay_mstime(500);
// printf("115200\r\n");
if(time1[0]==time1[1])
{
printf("123\r\n");
time1[1] = 500;
LED1_TURN;
}
if(time1[0]==time1[2])
{
printf("456\r\n");
time1[2] = 1000;
LED2_TURN;
}
}
}
串口实现效果
123每0.5秒输出一次,456每1秒输出一次