51 单片机LED闪烁(SDCC + Notepad++ + STC-ISP/普中ISP)

编写代码

想要实现 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下载代码

效果展示

相关推荐
小向是个Der18 小时前
嵌入式进阶——MCU上电后的动作
c语言·单片机·mcu·学习·链接脚本
车软学堂18 小时前
从测试转开发,到底要补什么
网络·人工智能·python·功能测试·单片机·车载系统·自动化
LCG米19 小时前
STM32 ADC多通道DMA定时器触发实测:TRGO触发链、采样率精确控制与乒乓缓冲落地
stm32·单片机·嵌入式·adc
iCxhust19 小时前
SEGGER 的 J-Scope
单片机·嵌入式硬件
路上有只喵21 小时前
认识元器件 · 单片机(MCU/MPU/SOC) · 实战篇2
单片机·嵌入式硬件
单片机仿真设计21 小时前
Proteus仿真51单片机的智能温控风扇调速系统设计(仿真图+程序)
单片机·嵌入式硬件·proteus
youcans_1 天前
【嵌入式软件AI编程】22. STM32 基础实验:GPIO外部中断
stm32·单片机·嵌入式硬件·ai编程·claude
未来_攻城狮1 天前
STM32F407VGT6 芯片详解:高性能 Cortex-M4 MCU 入门指南
stm32·单片机·嵌入式硬件
xcLeigh1 天前
FreeRTOS实战:用STM32+SEGGER打造工业级实时嵌入式系统
人工智能·stm32·单片机·嵌入式硬件·ai
路上有只喵1 天前
认识元器件 · 单片机(MCU/MPU/SOC) · 实战篇1
单片机·嵌入式硬件