STM32F407VG用系统中断函数设计微秒级别的滴答定时器

系统滴答定时器概述(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秒输出一次
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值