目录
前言:
最近需要用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