编写代码
想要实现 LED 闪烁,其实逻辑很简单:让 P2.0 这个灯亮 → 延时 → 灭 → 延时 → 循环。
如果只是写:
亮灭代码
c
while(1) {
P2 = 0xFE; // 亮
P2 = 0xFF; // 灭
}
程序会以极快的速度(12MHz 晶振,一个指令周期约 1 微秒)反复执行"亮-灭"。亮和灭的时间太短,人眼根本分辨不出来,看起来就像一直亮着或者一直灭着。
所以需要在"亮"和"灭"之间加上延时,让灯保持亮的状态一段时间,再保持灭的状态一段时间,人眼才能看到闪烁效果。
板子的晶振是 12MHz,我们写一个约 500ms(0.5秒) 的延时函数,这样灯就会:
- 亮 0.5 秒
- 灭 0.5 秒
- 循环
也就是 1 秒闪烁一次(一亮一灭为一个周期)。
延时代码
打开STC-ISP,右边选择"软件延时计算器"。输入系统频率为12MHz、定时长度为500毫秒、8051指令集为STC89 --> 复制代码

c
void Delay500ms(void) //@12.000MHz
{
unsigned char data i, j, k;
_nop_();
i = 4;
j = 205;
k = 187;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
完整代码
c
#include <mcs51/8051.h>
#include <INTRINS.h> // 包含nop_()函数
void Delay500ms(void) //@12.000MHz
{
unsigned char data i, j, k;
_nop_();
i = 4;
j = 205;
k = 187;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main(void)
{
while(1) {
P2 = 0xFE; // 11111110,P2.0/P20 输出低电平,点亮第一个 LED
Delay500ms();
P2 = 0xFF; // 11111111,P2.0/P20 输出低电平,点亮第一个 LED
Delay500ms();
}
}
编译代码
powershell
PS D:\project\STC51\02_led_scintillation> sdcc -mmcs51 --model-small --iram-size 256 --xram-size 0 --code-size 8192 .\led_scintillation.c
.\led_scintillation.c:3:10: fatal error: INTRINS.h: No such file or directory
3 | #include <INTRINS.h>
| ^~~~~~~~~~~
compilation terminated.
subprocess error 1
PS D:\project\STC51\02_led_scintillation> sdcc -mmcs51 --model-small --iram-size 256 --xram-size 0 --code-size 8192 .\led_scintillation.c
.\led_scintillation.c:7: syntax error: token -> 'i' ; column 21
将以上代码直接通过SDCC进行编译,会发现两个问题,INTRINS.h找不到,data找不到
问题 1:INTRINS.h 找不到
报错
text
fatal error: INTRINS.h: No such file or directory
原因
INTRINS.h 是 Keil C51 专有的头文件,SDCC 没有这个文件。STC-ISP 的"软件延时计算器"生成的代码默认是给 Keil 用的,所以会带这个头文件。
解决
SDCC 里没有 nop() 函数,需要用内联汇编自己实现:
c
#define _nop_() __asm NOP __endasm
把这行宏定义放在 #include <mcs51/8051.h> 之后,后面就可以像 Keil 一样用 nop()。
问题 2:data 找不到
报错
text
syntax error: token -> 'i' ; column 21
原因
data 是 Keil C51 的存储类型关键字,SDCC 里必须写成 __data(前面加两个下划线),否则编译器把 data 当成普通变量名,后面又跟了 i,就报语法错误。
解决
两种改法,任选一种:
c
unsigned char __data i, j, k; // 加双下划线
或者直接删掉 data,让编译器自动分配:
c
unsigned char i, j, k; // 推荐,简单程序不用手动指定
修复后的完整代码
#include <mcs51/8051.h>
// SDCC 没有 INTRINS.h,用宏定义实现 _nop_()
#define _nop_() __asm NOP __endasm
void Delay500ms(void) //@12.000MHz
{
unsigned char i, j, k; // 去掉 data,让编译器自动分配
_nop_();
i = 4;
j = 205;
k = 187;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main(void)
{
while(1) {
P2 = 0xFE; // 11111110,P2.0/P20 输出低电平,点亮第一个 LED
Delay500ms();
P2 = 0xFF; // 11111111,P2.0/P20 输出低电平,点亮第一个 LED
Delay500ms();
}
}
下载代码
使用STC-ISP下载代码

效果展示
