日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/9 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 无需另配定时器在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的基礎時鐘》

總結

以上是生活随笔為你收集整理的无需另配定时器在STM32 HAL下实现微秒级延时(兼容FreeRTOS)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。