1.DWT简介
在STM32微控制器中,DWT(Data Watchpoint and Trace)模块是一个功能强大的调试工具,它提供了精确的时间测量功能。DWT模块中的CYCCNT(Cycle Count)寄存器可以计数处理器的时钟周期,从而允许我们进行非常精确的时间测量和延时操作。这对于需要微秒级或更高精度延时的应用非常有用,尤其是在定时器资源紧张的情况下。
DWT模块的优势在于它几乎不占用任何额外资源,并且每个STM32芯片都内置了这个模块。
2.一般使用用途
2.1 平衡车项目
在我的平衡小车项目中,使用的是STM32F103C8T6芯片。由于FreeRTOS使用了一个定时器作为时钟源,另外两个定时器用于左右点击的编码器输入和使用最后一个定时器去PWM方波生成,导致没有多余的定时器用于超声波模块的时间差计算。这个时候我使用DWT来计算超声波模块发送和接收之间的时间差。
2.2 延时函数
由于DWT模块中的CYCCNT(Cycle Count)寄存器可以计数处理器的时钟周期,从而允许我们进行非常精确的时间测量和延时操作。
所以我们可以使用这个功能来做一个us级别的延时函数,可以适用于各种传感器需要us级别延时的地方,例如dht11等其他的传感器
3.代码实现
注:DWT只适用于STM32的芯片型号,其中需要考虑下方几点来修改代码
-
CPU时钟频率(
不同的STM32芯片可能有不同的核心时钟频率。你需要根据实际使用的芯片型号,调整CPU_CLOCK_FREQ
):CPU_CLOCK_FREQ
的值以匹配该芯片的实际时钟频率。 -
DWT寄存器地址:
虽然大多数STM32芯片都有DWT模块,但是寄存器地址可能有所不同。你需要查阅新芯片的技术参考手册,确认DWT寄存器的地址,并相应地更新代码中的宏定义。
3.1 delay.c 完整代码
#include "delay.h"// 定义CPU时钟频率,用于将时间转换为周期数
#define CPU_CLOCK_FREQ 72000000UL // 定义与数据观察与跟踪(DWT)模块相关的寄存器地址和位掩码
#define DEM_CR *((volatile uint32_t *)0xE000EDFC)
#define DWT_CR *((volatile uint32_t *)0xE0001000)
#define DWT_CYCCNT *((volatile uint32_t *)0xE0001004)
#define DEM_CR_TRCENA 0x01000000
#define DWT_CR_CYCCNTENA 0x00000001 // 初始化DWT(数据观察与跟踪)模块的函数
void DWT_Init(void)
{ DEM_CR |= DEM_CR_TRCENA; // 启用数据观察与跟踪模块的控制寄存器中的跟踪使能位 DWT_CYCCNT = 0; // 将周期计数器清零 DWT_CR |= DWT_CR_CYCCNTENA; // 启用周期计数器
} // 延迟指定微秒数的函数
void delay_us(uint32_t time)
{ uint32_t cycles = (time * (CPU_CLOCK_FREQ / 1000000UL)); // 根据CPU时钟频率将微秒转换为周期数 uint32_t start_count = DWT->CYCCNT; // 读取周期计数器的起始值 uint32_t target_count = start_count + cycles; // 计算目标周期数(起始值加上需要延迟的周期数) while(DWT_CYCCNT < target_count); // 等待直到周期计数器的值达到目标值
} // 延迟指定毫秒数的函数
void delay_ms(uint32_t time)
{ time *= 1000; // 将毫秒转换为微秒 delay_us(time); // 调用delay_us函数来实现毫秒级的延迟
} // 延迟指定秒数的函数
void delay_s(uint32_t time)
{ time *= 1000; // 将秒转换为毫秒 delay_ms(time); // 调用delay_ms函数来实现秒级的延迟
}
3.2 delay.h 完整代码
#ifndef __DELAY_H_
#define __DELAY_H_#include "main.h"void DWT_Init(void);
void delay_us(uint32_t us);
void delay_ms(uint32_t ms);
void delay_s(uint32_t s);#endif
4. 使用示例
4.1 初始化
引用头文件后在main函数中初始化
DWT_Init(); //初始化DWT注意修改时钟
4.2 延时函数使用
引用头文件后直接使用,例如下方的dht11读取字节函数
/** * @简要 从DHT11读取一个字节的数据 * @返回值 读取到的字节数据 */
uint8_t DHT11_Read_Byte(void)
{ uint8_t Byte = 0x00; uint8_t i = 0; for(i=0;i<8;i++) { while(DHT11_Read_Pin() == 0); delay_us(40); if(DHT11_Read_Pin() == 1) Byte |= (0x80 >> i); while(DHT11_Read_Pin() == 1); } return Byte;
}
5.结尾
通过使用DWT模块,我们可以在STM32项目中实现精确的延时功能,而不需要额外的定时器资源。这对于资源受限的项目来说是一个非常有用的解决方案。希望这个教程能帮助各位在项目中有效地使用DWT模块。