志→目标, 自我提升

51单片机实战:控制8个LED小灯

钱魏Way · · 8 次浏览
!文章内容如有错误或排版问题,请提交反馈,非常感谢!

使用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

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注