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
相关产品推荐
相关产品推荐

