无需另配定时器在STM32 HAL下实现微秒级延时(兼容FreeRTOS)


目录

  • 前言
  • 一、代码部分
  • 二、使用和验证
    • 1.引入头文件
    • 2.初始化
    • 3.使用和验证
  • 三、可移植性
  • 总结


前言

接触HAL库差不多两年了,一直苦于HAL库没有自带微秒级的延时,网上的前辈们给出的解决方案要么是改写HAL_Delay的延时时间,要么就是额外占用一个定时器来实现,不太方便移植,以下是我给出的解决方案。

软件平台:STM32 Cube IDE 1.5.0

一、代码部分

Delay.c 代码如下

#include "main.h"#define USE_HAL_LEGACY
#include "stm32_hal_legacy.h"#define Timebase_Source_is_SysTick 1	//当Timebase Source为SysTick时改为1
//#define Timebase_Source_is_SysTick 0	//当使用FreeRTOS,Timebase Source为其他定时器时改为0#if	(!Timebase_Source_is_SysTick)extern TIM_HandleTypeDef htimx;		//当使用FreeRTOS,Timebase Source为其他定时器时,修改为对应的定时器#define Timebase_htim htimx#define Delay_GetCounter()		__HAL_TIM_GetCounter(&Timebase_htim)#define Delay_GetAutoreload()	__HAL_TIM_GetAutoreload(&Timebase_htim)
#else#define Delay_GetCounter()		(SysTick->VAL)#define Delay_GetAutoreload()	(SysTick->LOAD)
#endifstatic uint16_t fac_us = 0;
static uint32_t fac_ms = 0;/*初始化*/
void delay_init(void)
{
#if	(!Timebase_Source_is_SysTick)fac_ms = 1000000;				//作为时基的计数器时钟频率在HAL_InitTick()中被设为了1MHzfac_us = fac_ms / 1000;
#elsefac_ms = SystemCoreClock / 1000;fac_us = fac_ms / 1000;
#endif
}/*微秒级延时*/
void delay_us(uint32_t nus)
{uint32_t ticks = 0;uint32_t told = 0;uint32_t tnow = 0;uint32_t tcnt = 0;uint32_t reload = 0;reload = Delay_GetAutoreload();ticks = nus * fac_us;told = Delay_GetCounter();while (1){tnow = Delay_GetCounter();if (tnow != told){if (tnow < told){tcnt += told - tnow;}else{tcnt += reload - tnow + told;}told = tnow;if (tcnt >= ticks){break;}}}
}/*毫秒级延时*/
void delay_ms(uint32_t nms)
{uint32_t ticks = 0;uint32_t told = 0;uint32_t tnow = 0;uint32_t tcnt = 0;uint32_t reload = 0;reload = Delay_GetAutoreload();ticks = nms * fac_ms;told = Delay_GetCounter();while (1){tnow = Delay_GetCounter();if (tnow != told){if (tnow < told){tcnt += told - tnow;}else{tcnt += reload - tnow + told;}told = tnow;if (tcnt >= ticks){break;}}}
}/*重写HAL_Delay*/
void HAL_Delay(uint32_t Delay)
{uint32_t tickstart = HAL_GetTick();uint32_t wait = Delay;/*不太明白官方源码为啥这么写,会多延时1ms,注释掉后更准*/
//  /* Add a freq to guarantee minimum wait */
//  if (wait < HAL_MAX_DELAY)
//  {
//    wait += (uint32_t)(uwTickFreq);
//  }while ((HAL_GetTick() - tickstart) < wait){}
}

Delay.h 代码如下

#ifndef DELAY_H
#define DELAY_H#include "main.h"extern void delay_init(void);
extern void delay_us(uint32_t nus);
extern void delay_ms(uint32_t nms);#endif

二、使用和验证

1.引入头文件

代码如下(示例):

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "../Delay/Delay.h"		//引入头文件
/* USER CODE END Includes *///...

2.初始化

代码如下(示例):

  //.../* Initialize all configured peripherals */MX_GPIO_Init();/* USER CODE BEGIN 2 */delay_init();		//初始化/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE *///...

3.使用和验证

(示例)
所用开发板为 野火指南者 STM32F103VET6 开发板。
工程优化等级为默认的None,所测输出引脚为PC13和PC4

先测试什么也不做时输出的脉冲周期(此时系统时钟为72M)

  //.../* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */GPIOC->BSRR = GPIO_PIN_13;					//PC13为高GPIOC->BSRR = (uint32_t)GPIO_PIN_13 << 16u;	//PC13为低}/* USER CODE END 3 *///...

测得此时的脉冲周期
在这里插入图片描述
延时500us时

  //.../* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */GPIOC->BSRR = GPIO_PIN_13;					//PC13为高delay_us(500);GPIOC->BSRR = (uint32_t)GPIO_PIN_13 << 16u;	//PC13为低}/* USER CODE END 3 *///...

在这里插入图片描述
延时50us时

  //.../* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */GPIOC->BSRR = GPIO_PIN_13;					//PC13为高delay_us(50);GPIOC->BSRR = (uint32_t)GPIO_PIN_13 << 16u;	//PC13为低}/* USER CODE END 3 *///...

在这里插入图片描述
延时10us时

  //.../* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */GPIOC->BSRR = GPIO_PIN_13;					//PC13为高delay_us(10);GPIOC->BSRR = (uint32_t)GPIO_PIN_13 << 16u;	//PC13为低}/* USER CODE END 3 *///...

在这里插入图片描述
加入FreeRTOS
在这里插入图片描述
Cube建议我们更改时基源
在这里插入图片描述
更改Timebase Source为其他定时器
在这里插入图片描述
更新工程后修改Delay.c文件

#include "main.h"#define USE_HAL_LEGACY
#include "stm32_hal_legacy.h"//#define Timebase_Source_is_SysTick 1	//当Timebase Source为SysTick时改为1
#define Timebase_Source_is_SysTick 0	//当使用FreeRTOS,Timebase Source为其他定时器时改为0#if	(!Timebase_Source_is_SysTick)extern TIM_HandleTypeDef htim7;		//当使用FreeRTOS,Timebase Source为其他定时器时,修改为对应的定时器#define Timebase_htim htim7#define Delay_GetCounter()		__HAL_TIM_GetCounter(&Timebase_htim)#define Delay_GetAutoreload()	__HAL_TIM_GetAutoreload(&Timebase_htim)
#else#define Delay_GetCounter()		(SysTick->VAL)#define Delay_GetAutoreload()	(SysTick->LOAD)
#endif//...

修改测试任务

//...
/* USER CODE BEGIN Header_StartDefaultTask */
/*** @brief  Function implementing the defaultTask thread.* @param  argument: Not used* @retval None*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{/* USER CODE BEGIN 5 *//* Infinite loop */for(;;){GPIOC->BSRR = GPIO_PIN_13;delay_us(50);								//PC13高电平时间为50usGPIOC->BSRR = (uint32_t)GPIO_PIN_13 << 16u;}/* USER CODE END 5 */
}/* USER CODE BEGIN Header_StartTask02 */
/**
* @brief Function implementing the myTask02 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask02 */
void StartTask02(void *argument)
{/* USER CODE BEGIN StartTask02 *//* Infinite loop */for(;;){GPIOC->BSRR = GPIO_PIN_4;osDelay(1);									//PC4高电平时间为1msGPIOC->BSRR = (uint32_t)GPIO_PIN_4 << 16u;}/* USER CODE END StartTask02 */
}
//...

如图所示微秒级延时仍然工作正常
在这里插入图片描述
在这里插入图片描述

三、可移植性

//...
/*初始化*/
void delay_init(void)
{
#if	(!Timebase_Source_is_SysTick)fac_ms = 1000000;				//作为时基的计数器时钟频率在HAL_InitTick()中被设为了1MHzfac_us = fac_ms / 1000;
#elsefac_ms = SystemCoreClock / 1000;fac_us = fac_ms / 1000;
#endif
}
//...

使用滴答定时器作为时基时自然不用多说,当使用其他定时器作为时基时(如本文的例子),Src目录下会自动生成一个stm32f1xx_hal_timebase_tim.c文件,其中的HAL_InitTick函数重构了在stm32f1xx_hal.c中的、__weak修饰的同名函数,它设置了所选定时器的时钟频率为1MHz:

//.../* Compute TIM7 clock */uwTimclock = 2*HAL_RCC_GetPCLK1Freq();/* Compute the prescaler value to have TIM7 counter clock equal to 1MHz */uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000U) - 1U);
//...

因此本方案在绝大多数由cube生成工程的情况下应该是通用的。


总结

经过实验,我们发现本方案实现了精度还算可以接受的微秒级延时,不过本方案的延时方式和HAL_Delay差不多,不建议在任务中过多地调用。

不同时基下的初始化过程建议参阅HongAndYi大佬写的
《HAL和FreeRTOS的基础时钟》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/400882.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

×××S 2012 交互式报表 -- 同步交互式排序

S 2012 交互式报表 -- 同步交互式排序步骤1&#xff1a;首先&#xff0c;在刚才的“交互式排序”示例报表中再拖拉一个“Chart”&#xff0c;设置为长条图&#xff0c;从报表数据窗口中将销售金额、销售数量拖至“Values”&#xff0c;将产品大类拖放至“Category Groups”区域…

SpringCloud GateWay 万字详解

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

STM32 HAL 硬件IIC+DMA+简单图形库控制OLED

目录前言一、建立工程二、编写和移植前期准备驱动部分修改三、使用和验证结论&#xff08;2022年1月22日重制&#xff09;本文主要是移植带简单图形库的程序&#xff0c;如果只是实现DMA控制&#xff0c;建议看【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动…

python创建分类器小结

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

SPOJ 1676 矩阵乘法+DP

题意&#xff1a; 给定N (1 ≤ N ≤ 10)个长度不超过6的单词,求由大写字母组成长度为L的包含至少一个给定单词的字符串有多少种,答案 mod 10007,(1 ≤ L ≤ 10^6)。 题解&#xff1a; 这个题最早是在一个关于trie图的论文中看到了&#xff0c;最近jzh又讲到了这个题&#xff0c…

go-zero微服务实战系列(三、API定义和表结构设计)

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

STM32 串口DMA接收 Openmv / K210 整数、小数字符串数据 (基于HAL库)

目录前言一、工程配置二、串口DMA部分代码1.源文件UART_DMA.c2.头文件UART_DMA.h3.stm32f1xx_it.c的修改4.串口收发DMA测试三、字符串数字提取代码1.源文件NumAndStr.c:2.头文件NumAndStr.h:3.测试:四、Openmv / K210 发送、STM32接收测试总结修订版本UART_DMA.cUART_DMA.h平台…

6000字|22张图 带你彻底弄懂Zookeeper分布式锁

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

【HDU2896】病毒侵袭——ac自动机

网上很多代码都略显繁琐&#xff0c;看了一下yy dalao的代码感觉很好&#xff0c;但他懒得打题解&#xff08;好吧我也是 以0为根节点的话&#xff0c;我把yy的一段代码删了改用fail[c]x0?0:ch[fail[x]][i];来实现特判&#xff0c;效果还不错&#xff01;也算是AC自动机的模版…

经典 HTML5 Javascript 俄罗斯方块游戏

Blockrain.js 是一个使用 HTML5 & JavaScript 开发的经典俄罗斯方块游戏。只需要复制和粘贴一段代码就可以玩起来了。最重要的是&#xff0c;它是响应式的&#xff0c;无论你的显示屏多么宽都能自动匹配。你可以自定义你想要的颜色以适应您的网站&#xff0c;也可以调整方块…

【电赛PID半天入门】从接触编码器到调出好康的PID波形

从接触编码器到调出好康的PID波形认识电机及编码器只需动动手指&#xff0c;就能让STM32得到电机转过的角度让电机转起来认识PID控制①比例调节器②积分调节③微分调节④比例积分微分调节数字PID调节器&#xff08;1&#xff09;数字PID位置型控制算法&#xff08;2&#xff09…

算法的复杂度分析

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

PHP面向对象 封装与继承

知识点&#xff1a; PHP封装三个关键词&#xff1a; 一、public 公有的&#xff0c;被public修饰的属性和方法&#xff0c;对象可以任意访问和调用 二、private 私有的&#xff0c;被private修饰的属性和方法&#xff0c;只能在类内部的方法可以进行调用&#xff0c;或者被子类…

POJ 1380 坐标旋转

题意&#xff1a; 问第二个矩形能不能放进第一个矩形中。 题解&#xff1a; 暴力旋转第二个矩形&#xff0c;判断左右、上下是否同时小于第一个矩形 当然&#xff0c;数学推导也可以&#xff0c;挺简单的相似神马的胡搞就行~ View Code 1 #include <iostream>2 #include…

MSP430F5529 DriverLib 库函数学习笔记(一)时钟配置和闪烁LED

目录一、新建工程二、时钟树时钟系统结构时钟系统的原理时钟树配置实战三、点灯工程师封装好的初始化函数平台&#xff1a;Code Composer Studio 10.3.1 MSP430F5529 LaunchPad™ Development Kit (MSP‑EXP430F5529LP) 一、新建工程 二、时钟树 时钟系统结构 &#xff08;1&…

libcurl上传文件

libcurl参数很多&#xff0c;一不小心就容易遇到问题。曾经就遇到过一个很蛋疼的问题&#xff1a;libcurl断点下载>> 这里主要汇总一下&#xff0c;libcurl上传的二种方式&#xff1a; 1、直接上传文件&#xff0c;类似form表单<input type”file” />&#xff0c;…

MSP430F5529 DriverLib 库函数学习笔记(二)GPIO

目录硬知识一、MSP430单片机端口概述二、通用IO端口输出特性三、端口P1和P21&#xff0e;输入寄存器PxIN2&#xff0e;输出寄存器PxOUT3&#xff0e;方向寄存器PxDIR4&#xff0e;上拉/下拉电阻使能寄存器PxREN5&#xff0e;输出驱动能力调节寄存器PxDS6&#xff0e;功能选择寄…

MSP430F5529 DriverLib 库函数学习笔记(三)认识中断

目录一、硬知识中断的基本概念MSP430单片机中断源中断响应过程中断返回过程中断嵌套二、msp430f5529.h中所列的中断向量宏定义平台&#xff1a;Code Composer Studio 10.3.1 MSP430F5529 LaunchPad™ Development Kit (MSP‑EXP430F5529LP) 一、硬知识 中断的基本概念 中断…

推荐系统相关算法

摘要&#xff1a; 热门推荐 协同过滤算法 矩阵分解 基于内容的推荐&#xff08;文本&#xff0c;标签&#xff0c;特征/profile&#xff09; 基于图的算法 内容&#xff1a; 热门推荐&#xff1a; 热门推荐本质上是一个排行榜&#xff0c;可能会考虑到时间衰减&#xff0c;商品…

冒泡排序的简单理解

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…