stm32 主频216MHz,写个ms延时函数,us延时函数

在 STM32 微控制器中,实现精确的 ms(毫秒)和 us(微秒)延时函数通常依赖于系统时钟(SysTick)或定时器。以下是基于主频为 216 MHz 的实现方法:

1. 使用 SysTick 实现延时函数

SysTick 是 Cortex-M 内核提供的一个 24 位倒计时定时器,通常用于操作系统的任务调度或提供精确的延时。

(1) 配置 SysTick

在 HAL_Init() 中,SysTick 已经被初始化为 1ms 中断。我们可以利用 SysTick 的计数器来实现延时。

(2) 实现 ms 延时函数

c 复制代码
#include "stm32f4xx_hal.h"  // 包含 HAL 库头文件

void Delay_ms(uint32_t ms)
{
    uint32_t start_tick = HAL_GetTick();  // 获取当前 SysTick 值
    while ((HAL_GetTick() - start_tick) < ms)
    {
        // 等待
    }
}

(3) 实现 us 延时函数

由于 SysTick 的分辨率是 1ms,无法直接用于微秒级延时。可以通过循环空操作来实现微秒级延时。

c 复制代码
void Delay_us(uint32_t us)
{
    uint32_t delay_cycles = us * (SystemCoreClock / 1000000);  // 计算需要的 CPU 周期数
    volatile uint32_t count = 0;
    for (count = 0; count < delay_cycles; count++)
    {
        __asm__("nop");  // 空操作,占用一个 CPU 周期
    }
}

2. 使用定时器实现延时函数

如果需要更高精度的延时(尤其是微秒级延时),可以使用硬件定时器(如 TIM2、TIM3 等)。

(1) 配置定时器

假设使用 TIM2 定时器,配置为主频 216 MHz 下的 1us 分辨率。

c 复制代码
#include "stm32f4xx_hal.h"

void TIM2_Init(void)
{
    __HAL_RCC_TIM2_CLK_ENABLE();  // 使能 TIM2 时钟

    TIM_HandleTypeDef htim2;
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = (SystemCoreClock / 1000000) - 1;  // 分频为 1MHz(1us)
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 0xFFFFFFFF;  // 最大计数值
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_Base_Init(&htim2);

    HAL_TIM_Base_Start(&htim2);  // 启动定时器
}

(2) 实现 us 延时函数

c 复制代码
void Delay_us(uint32_t us)
{
    uint32_t start_tick = __HAL_TIM_GET_COUNTER(&htim2);  // 获取当前定时器值
    while ((__HAL_TIM_GET_COUNTER(&htim2) - start_tick) < us)
    {
        // 等待
    }
}

(3) 实现 ms 延时函数

c 复制代码
void Delay_ms(uint32_t ms)
{
    Delay_us(ms * 1000);  // 调用微秒延时函数
}

3. 综合示例

以下是一个完整的示例,结合 SysTick 和定时器实现 ms 和 us 延时函数:

c 复制代码
#include "stm32f4xx_hal.h"

// SysTick 延时函数
void Delay_ms(uint32_t ms)
{
    uint32_t start_tick = HAL_GetTick();
    while ((HAL_GetTick() - start_tick) < ms)
    {
        // 等待
    }
}

// 定时器延时函数
TIM_HandleTypeDef htim2;

void TIM2_Init(void)
{
    __HAL_RCC_TIM2_CLK_ENABLE();

    htim2.Instance = TIM2;
    htim2.Init.Prescaler = (SystemCoreClock / 1000000) - 1;
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 0xFFFFFFFF;
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_Base_Init(&htim2);

    HAL_TIM_Base_Start(&htim2);
}

void Delay_us(uint32_t us)
{
    uint32_t start_tick = __HAL_TIM_GET_COUNTER(&htim2);
    while ((__HAL_TIM_GET_COUNTER(&htim2) - start_tick) < us)
    {
        // 等待
    }
}

int main(void)
{
    // 初始化 HAL 库
    HAL_Init();

    // 配置系统时钟
    SystemClock_Config();

    // 初始化定时器
    TIM2_Init();

    // 初始化 GPIO
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 主循环
    while (1)
    {
        // 闪烁 LED(500ms 间隔)
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
        Delay_ms(500);

        // 微秒延时示例
        Delay_us(1000);  // 延时 1ms
    }
}

4. 注意事项

精度问题:

SysTick 的 ms 延时精度较高,但 us 延时依赖于空操作循环,可能受编译器优化影响。

定时器的 us 延时精度较高,但需要占用一个硬件定时器资源。

编译器优化:

如果使用空操作循环实现 us 延时,建议禁用编译器优化(如 -O0),或使用 volatile 关键字防止优化。

定时器资源:

如果系统中使用了多个定时器,请确保选择的定时器未被占用。

通过以上方法,可以在 216 MHz 主频的 STM32 微控制器上实现精确的 ms 和 us 延时函数。

相关推荐
微信1532379424315 小时前
离线语音识别 ( 小语种国家都支持)可定制词组
嵌入式硬件
weixin_5088216516 小时前
1ms软延时,不用定时器,stm32
stm32·单片机·嵌入式硬件
月阳羊17 小时前
【无人机】无人机PX4飞控系统高级软件架构
嵌入式硬件·架构·系统架构·无人机
华清远见IT开放实验室18 小时前
【新书上市】《STM32嵌入式系统开发—基于STM32CubeMX和HAL库》,高校教学推荐,STM32入门必读书籍!
stm32·单片机·嵌入式硬件·虚拟仿真·必读书籍·高校教学
智木芯语18 小时前
【58】编程技巧:单片机编程命名规范
单片机·嵌入式硬件·嵌入式·#stm32·#stc8
捷配datasheet18 小时前
OP2177运算放大器:高性能模拟信号处理的关键元件
嵌入式硬件·信号处理
逼子格20 小时前
五种音频器件综合对比——《器件手册--音频器件》
嵌入式硬件·音视频·硬件工程师·硬件测试·电子器件·硬件笔试真题·音频器件
niuTaylor1 天前
STM32平衡车开发实战教程:从零基础到项目精通
stm32·单片机·嵌入式硬件