You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32 Nucleo F103RB基于NOP()的延时函数异常问题求助

问题分析与解决办法

核心误解:NOP指令的执行周期

NOP()指令在STM32F103采用的Cortex-M3内核中,并非1个时钟周期就能完成执行——实际上它需要2个时钟周期。你传入64×10⁶的计数,仅NOP本身就会消耗2秒,再加上循环的额外开销,延时自然会远超预期。

循环的额外开销

你的delay函数大概率是类似这样的结构:

void delay(uint32_t count) {
    volatile uint32_t i;
    for(i=0; i<count; i++) {
        __NOP();
    }
}

除了NOP的2个周期,循环的自增、比较跳转操作还会额外消耗3-4个时钟周期。单次循环总周期数约5个,这会让实际延时比单纯计算NOP周期的结果再拉长一倍多,这就是你看到LED亮灭间隔极长的直接原因。

修正方案

方案1:调整计数数值(临时凑合用)

如果非要用NOP延时,先估算单次循环的总周期数(按5个计算),1秒延时对应的计数应为 64×10⁶ / 5 = 12.8×10⁶。你可以先传入10×10⁶测试,再根据实际延时效果微调数值。

方案2:用SysTick实现精准延时(推荐)

Cortex-M内核自带的SysTick定时器是实现精准延时的最佳选择,示例代码如下:

#include "stm32f10x.h"

// 初始化SysTick,配置为1微秒触发一次
void SysTick_Init(void) {
    // 64MHz时钟下,1微秒需要64个时钟周期
    if(SysTick_Config(SystemCoreClock / 1000000)) {
        // 配置失败则死循环
        while(1);
    }
}

// 微秒延时函数
void delay_us(uint32_t us) {
    uint32_t start = SysTick->VAL;
    while((start - SysTick->VAL) < us);
}

// 毫秒延时函数
void delay_ms(uint32_t ms) {
    while(ms--) {
        delay_us(1000);
    }
}

使用前先调用SysTick_Init(),之后用delay_ms(1000)就能实现准确的1秒延时。

方案3:确认系统时钟是否真为64MHz

你假设的64MHz可能只是理论值,需实际验证时钟配置是否正确。可以通过读取寄存器确认:

uint32_t get_system_clock(void) {
    uint32_t pllmul, pllsrc;
    pllsrc = (RCC->CFGR >> 16) & 0x01;
    pllmul = (RCC->CFGR >> 18) & 0x0F;
    
    // Nucleo板默认用8MHz外部晶振作为PLL源
    return 8000000 * (pllmul + 2);
}

调用该函数获取实际系统时钟,如果数值不是64MHz,那你的计数从根源上就错了。


内容的提问来源于stack exchange,提问作者jin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 18:34:50