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下载代码

效果展示

相关推荐
桀人3 小时前
USART帧格式
网络·stm32·单片机·嵌入式硬件
qq_448011163 小时前
如何烧录TAU804的固件
单片机·嵌入式硬件
深圳老胡3 小时前
STM32F4 OTA 升级双 App 方案设计与实现
笔记·stm32·单片机·代码规范
HRTOS3 小时前
HRTOS 4.0 内核资源配置优化:减少资源对象与消息队列数量
经验分享·单片机·系统架构·51单片机
深圳老胡5 小时前
STM32F4 OTA升级:单App与双App方案优缺点对比
笔记·stm32·单片机·代码规范
mftang6 小时前
CAN总线控制段:位级结构、DLC编码、代际扩展与错误处理的系统性分析
单片机·嵌入式硬件·can总线·控制段·数据长度代码
BSD_CGQ15 小时前
FSR传感器STM32 DMA高速采样工程实现(高精度、低CPU占用)
stm32·单片机·嵌入式硬件·压力传感器·源头工厂·柔性薄膜压力传感器·可变电阻压力传感器
芯岭技术郦18 小时前
32 位 ARM® Cortex®-M0+ 内核MCU普冉MS32C001-C
单片机·嵌入式硬件
骑着毛驴数星星18 小时前
STM32 CAN波特率与采样点计算,基于HAL库
stm32·单片机·嵌入式硬件