DWT模块在STM32中的延时函数应用教程

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的芯片型号,其中需要考虑下方几点来修改代码

  1. CPU时钟频率(CPU_CLOCK_FREQ):

    不同的STM32芯片可能有不同的核心时钟频率。你需要根据实际使用的芯片型号,调整CPU_CLOCK_FREQ的值以匹配该芯片的实际时钟频率。

  2. DWT寄存器地址:

    虽然大多数STM32芯片都有DWT模块,但是寄存器地址可能有所不同。你需要查阅新芯片的技术参考手册,确认DWT寄存器的地址,并相应地更新代码中的宏定义。

3.1 delay.c 完整代码

cpp 复制代码
#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 完整代码

cpp 复制代码
#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函数中初始化

cpp 复制代码
DWT_Init();    	//初始化DWT注意修改时钟

4.2 延时函数使用

引用头文件后直接使用,例如下方的dht11读取字节函数

cpp 复制代码
/**  
  * @简要  从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模块。

相关推荐
前进的李工3 小时前
Agent 学习笔记 05:系统提示词应该怎么写
笔记·学习·prompt·agent·个人开发·few-shot·ai应用开发
LCG米3 小时前
STM32硬件CRC外设实测:多项式固定陷阱、CRC-32校验不匹配根因与软件查表法耗时对比落地
stm32·单片机·嵌入式硬件
正在走向自律4 小时前
【3/5】人工智能训练师 三级/高级工 考证学习方向:从“独立执行”到“设计、归因与全链条负责”
人工智能·学习·人工智能训练师·注方案设计·数据质控负责人·模型评测与调优辅助·ai训练项目交付
CCIE-Yasuo6 小时前
网络安全-学习数据库-Mysql-2
数据库·学习·mysql
La Pulga6 小时前
【FreeRTOS源码学习笔记】任务切换
单片机·mcu·学习·嵌入式·freertos·实时操作系统
li星野7 小时前
【学习记录】逻辑分析仪完全入门:从品牌方案到采样率、存储深度的核心概念解析
学习
旖旎夜光7 小时前
【C++ 基础入门】类和对象(上):封装、对象模型与 this 指针
开发语言·c++·笔记·学习
WEI_YANG_JU8 小时前
初中数学教学中合作学习的研究与实践
学习
码农小韩8 小时前
FPGA学习(一)——LED点灯与开发流程
学习·fpga开发·入门·环境配置·仿真·点灯
李长渊哦9 小时前
Qoder 自定义子智能体(Subagent)学习笔记
chrome·笔记·学习