STM32CubeMX 配置STM32F407 实现HAL库延时微妙方案

本文介绍如何在STM32F407使用HAL库通过TIM7定时器实现微秒级延时。通过合理配置预分频系数和自动重载值,使定时器溢出频率达到1MHz,从而实现精确延时。测试结果显示,延时精度高,适用于需要精确控制时间的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

STM32F407 使用HAL库延时微妙实现方法(STM32CubeMX配置)

作者 : 李剀
出处 :

https://blog.youkuaiyun.com/Kevin_8_Lee/article/details/89243195

或者

https://www.cnblogs.com/kevin-nancy/p/10696681.html

欢迎转载,但也请保留上面这段声明。 谢谢! (以上两个链接均是我个人的博客,只是在不同的平台上面)

先说一下为什么写这篇博客。

不知道大家有没有遇到过这种情况,当你在移植别人的程序的时候,尤其是移植STM32的程序,从标准库移植到HAL库的时候,总是无奈延时微妙函数在HAL库中找不到,delay_us(u8 us); 很多次我都是用毫秒延时代替了, 但是,这样会使得程序的效率大大降低,所以通过参考别人的资料,通过定时器写了延时us函数,延时还是很准确的

1、我所使用的单片机型号及开发环境

在这里插入图片描述
**PS**: emmmmm… (这里并不是打广告,只是我个人使用的这个开发板,其他任何的开发板,只要主控芯片一样均可以)
在这里插入图片描述开发环境如图,我是用的Cube+IAR, Keil5也可以的,都一样。

2、使用Cube配置定时器TIM7

PS: 每个定时器都可以,但是最好使用最低级的定时器,TIM7和TIM8都只能定时,所以我这里用的TIM7

这里我新建一个工程演示

在这里插入图片描述
选择STM32F407zg芯片
在这里插入图片描述
RCC和SYS配置就不截图了,大家都会的
时钟树配置如下图
在这里插入图片描述
通过查看STM32F407的数据手册可以知道
TIM7的频率就是APB1的频率,84MHz

TIM7配置:预分频系数为84-1 (83)
自动重载值 1

(这里的自动重载(arr)一定要设置为1,不能为0,否则无法得到正确的结果)

则TIM7的溢出频率 = 84MHz / (83 + 1) = 1MHz(1us)

在这里插入图片描述

在IAR或者MDK编译器中写代码

在tim.c文件里面添加代码,一定要写在
/* USER CODE BEGIN 1 */

/* USER CODE END1 */
之间,否则下次在Cube中有所更改,再重新生成文件,不在规定区域的代码会消失

void delay_us(uint16_t us)
{
	uint16_t differ=0xffff-us-5; 

	
	HAL_TIM_Base_Start(&htim7);
	__HAL_TIM_SetCounter(&htim7,differ); 
	while(differ < 0xffff-5) 
	{ 
		differ = __HAL_TIM_GetCounter(&htim7); 
	} 
	HAL_TIM_Base_Stop(&htim7);
 
}

效果见下图,上面的代码我特别打出来,方便大家复制
在这里插入图片描述

不要忘了在tim.h中对函数进行声明

在这里插入图片描述

OK, 接下来进行测试并用示波器显示

我们在主函数里面写入测试代码,通过示波器观察波形及周期,看一下延时是否成功及精确。。

在这里插入图片描述
在主函数的while(1)循环中写入上图所示测试代码,理论结果是PF9引脚的输出电平每100微妙反转一次

示波器延时的波形如下图

在这里插入图片描述
这里我们可以看到,周期为200.8us, 即100.4us电平反转一次,还是很精准的

是梦别怕疼,想赢别喊停! 加油吧
<think>好的,用户现在想用STM32HAL实现微秒级的延时。之前他们问过关于W5500和SPI驱动的问题,现在转向了定时器相关的功能。首先,我需要确定用户的需求是什么。他们可能需要精确的微秒级延时,用于外设的时序控制,比如SPI通信中的等待时间,或者传感器读取时的精确时序。 接下来,我得考虑HAL本身提供的延时函数HAL_Delay()是基于SysTick的毫秒级延时,无法满足微秒需求。所以用户需要自己实现更细粒度的延时。常见的实现方法有几种:使用定时器、使用SysTick、或者使用NOP指令的空循环。但NOP的方法受编译器优化和CPU频率影响大,可能不准。所以更可靠的是定时器或SysTick。 用户可能已经知道这些方法,但需要具体的代码实现。我需要提供基于定时器和DWT的两种方法,因为这两种比较常见。使用定时器的话,需要配置一个基本定时器,比如TIM2,设置时钟为1MHz,这样每个计数就是1微秒。然后编写启动、延时、停止的函数。这种方法需要用户根据自己MCU的时钟配置调整定时器的预分频值。 另一种方法是使用DWT(Data Watchpoint and Trace)的Cycle Counter,这需要启用DWT模块,通过读取时钟周期数来实现精确延时。这种方法不需要占用定时器资源,但需要确认MCU支持DWT,并且时钟配置正确。比如,如果系统主频是72MHz,那么每微秒有72个周期,这样计算起来方便。 用户可能关心代码的可移植性和准确性,所以需要给出注意事项,比如时钟配置、中断的影响等。此外,他们可能在实际使用中遇到问题,比如延时不准,这时候需要提示检查系统时钟和定时器配置是否正确。 还要考虑到代码的兼容性,不同STM32型号可能有不同的定时器或DWT支持情况,所以需要用户根据具体情况调整。最后,示例代码需要简洁明了,直接给出关键部分,让用户能够快速集成到自己的项目中。</think>以下提供两种基于STM32 HAL的微秒级延时实现方案(推荐方案1): --- ### **方案1:定时器实现(高精度)** ```c // timer.h #define DELAY_TIM TIM2 #define DELAY_TIM_CLK_ENABLE() __HAL_RCC_TIM2_CLK_ENABLE() // 初始化函数(时钟配置为1MHz) void Delay_TIM_Init(void) { TIM_HandleTypeDef htim; htim.Instance = DELAY_TIM; htim.Init.Prescaler = HAL_RCC_GetPCLK1Freq()/(2*1000000) - 1; // 1MHz时钟 htim.Init.CounterMode = TIM_COUNTERMODE_UP; htim.Init.Period = 0xFFFF-1; htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&htim); HAL_TIM_Base_Start(&htim); } // 微秒延时函数 void delay_us(uint16_t us) { __HAL_TIM_SET_COUNTER(&htim, 0); while(__HAL_TIM_GET_COUNTER(&htim) < us); } ``` --- ### **方案2:DWT周期计数器实现(无需硬件定时器)** ```c // dwt.h #include "core_cm4.h" // 根据内核型号选择 void Delay_DWT_Init(void) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; } void delay_us(uint32_t us) { uint32_t cycles = SystemCoreClock / 1000000 * us; uint32_t start = DWT->CYCCNT; while((DWT->CYCCNT - start) < cycles); } ``` --- ### **使用示例** ```c int main(void) { HAL_Init(); SystemClock_Config(); // 选择其中一种初始化方式 Delay_TIM_Init(); // 或者 Delay_DWT_Init(); while(1) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); delay_us(500); // 500微秒延时 } } ``` --- ### **关键参数说明** | 参数 | 方案1要求 | 方案2要求 | |--------------|-------------------------|-------------------------| | 时钟精度 | 依赖定时器配置 | 依赖系统主频 | | 适用场景 | 需要严格时序控制 | 通用延时 | | 误差范围 | &plusmn;0.5us72MHz主频) | &plusmn;1us(无中断干扰) | | 资源占用 | 占用一个定时器 | 无需硬件资源 | --- ### **注意事项** 1. 方案1需根据实际APB时钟调整预分频值 2. 方案2要求: - 内核必须支持DWT(Cortex-M3/M4/M7) - 系统时钟需准确配置(通过`SystemCoreClock`变量反映) 3. 两种方案均需关闭全局中断才能保证最高精度 4. 对于100us以上延时,建议结合HAL_Delay()使用
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值