freertos开发空气检测仪之延迟函数设计:DWT软件实现
本篇带来空气检测仪项目之延迟函数设计
在项目中,一般都需要设计一些delay函数,比较常用,本篇设计带来DWT的软件实现。
一、引言
在空气检测仪项目的开发过程中,延迟函数是一项非常基础且重要的功能。无论是传感器数据的采集间隔控制,还是与外部设备通信时的时序要求,都离不开精确的延迟操作。在众多实现延迟函数的方法中,使用 DWT(Data Watchpoint and Trace)进行软件延迟是一种高效且精确的方式。本文将详细介绍在空气检测仪项目中如何使用 DWT 来实现延迟函数。
二、DWT 简介
2.1 什么是 DWT
DWT 是 ARM Cortex - M 系列处理器中一个非常有用的调试组件,它主要用于数据观察点和跟踪功能。不过,我们也可以利用 DWT 中的 CYCCNT(Cycle Counter)寄存器来实现高精度的延迟功能。CYCCNT 寄存器是一个 32 位的计数器,它会在处理器每执行一个时钟周期就自动加 1。
2.2 DWT 实现延迟的优势
- 高精度:由于 CYCCNT 寄存器是根据处理器的时钟周期进行计数的,因此可以实现非常精确的延迟。
- 灵活性:可以根据需要实现不同时长的延迟,只需要调整计数器的初始值和比较值即可。
- 占用资源少:相比于一些硬件定时器的实现方式,DWT 实现延迟不需要额外的硬件资源。
三、具体代码
core_delay.h文件
c
#ifndef __CORE_DELAY_H
#define __CORE_DELAY_H
#include "gd32f30x.h"
void dwt_init(void);
void dwt_delay_us(uint32_t us);
void dwt_delay_ms(uint32_t ms);
void dwt_delay_us_accurate(uint32_t us);
uint32_t dwt_ns_tick_get(void);
#endif /* __CORE_DELAY_H */
core_delay.c文件
c
#include "core_delay.h"
/**
* @brief 微秒级延时函数
* @param us: 要延时的微秒数
* @note 此函数基于循环计数实现延时,精度取决于系统时钟稳定性
* 使用前请确保SystemCoreClock变量已正确初始化 感觉延迟不够好用
*/
void dwt_delay_us_accurate(uint32_t us)
{
// 根据实际测试结果调整系数(例如除以10)
uint32_t wait_loop_index = us * (SystemCoreClock / 1000000U) / 10;
// 使用volatile防止编译器优化
volatile uint32_t *p = &wait_loop_index;
while(*p != 0U)
{
(*p)--;
}
}
// 初始化DWT计数器(在系统初始化时调用一次)
void dwt_init(void)
{
if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk))
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
}
// 精确的微秒级延时
void dwt_delay_us(uint32_t us)
{
uint32_t start = DWT->CYCCNT;
uint32_t cycles = us * (SystemCoreClock / 1000000U);
while ((DWT->CYCCNT - start) < cycles);
}
// ms级别延时
void dwt_delay_ms(uint32_t ms)
{
dwt_delay_us(ms * 1000);
}
// ns级别延时获得
uint32_t dwt_ns_tick_get(void)
{
return ((uint32_t)((DWT->CYCCNT)/ 120) * 1000);
}
四、DWT测试代码
c
/* 初始化DWT计数器 */
dwt_init();
uint32_t start_tick = dwt_ns_tick_get();
// 测试dwt延迟
PLEDDevice ptLEDDevice;
ptLEDDevice = GetLEDDevice(LED_ID_WHITE);
if (ptLEDDevice != NULL)
{
ptLEDDevice->Init(ptLEDDevice);
ptLEDDevice->Control(ptLEDDevice, 1);
dwt_delay_ms(100);
ptLEDDevice->Control(ptLEDDevice, 0);
dwt_delay_ms(100);
}
uint32_t end_tick = dwt_ns_tick_get();
DBG_log("LED device control test time: %d ns\n", end_tick - start_tick);
五、实验现象

成功测试使用,可以看到执行了两个dwt_delay_ms(100),得到的时间也是比较可观。
六、注意事项
6.1 系统时钟频率的影响
DWT 延迟函数的精度依赖于系统时钟频率的准确性。如果系统时钟频率发生变化,延迟时间也会相应地改变。因此,在使用 DWT 延迟函数时,需要确保系统时钟频率的稳定性。
6.2 计数器溢出问题
由于 CYCCNT 是一个 32 位的计数器,当计数器值达到最大值(2^32 -1)时会发生溢出。在实现延迟函数时,需要注意避免因计数器溢出而导致延迟时间不准确的问题。一般来说,在短时间延迟的情况下,这个问题不会出现,但在长时间延迟时需要特别注意。
七、总结
通过使用 DWT 实现延迟函数,我们可以在空气检测仪项目中获得高精度、灵活且占用资源少的延迟功能。在实际应用中,同时,需要注意系统时钟频率和计数器溢出等问题,以保证延迟函数的可靠性。希望本文能给大家对延迟函数设计有所帮助。
完!!