目录
前言:
思考:
代码实现:
delay.c:
delay.h:
前言:
最近需要用STM32G4系列的单片机做个项目,因为之前一直用的标准库,也是第一次用G4的芯片,所以打算先从简单的做起,比如说把温湿度显示到OLED屏上。那么现在问题来了,DHT11需要us级的延时,hal库自带的是ms级延时,需要自己写us级延时函数。
思考:
我想到了两种方法:一种是使用STM32G431上的定时器来产生精确的us级延时;另一种是使用SysTick定时器。这里我选用了第二种,SysTick定时器是一个内置于Cortex-M内核中的定时器,可以节省通用和基本定时器资源。
delay函数涉及到单片机本身的systick,而F1和G4主频不同,F1最高72MHZ,G4最高170MHZ
这里直接使用了正点原子F103的HAL库版本的delay函数,STM32F1系列是采用ARM-CortexM3的架构,G4是ARM-CortexM4的架构,Cortex-M4(继承了Cortex-M3内核的特性)比Cortex-M3多了 数字信号处理(DSP);单精度浮点运算。所以可以直接使用。
代码实现:
delay.c:
#include "delay.h"static uint32_t g_fac_us = 0; /* us延时倍乘数 *//*** @brief 初始化延迟函数* @param sysclk: 系统时钟频率, 即CPU频率(rcc_c_ck), 72MHz* @retval 无*/ void delay_init(uint16_t sysclk)
{g_fac_us = sysclk; /* 由于在HAL_Init中已对systick做了配置,所以这里无需重新配置 */}/*** @brief 延时nus* @note 无论是否使用OS, 都是用时钟摘取法来做us延时* @param nus: 要延时的us数* @note nus取值范围: 0 ~ (2^32 / fac_us) (fac_us一般等于系统主频, 自行套入计算)* @retval 无*/void delay_us(uint32_t nus)
{uint32_t ticks;uint32_t told, tnow, tcnt = 0;uint32_t reload = SysTick->LOAD; /* LOAD的值 */ticks = nus * g_fac_us; /* 需要的节拍数 */told = SysTick->VAL; /* 刚进入时的计数器值 */while (1){tnow = SysTick->VAL;if (tnow != told){if (tnow < told){tcnt += told - tnow; /* 这里注意一下SYSTICK是一个递减的计数器就可以了 */}else{tcnt += reload - tnow + told;}told = tnow;if (tcnt >= ticks) {break; /* 时间超过/等于要延迟的时间,则退出 */}}}}/*** @brief 延时nms* @param nms: 要延时的ms数 (0< nms <= (2^32 / fac_us / 1000))(fac_us一般等于系统主频, 自行套入计算)* @retval 无*/
void delay_ms(uint16_t nms)
{delay_us((uint32_t)(nms * 1000)); /* 普通方式延时 */}/*** @brief HAL库内部函数用到的延时* @note HAL库的延时默认用Systick,如果我们没有开Systick的中断会导致调用这个延时后无法退出* @param Delay : 要延时的毫秒数* @retval None*/
void HAL_Delay(uint32_t Delay)
{delay_ms(Delay);
}
delay.h:
#ifndef __DELAY_H
#define __DELAY_H #include "stm32g4xx_hal.h"void delay_init(uint16_t sysclk); /* 初始化延迟函数 */
void delay_ms(uint16_t nms); /* 延时nms */
void delay_us(uint32_t nus); /* 延时nus */#endif