!文章内容如有错误或排版问题,请提交反馈,非常感谢!
使用51单片机的P2口控制8个LED灯时,可以通过C语言实现多种创意效果。
线路连接:
基础效果
流水灯(单方向循环)
#include <reg51.h> #include <intrins.h> // 包含_crol_函数 void delay(unsigned int t) { while(t--); } void main() { P2 = 0xFE; // 初始值:11111110(第一个LED亮) while(1) { P2 = _crol_(P2, 1); // 循环左移一位 delay(50000); } }
这段代码是为8051单片机设计的流水灯程序,使用了P2端口控制LED。
#include <reg51.h>
- 引入8051单片机的寄存器定义头文件,提供P0、P1、P2等端口寄存器的地址定义。
- 建议使用STC-ISP导出的头文件替换。使用#include “STC89C5xRc.h”可替换#include <reg51.h>和#include <intrins.h>
#include <intrins.h>
引入内部函数库,提供_crol_()(循环左移)等编译器内置函数。
void delay(unsigned int t) { … }
- 延时函数:通过空循环实现简单延时。
- 参数t控制循环次数,值越大延时越长。但注意:
- 延时精度低(依赖单片机主频和指令周期)。
- 在while(t–)中,每次循环约消耗2-3个机器周期(12MHz时钟下约2-3µs)。
void main() { … }
- 程序入口函数(8051复位后从此执行)。
P2 = 0xFE;
- 初始化P2端口:
- 0xFE的二进制:1111 1110
- 最低位(LSB)为0 → 若LED阴极接0且阳极接Vcc,第一个LED点亮。
while(1) { … }
- 无限循环实现持续运行。
P2 = _crol_(P2, 1);
- 循环左移操作:将P2当前值左移1位,最高位移到最低位。
初始 0xFE (1111 1110) → LED0亮 第一次 0xFD (1111 1101) → LED1亮 第二次 0xFB (1111 1011) → LED2亮 ... 第七次 0x7F (0111 1111) → LED7亮 第八次 0xFE (1111 1110) → 回到初始状态(循环)
delay(50000);
每次移位后延时约100ms(假设12MHz时钟):
- 每循环约2机器周期(2µs)。
- 总延时 ≈ 50000 × 2µs = 100ms(实测可能有偏差)。
优化后的代码(使用精确延时函数)
#include "STC89C5xRC.h" // STC89C5x系列专用头文件 // 精确100ms延时函数(晶振频率11.0592MHz) void Delay100ms(void) { unsigned char i, j; i = 180; j = 73; do { while (--j); } while (--i); } void main() { unsigned char ledPattern = 0xFE; // 初始模式:11111110 (P2.0 LED亮) while(1) { P2 = ledPattern; // 输出当前灯效到P2端口 Delay100ms(); // 精确延时100ms // 手动实现循环左移效果 if(ledPattern == 0x7F) { // 当达到最后一位(01111111)时回到初始位置 ledPattern = 0xFE; } else { // 标准循环左移实现: // 1. 左移一位(最低位自动补0) // 2. 将移出的高位补到最低位 ledPattern = (ledPattern << 1) | (ledPattern >> 7); } } }
关键优化说明:
- 精确延时系统
- 使用STC官方推荐的精确延时算法
- 在0592MHz晶振下精确产生100ms延时
- 双重循环结构确保时间精度
- 手动循环左移算法
- 通过位运算实现循环左移:
- << 1:左移一位(最高位移出,最低位补0)
- >> 7:将原始值的最高位移到最低位
- 位或操作:将两部分合并
- 边界条件处理
- 当检测到0x7F(01111111)时重置为初始状态
- 确保流水灯循环不间断运行
全闪烁(同步闪烁)
#include "STC89C5xRC.h" // STC89C5x系列专用头文件 // 精确100ms延时函数(晶振频率11.0592MHz) void Delay100ms(void) { unsigned char data i, j; i = 180; j = 73; do { while (--j); } while (--i); } void main() { while(1) { P2 = 0x00; // P2所有引脚低电平 - LED全亮 Delay100ms(); // 精确延时100ms P2 = 0xFF; // P2所有引脚高电平 - LED全灭 Delay100ms(); // 精确延时100ms } }
交替闪烁(奇偶交替)
#include "STC89C5xRC.h" // STC89C5x系列专用头文件 // 精确100ms延时函数(晶振频率11.0592MHz) void Delay100ms(void) { unsigned char data i, j; i = 180; j = 73; do { while (--j); } while (--i); } void main() { while(1) { P2 = 0xAA; // P2所有引脚低电平 - LED全亮 Delay100ms(); // 精确延时100ms P2 = 0x55; // P2所有引脚高电平 - LED全灭 Delay100ms(); // 精确延时100ms } }
中级效果
呼吸灯(PWM调光)
#include "STC89C5xRC.h" // STC89C5x系列专用头文件 // 延时50us函数(11.0592MHz) void Delay50us(void) { unsigned char i; // 根据STC-ISP,12T模式,11.0592MHz,延时50us i = 23; while (--i); } // 可调节的延时函数(单位:50us) void DelayX50us(unsigned int count) { while(count--) { Delay50us(); } } void main() { unsigned char duty; // 占空比控制变量 while(1) { // 从暗到亮:占空比0-100 for(duty = 0; duty < 100; duty++) { P2 = 0x00; // LED全亮 DelayX50us(duty); // 亮的时间 P2 = 0xFF; // LED全灭 DelayX50us(100 - duty); // 灭的时间 } // 从亮到暗:占空比100-0 for(duty = 100; duty > 0; duty--) { P2 = 0x00; // LED全亮 DelayX50us(duty); // 亮的时间 P2 = 0xFF; // LED全灭 DelayX50us(100 - duty); // 灭的时间 } } }
这段代码是一个针对STC89C5x系列单片机的快速呼吸灯实现。
头文件和寄存器定义
- #include “STC89C5xRC.h”,STC89C5x系列单片机的专用头文件,包含所有特殊功能寄存器的定义
精确延时系统
- void Delay50us(void)
- 使用i = 23和while (–i)组合实现精确50us延时
- 参数23是根据STC单片机0592MHz晶振、12时钟周期模式计算得出
- 每次循环消耗约17us (12/11.0592 ≈ 1.085us/机器周期 × 2)
- void DelayX50us(unsigned int count)
- 基于Delay50us()的多倍延时函数
- 调用count次Delay50us()
- 总延时 = count × 50us
延时参数表(11.0592MHz)
指令周期 | 机器周期数 | 近似时间 |
初始化 | 1 | 0.09us |
i=23 | 1 | 0.09us |
–i | 22 | 0.99us × 22 ≈ 21.78us |
while | 22 × 2 | 43.56us |
总时间 | 1+1+22+44 | ≈50us |
从暗到亮的渐变过程(呼气效果)
- 控制逻辑:
- 设置P2输出低电平(0x00)使LED亮起
- 亮起时间 = duty × 50us
- 设置P2输出高电平(0xFF)使LED熄灭
- 熄灭时间 = (100 – duty) × 50us
- 占空比变化:
- 起始: duty=0 → 亮0us/灭5000us → LED几乎不亮
- 结束: duty=99 → 亮4950us/灭50us → LED几乎全亮
- LED亮度曲线:
- 亮度 = (亮起时间)/总周期 = duty/100
- 线性增长,duty每增加1,亮度增加1%
从亮到暗的渐变过程(吸气效果)
- 控制逻辑:
- 与第一阶段相同,但duty从100递减到1
- 保持相同的时间计算公式
- 占空比变化:
- 起始: duty=100 → 亮5000us/灭0us → LED全亮
- 结束: duty=1 → 亮50us/灭4950us → LED几乎熄灭
- LED亮度曲线:线性下降,duty每减少1,亮度降低1%
整体系统参数分析
- 呼吸周期计算
- 每个子周期:100步 × 每步延时总和 = 100 × (duty + (100-duty)) × 50us = 100 × 100 × 50us = 500,000us = 0.5s
- 完整呼吸周期:(暗到亮 + 亮到暗) = 0.5s × 2 = 1s
- PWM频率
- 每个duty步骤的总时间:= 亮起时间 + 熄灭时间 = duty × 50us + (100-duty) × 50us = 100 × 50us = 5000us = 5ms
- PWM频率:= 1 / 0.005s = 200Hz,200Hz远高于人眼可察觉的闪烁频率(>75Hz),因此呼吸效果平滑无闪烁
跑马灯(双向循环)
#include "STC89C5xRC.h" // STC89C5x系列专用头文件 // 精确延时函数(11.0592MHz晶振) void Delay100ms(void) { unsigned char i, j, k; // STC官方推荐的100ms延时参数 i = 5; j = 52; k = 195; do { do { while (--k); } while (--j); } while (--i); } // 手动实现循环左移 unsigned char custom_crol(unsigned char value, unsigned char shift) { return (value << shift) | (value >> (8 - shift)); } // 手动实现循环右移 unsigned char custom_cror(unsigned char value, unsigned char shift) { return (value >> shift) | (value << (8 - shift)); } void main() { unsigned char led = 0xFE; // 初始LED状态:11111110(第一个LED亮) unsigned char i; P2 = led; // 初始化LED状态 while(1) { // 从左到右流水效果(循环左移) for(i = 0; i < 7; i++) { led = custom_crol(led, 1); // 循环左移一位 P2 = led; Delay100ms(); } // 从右到左流水效果(循环右移) for(i = 0; i < 7; i++) { led = custom_cror(led, 1); // 循环右移一位 P2 = led; Delay100ms(); } } }
二进制计数器
#include "STC89C5xRC.h" // STC89C5x系列专用头文件 // 精确延时函数(11.0592MHz晶振) void Delay100ms(void) { unsigned char data i, j, k; // STC官方推荐的100ms延时参数 i = 5; j = 52; k = 195; do { do { while (--k); } while (--j); } while (--i); } void main() { unsigned char count = 0; // 计数变量 // 初始显示:全灭(计数0的反码为0xFF) P2 = 0xFF; while(1) { // 更新计数并输出LED状态 P2 = ~count; // 计数值取反输出(LED低电平点亮) count++; // 计数递增 // 精确延时(约100ms) Delay100ms(); // 添加特殊效果:计数回零时短暂停 if(count == 0) { // 计数回零时额外延时半秒 unsigned char i; for(i = 0; i < 5; i++) { Delay100ms(); } } } }
高级效果
随机流星效果
#include <reg51.h> #include <intrins.h> #include <stdlib.h> // 包含rand()函数 // 使用定时器0生成随机种子 void init_random() { TMOD |= 0x01; // 定时器0模式1 TH0 = 0; // 初始值设为0 TL0 = 0; TR0 = 1; // 启动定时器 while(!TF0); // 等待溢出 TR0 = 0; // 停止定时器 TF0 = 0; // 清除标志 srand(TH0 * 256 + TL0); // 用定时器值做随机种子 } void delay(unsigned int t) { while(t--); } // 创建随机流星效果 void meteor_shower() { unsigned char start_pos = rand() % 8; // 随机起始位置(0-7) unsigned char length = 3 + rand() % 3; // 流星长度(3-5灯) unsigned char speed = 50 + rand() % 150; // 随机速度因子 unsigned char mask; unsigned int i, j; for(i=0; i<8+length; i++) { mask = 0; // 绘制流星(从start_pos开始) for(j=0; j<length; j++) { int pos = start_pos + i - j; if(pos >= 0 && pos < 8) { mask |= (0x80 >> pos); // 设置对应位 } } P2 = ~mask; // 输出到LED delay(speed * 100); // 随机延时 } } void main() { init_random(); // 初始化随机数生成器 while(1) { meteor_shower(); delay(30000); // 流星之间的暂停 // 30%概率出现双流星 if(rand() % 100 < 30) { meteor_shower(); delay(20000); } } }
按键控制LED灯
8个独立按键各自控制1个LED
要实现51单片机P2口连接的8个LED与P3口连接的8个独立开关进行一对一控制,代码如下(假设LED低电平点亮,开关按下时低电平):
- 硬件连接:
- P2口的8个引脚连接LED(共阳极接法:LED正极接VCC,负极通过限流电阻接x,低电平时点亮)。
- P3口的8个引脚连接独立开关(开关一端接地,另一端通过上拉电阻接VCC,按下时输出低电平)。
- 控制逻辑:
- 当开关按下(x=0)时,对应的P2.x输出0,LED点亮。
- 当开关松开(x=1)时,对应的P2.x输出1,LED熄灭。
- P2 = P3 实现了开关状态与LED状态的实时同步。
#include <reg51.h> void delay_ms(unsigned int n) { unsigned int i, j; for(i=0; i<n; i++) for(j=0; j<120; j++); } void main() { bit last_state = 0xFF; // 存储上次开关状态 while(1) { if(P3 != last_state) { // 检测状态变化 delay_ms(10); // 延时10ms消抖 if(P3 != last_state) { P2 = P3; // 更新LED状态 last_state = P3; } } } }
8个独立按键控制8个灯效
#include <reg51.h> #include <intrins.h> // 包含移位函数 #define MODE_COUNT 8 // 模式总数 #define LED_PORT P2 // LED连接端口 #define KEY_PORT P3 // 按键连接端口 // 函数声明 void delay_us(unsigned int us); void delay_ms(unsigned int ms); void all_off(void); void all_on(void); void flow_left(void); void flow_right(void); void blink_all(void); void alternate(void); void breath(void); void wave(void); unsigned char get_key(void); // 全局变量 unsigned char current_mode = 0; // 当前模式 (0-7) unsigned char prev_key = 0xFF; // 上次按键状态 // 呼吸灯专用变量 unsigned char breath_duty = 0; // 当前占空比 bit breath_dir = 0; // 呼吸方向: 0=渐亮, 1=渐暗 // 主函数 void main() { KEY_PORT = 0xFF; // 初始化按键端口 all_off(); // 初始化所有LED熄灭 while(1) { unsigned char key = get_key(); // 检测新按键按下 if (key != 0xFF && key != prev_key) { current_mode = key; // 切换到新按钮对应的模式 prev_key = key; // 重置呼吸灯状态 if(current_mode == 6) { breath_duty = 0; breath_dir = 0; } } // 根据当前模式执行相应灯光效果 switch(current_mode) { case 0: all_off(); break; // 模式0: 全灭 case 1: all_on(); break; // 模式1: 全亮 case 2: flow_left(); break; // 模式2: 左流水灯 case 3: flow_right(); break; // 模式3: 右流水灯 case 4: blink_all(); break; // 模式4: 全体闪烁 case 5: alternate(); break; // 模式5: 交替闪烁 case 6: breath(); break; // 模式6: 呼吸灯效果 case 7: wave(); break; // 模式7: 波浪效果 } } } // 模式0: 所有LED熄灭 void all_off() { LED_PORT = 0xFF; } // 模式1: 所有LED点亮 void all_on() { LED_PORT = 0x00; } // 模式2: 左流水灯 void flow_left() { static unsigned char pos = 0; static unsigned int count = 0; LED_PORT = ~(0x01 << pos); // 点亮当前位置 // 非阻塞延时 if(++count >= 150) { count = 0; pos = (pos + 1) % 8; // 更新位置 } delay_ms(1); } // 模式3: 右流水灯 void flow_right() { static unsigned char pos = 0; static unsigned int count = 0; LED_PORT = ~(0x80 >> pos); // 点亮当前位置 // 非阻塞延时 if(++count >= 150) { count = 0; pos = (pos + 1) % 8; // 更新位置 } delay_ms(1); } // 模式4: 全体闪烁 void blink_all() { static bit state = 0; static unsigned int count = 0; LED_PORT = state ? 0x00 : 0xFF; // 非阻塞延时 if(++count >= 250) { count = 0; state = !state; } delay_ms(1); } // 模式5: 交替闪烁 void alternate() { static bit state = 0; static unsigned int count = 0; LED_PORT = state ? 0x55 : 0xAA; // 交替模式 // 非阻塞延时 if(++count >= 250) { count = 0; state = !state; } delay_ms(1); } // 模式6: 呼吸灯效果(使用优化的PWM控制) void breath() { // 使用PWM控制亮度 LED_PORT = 0x00; // 开启所有LED delay_us(breath_duty * 10); // 开启时间 (10us/单位) LED_PORT = 0xFF; // 关闭所有LED delay_us((100 - breath_duty) * 10); // 关闭时间 // 更新占空比 if(breath_dir == 0) { if(++breath_duty >= 100) breath_dir = 1; } else { if(--breath_duty <= 0) breath_dir = 0; } } // 模式7: 波浪效果 void wave() { static unsigned char step = 0; static unsigned int count = 0; // 不同模式的光波样式 unsigned char patterns[] = {0x81, 0x42, 0x24, 0x18, 0x24, 0x42, 0x81, 0x00}; LED_PORT = patterns[step]; // 非阻塞延时 if(++count >= 150) { count = 0; step = (step + 1) % 8; } delay_ms(1); } // 检测按键函数 (返回0-7表示按键号,0xFF表示无按键) unsigned char get_key() { unsigned char i; if(KEY_PORT == 0xFF) { return 0xFF; // 无按键 } // 检测按键防抖 delay_ms(15); if(KEY_PORT == 0xFF) { return 0xFF; // 误触发 } // 找出按下按键的编号 for(i = 0; i < 8; i++) { if(!(KEY_PORT & (1 << i))) { // 检测到低电平 while(!(KEY_PORT & (1 << i))); // 等待按键释放 return i; // 返回按键编号 } } return 0xFF; } // 延时函数(微秒级) void delay_us(unsigned int us) { while(us--) { /* 对于12MHz时钟: 1个机器周期 = 1us 执行一个空循环约3个机器周期 */ _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); } } // 延时函数(毫秒级) void delay_ms(unsigned int ms) { unsigned int i, j; for(i = 0; i < ms; i++) for(j = 0; j < 120; j++); // 120次循环约1ms }
1个独立按键控制8个LED
以下是实现一个按键按顺序单独打开LED灯的效果的代码。每次按键只打开一个LED灯,并且每次按键切换到下一个LED:
#include "STC89C5xRC.h" // 延时函数 void delay_ms(unsigned int n) { unsigned int i, j; for(i = 0; i < n; i++) for(j = 0; j < 120; j++); } // 按键检测函数 bit key_press() { static unsigned int debounce = 0; static bit last_state = 1; bit current_state = P30; // 假设按钮接在P3.0 // 检测按键下降沿(按下) if(last_state && !current_state) { debounce = 20; // 开始消抖计数 } last_state = current_state; if(debounce > 0) { debounce--; if(debounce == 0 && !current_state) { // 等待按键释放 while(!P30); return 1; } } return 0; } void main() { unsigned char led_state = 0; // 当前LED状态 (0-8) P2 = 0xFF; // 初始所有LED熄灭 while(1) { // 检测按键按下 if(key_press()) { // 切换到下一个LED状态 led_state = (led_state + 1) % 9; // 根据状态点亮相应的LED switch(led_state) { case 0: P2 = 0xFF; // 所有LED熄灭 break; case 1: P2 = 0xFE; // 11111110 - 只有P2.0亮 break; case 2: P2 = 0xFD; // 11111101 - 只有P2.1亮 break; case 3: P2 = 0xFB; // 11111011 - 只有P2.2亮 break; case 4: P2 = 0xF7; // 11110111 - 只有P2.3亮 break; case 5: P2 = 0xEF; // 11101111 - 只有P2.4亮 break; case 6: P2 = 0xDF; // 11011111 - 只有P2.5亮 break; case 7: P2 = 0xBF; // 10111111 - 只有P2.6亮 break; case 8: P2 = 0x7F; // 01111111 - 只有P2.7亮 break; } } // 短延时防止按键响应过快 delay_ms(1); } }
1个独立按键控制8个灯效
具体效果:
- 按键按下 → 模式0:所有LED熄灭
- 按键按下 → 模式1:所有LED点亮
- 按键按下 → 模式2:左流水灯(从左向右移动)
- 按键按下 → 模式3:右流水灯(从右向左移动)
- 按键按下 → 模式4:全体闪烁
- 按键按下 → 模式5:交替闪烁
- 按键按下 → 模式6:呼吸灯效果
- 按键按下 → 模式7:波浪效果(从两端向中间传播)
- 再按键 → 回到模式0:所有LED熄灭
#include "STC89C5xRC.h" #include <intrins.h> #define LED_PORT P2 // LED连接端口 #define KEY_PIN P30 // 按键连接P3.0 // 模式枚举 typedef enum { MODE_OFF = 0, // 模式0: 全灭 MODE_ALL_ON, // 模式1: 全亮 MODE_FLOW_LEFT, // 模式2: 左流水灯 MODE_FLOW_RIGHT, // 模式3: 右流水灯 MODE_BLINK_ALL, // 模式4: 全体闪烁 MODE_ALTERNATE, // 模式5: 交替闪烁 MODE_BREATH, // 模式6: 呼吸灯 MODE_WAVE, // 模式7: 波浪效果 MODE_COUNT // 模式总数 } Modes; // 函数声明 void delay_us(unsigned int us); void delay_ms(unsigned int ms); void all_off(void); void all_on(void); void flow_left(void); void flow_right(void); void blink_all(void); void alternate(void); void breath(void); void wave(void); bit get_key_press(void); // 全局变量 Modes current_mode = MODE_OFF; // 当前模式 bit key_pressed = 0; // 按键按下标志 // 呼吸灯专用变量 unsigned char breath_duty = 0; // 当前占空比 bit breath_dir = 0; // 呼吸方向: 0=渐亮, 1=渐暗 // 主函数 void main() { // 初始化所有LED熄灭 all_off(); while(1) { // 检测按键按下 if(get_key_press()) { // 模式循环切换:0→1→2→3→4→5→6→7→0... current_mode = (current_mode + 1) % MODE_COUNT; // 模式7之后回到模式0(实际由取模运算自动处理) // 重置呼吸灯状态 if(current_mode == MODE_BREATH) { breath_duty = 0; breath_dir = 0; } // 初始化新模式的LED状态 switch(current_mode) { case MODE_OFF: all_off(); break; case MODE_ALL_ON: all_on(); break; case MODE_FLOW_LEFT: case MODE_FLOW_RIGHT: case MODE_WAVE: LED_PORT = 0xFF; break; case MODE_BLINK_ALL: case MODE_ALTERNATE: LED_PORT = 0x55; break; case MODE_BREATH: LED_PORT = 0x00; break; // 呼吸灯开始时全亮 default: break; } } // 执行当前模式效果 switch(current_mode) { case MODE_OFF: all_off(); break; case MODE_ALL_ON: all_on(); break; case MODE_FLOW_LEFT: flow_left(); break; case MODE_FLOW_RIGHT: flow_right(); break; case MODE_BLINK_ALL: blink_all(); break; case MODE_ALTERNATE: alternate(); break; case MODE_BREATH: breath(); break; case MODE_WAVE: wave(); break; default: all_off(); // 默认全灭 } } } // 模式0: 所有LED熄灭 void all_off() { LED_PORT = 0xFF; } // 模式1: 所有LED点亮 void all_on() { LED_PORT = 0x00; } // 模式2: 左流水灯 void flow_left() { static unsigned char pos = 0; static unsigned int count = 0; if(++count >= 150) { // 150ms更新一次位置 count = 0; LED_PORT = ~(0x01 << pos); // 点亮当前位置 pos = (pos + 1) % 8; // 更新位置 } delay_ms(1); } // 模式3: 右流水灯 void flow_right() { static unsigned char pos = 0; static unsigned int count = 0; if(++count >= 150) { // 150ms更新一次位置 count = 0; LED_PORT = ~(0x80 >> pos); // 点亮当前位置 pos = (pos + 1) % 8; // 更新位置 } delay_ms(1); } // 模式4: 全体闪烁 void blink_all() { static bit state = 0; static unsigned int count = 0; if(++count >= 250) { // 250ms切换状态 count = 0; state = !state; } LED_PORT = state ? 0x00 : 0xFF; // 全亮或全灭 delay_ms(1); } // 模式5: 交替闪烁 void alternate() { static bit state = 0; static unsigned int count = 0; if(++count >= 250) { // 250ms切换状态 count = 0; state = !state; } LED_PORT = state ? 0x55 : 0xAA; // 01010101或10101010 delay_ms(1); } // 模式6: 呼吸灯效果 void breath() { // PWM控制亮度 LED_PORT = 0x00; // 开启所有LED delay_us(breath_duty * 10); // 开启时间 LED_PORT = 0xFF; // 关闭所有LED delay_us((100 - breath_duty) * 10); // 关闭时间 // 更新占空比 if(breath_dir == 0) { if(++breath_duty >= 100) breath_dir = 1; } else { if(--breath_duty <= 0) breath_dir = 0; } } // 模式7: 波浪效果 void wave() { static unsigned char step = 0; static unsigned int count = 0; // 波浪模式:光从两边向中间移动 unsigned char patterns[] = {0x81, 0xC3, 0xE7, 0xFF, 0xE7,0xC3, 0x81, 0x00}; LED_PORT = patterns[step]; // 非阻塞延时 if(++count >= 150) { count = 0; step = (step + 1) % 8; } delay_ms(1); } // 按键检测函数(带消抖),返回按键按下状态 bit get_key_press(void) { static bit last_state = 1; // 默认高电平(按键未按下) static unsigned int debounce = 0; bit current_state = KEY_PIN; // 检测下降沿(按键按下) if(last_state && !current_state) { debounce = 20; // 开始消抖计数 } last_state = current_state; // 按键消抖处理 if(debounce > 0) { debounce--; if(debounce == 0 && !current_state) { // 等待按键释放 while(!KEY_PIN); return 1; } } return 0; } // 延时函数(微秒级,近似) void delay_us(unsigned int us) { while(us--) { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); } } // 延时函数(毫秒级) void delay_ms(unsigned int ms) { unsigned int i, j; for(i = 0; i < ms; i++) for(j = 0; j < 120; j++); // 120次循环约1ms