本教程使用的是【立创·天空星开发板】
原理图和PCB全开源!!!感谢立创开发板开源!!!
我们为什么需要us级别的延时函数?
-
精确通信:
在一些通信协议中,时序要求非常严格,例如I2C、SPI、UART等。微秒级的延时能确保数据在正确的时间发送和接收,避免通信错误。 -
传感器接口:
与一些传感器通信时,可能需要在读写操作之间插入精确的延时。例如,DHT11温湿度传感器在数据传输过程中需要严格的时间间隔。 -
时间敏感的任务:
比如实时系统中,对某些事件的响应需要在非常短的时间内完成,微秒级的延时函数能帮助实现这种高响应速度。 -
模拟信号采样:
在采样模拟信号时,需要在精确的时间间隔内进行多次采样,微秒级延时函数可以确保每次采样的时间间隔一致。
总的来说,微秒级延时函数能够帮助实现对时间要求非常严格的功能,确保系统的稳定和可靠运行。
什么是阻塞延时函数?
简单的来说:阻塞延时函数是指在执行延时操作期间,单片机或处理器暂停执行其他任何任务,直到延时时间结束为止。在这段时间内,CPU被“阻塞”,不能进行其他处理或响应其他事件。
它具有以下的特点:
- CPU闲置:在阻塞延时期间,CPU处于闲置状态,不执行任何其他指令,只是在等待延时时间结束。
- 单任务执行:阻塞延时函数适用于简单的单任务系统,或者在特定的任务中需要精确控制时间的场合。
us延时函数模板
这个函数模板可以用在很多的开发板上面!!
void delay_us(uint32_t _us)
{
uint32_t ticks;
uint32_t told, tnow, tcnt = 0;
// 计算需要的时钟数 = 延迟微秒数 * 每微秒的时钟数
ticks = _us * (SystemCoreClock / 1000000);
// 获取当前的SysTick值
told = SysTick->VAL;
while (1)
{
// 重复刷新获取当前的SysTick值
tnow = SysTick->VAL;
if (tnow != told)
{
if (tnow < told)
tcnt += told - tnow;
else
tcnt += SysTick->LOAD - tnow + told;
told = tnow;
// 如果达到了需要的时钟数,就退出循环
if (tcnt >= ticks)
break;
}
}
}
整个函数有三个逻辑部分:
- 初始计算:
- 根据系统时钟频率和延时的微秒数,计算所需的时钟周期数(ticks)。
- 初始计数:
- 读取当前的SysTick计数器值,作为初始值(told)。
- 延时循环:
- 不断读取当前的SysTick计数器值(tnow)。
- 计算当前值与上次记录值之间的差值,累积到计数器(tcnt)中。
- 判断累积的时钟数是否达到所需的延时时钟数(ticks)。
- 如果达到或超过所需的延时,退出循环;否则继续循环。
关键代码解析
SystemCoreClock / 1000000
这一句是用来计算当前单片机频率下每微妙的时钟数。
SystemCoreClock也可以直接换成168000000也是可以的。因为主频为168MHz。
SysTick->VAL
取出SysTick当前计数器的值。
SysTick->LOAD
重装载寄存器,取出极限计数的值(用于比对)。