如果你刚接触嵌入式开发,可能会对8051单片机束手无策,因为它的标准库好像没有延迟函数,所以如何用最基础的指令“炼”出精准延时?本文将提供三种方案,以供参考。
1、空循环法
void delay_ms(unsigned int ms) {
unsigned int i, j;
for(i=0; i for(j=0; j<123; j++); // 12MHz晶振下约1ms } 核心逻辑:通过双重循环消耗CPU周期,循环次数需根据晶振频率手动校准。 致命缺陷:编译器优化会“吃掉”空循环,需加volatile关键字或关闭优化。 2、定时器中断 配置步骤 初始化Timer0(模式1,16位自动重装): TMOD |= 0x01; // Timer0模式1 TH0 = 0xFC; // 1ms@12MHz(计算:65536-1000=64536=FC18H) TL0 = 0x18; ET0 = 1; // 允许Timer0中断 EA = 1; // 开总中断 TR0 = 1; // 启动定时器 中断服务函数: volatile unsigned int ms_count = 0; void timer0_isr() interrupt 1 { TH0 = 0xFC; TL0 = 0x18; // 重装初值 ms_count++; } 调用延时: void delay_ms(unsigned int ms) { ms_count = 0; while(ms_count < ms); } 优势:不受编译器优化影响,延时精度达微秒级。 3、汇编指令级优化 DELAY_MS: MOV R6, #250 ; 外层循环次数 DELAY_LOOP: MOV R7, #250 ; 内层循环次数 DJNZ R7, $ ; 消耗1个机器周期 DJNZ R6, DELAY_LOOP RET ; 12MHz下约1ms 适用场景:对代码体积敏感的极端环境(如8051小容量型号)。 4、如何选择? 简单场景(如LED闪烁) → 空循环法(代码最简)。 多任务系统(如UART通信) → 定时器中断(不阻塞主程序)。 代码体积优先(如OTP芯片) → 汇编优化(牺牲可读性换空间)。 本文凡亿教育原创文章,转载请注明来源!