!文章内容如有错误或排版问题,请提交反馈,非常感谢!
5050全彩LED是共阳极设计(V接正极),通过控制R、G、B引脚的负极调光。使用PWM(脉宽调制)调整R、G、B的占空比,混合出不同颜色。
系统目标
- MCU: STC89C52RC
- LED模块:普通 5050 RGB 模块(共阴极,4引脚:VCC、R、G、B)
- 控制方式:用 51 单片机 软件 PWM 控制 RGB 三色亮度
- 输入方式:使用0 ~ P3.7 八个独立按键控制 8 种灯效
接线说明
名称 | 引脚 | 说明 |
R | P2.0 | 红灯控制(低电平亮) |
G | P2.1 | 绿灯控制(低电平亮) |
B | P2.2 | 蓝灯控制(低电平亮) |
VCC | +5V | 接电源正极 |
GND | GND | 接电源负极 |
按键 | P3.0~P3.7 | 低电平有效(带上拉) |
灯效定义(按键模式切换)
按键(P3.x) | 灯效说明 |
P3.0 | 红色常亮 |
P3.1 | 绿色常亮 |
P3.2 | 蓝色常亮 |
P3.3 | 呼吸灯(红) |
P3.4 | RGB轮换 |
P3.5 | 彩色渐变 |
P3.6 | 快速闪烁随机色 |
P3.7 | 熄灭 |
主程序(Keil C 源码)
#include <REGX52.H> #define uchar unsigned char #define uint unsigned int // RGB 引脚定义 sbit R_LED = P2^0; sbit G_LED = P2^1; sbit B_LED = P2^2; uchar mode = 0; // 当前灯效模式 uchar R_val = 0, G_val = 0, B_val = 0; // PWM值 // 简单延时 void Delay_ms(uint ms) { uint i, j; for (i = 0; i < ms; i++) for (j = 0; j < 123; j++); } // 读取按键状态(低电平有效) void KeyScan() { uchar key = P3 ^ 0xFF; // 获取按键值(P3.0~P3.7) uchar i; for (i = 0; i < 8; i++) { if ((key >> i) & 0x01) { mode = i; // 切换灯效 } } } // 软件PWM输出,周期为256(约1ms) void RGB_PWM_Output() { uchar i; for (i = 0; i < 255; i++) { R_LED = (i < R_val) ? 0 : 1; G_LED = (i < G_val) ? 0 : 1; B_LED = (i < B_val) ? 0 : 1; } } // 呼吸灯变量 uchar breathe = 0; bit up = 1; // 随机数种子 uint seed = 12345; uchar random() { seed = seed * 25173 + 13849; return (uchar)(seed >> 8); } // 设置 RGB 值 void SetColor(uchar r, uchar g, uchar b) { R_val = r; G_val = g; B_val = b; } void main() { while (1) { KeyScan(); switch (mode) { case 0: SetColor(255, 0, 0); break; // 红 case 1: SetColor(0, 255, 0); break; // 绿 case 2: SetColor(0, 0, 255); break; // 蓝 case 3: // 呼吸灯 红色 if (up) breathe += 5; else breathe -= 5; if (breathe >= 250) up = 0; if (breathe <= 5) up = 1; SetColor(breathe, 0, 0); break; case 4: // RGB轮换(每轮切换一次) { static uchar rgb_state = 0; switch (rgb_state) { case 0: SetColor(255, 0, 0); break; // 红 case 1: SetColor(0, 255, 0); break; // 绿 case 2: SetColor(0, 0, 255); break; // 蓝 } rgb_state++; if (rgb_state > 2) rgb_state = 0; Delay_ms(300); } break; case 5: // 渐变 SetColor(breathe, 255 - breathe, breathe / 2); if (up) breathe += 3; else breathe -= 3; if (breathe >= 250) up = 0; if (breathe <= 5) up = 1; break; case 6: // 快速闪烁随机 SetColor(random(), random(), random()); Delay_ms(150); break; case 7: // 熄灭 SetColor(0, 0, 0); break; } RGB_PWM_Output(); } }
代码注解:
全局变量
uchar mode = 0; // 当前灯效模式 uchar R_val = 0, G_val = 0, B_val = 0; // PWM值 uchar breathe = 0; // 呼吸灯变量 bit up = 1; // 呼吸灯方向标志 uint seed = 12345; // 随机数种子
- mode:保存当前选择的灯光效果(0-7)
- R_val, G_val, B_val:存储RGB三色的PWM值
- breathe:用于呼吸灯效果和渐变效果的亮度控制变量
- up:控制呼吸灯方向(增亮或减暗)
- seed:用于生成伪随机数的种子
延时函数
void Delay_ms(uint ms) { uint i, j; for (i = 0; i < ms; i++) for (j = 0; j < 123; j++); }
- 实现毫秒级延时
- 参数ms指定延时时间(毫秒)
- 循环次数123根据单片机的晶振频率设定
按键扫描函数
void KeyScan() { uchar key = P3 ^ 0xFF; // 获取按键值(P3.0~P3.7) uchar i; for (i = 0; i < 8; i++) { if ((key >> i) & 0x01) { mode = i; // 切换灯效 } } }
- 检测P3口的8个按键(按键按下对应引脚为低电平)
- 通过P3 ^ 0xFF将按下的按键位置为1
- 循环检查每个位,如果某位为1表示对应按键按下
- 将按键编号(0-7)赋值给mode变量
PWM输出函数
void RGB_PWM_Output() { uchar i; for (i = 0; i < 255; i++) { R_LED = (i < R_val) ? 0 : 1; G_LED = (i < G_val) ? 0 : 1; B_LED = (i < B_val) ? 0 : 1; } }
- 软件实现的PWM(脉宽调制)输出
- 通过255次循环模拟PWM周期
- 当循环计数器i小于目标PWM值时,LED引脚输出低电平(LED亮)
- 当i大于等于目标PWM值时,LED引脚输出高电平(LED灭)
- 例如:R_val=255表示全亮,R_val=0表示全灭
随机数生成函数
uchar random() { seed = seed * 25173 + 13849; return (uchar)(seed >> 8); }
- 伪随机数生成器,使用线性同余法
- 25173和13849是算法参数
- 返回种子值的高8位作为随机数(0-255)
颜色设置函数
void SetColor(uchar r, uchar g, uchar b) { R_val = r; G_val = g; B_val = b; }
- 设置RGB三个通道的PWM值
- 参数r、g、b范围为0-255(0为最暗,255为最亮)
主函数框架
void main() { while (1) { KeyScan(); // 检测按键状态 // 根据mode选择不同的灯光效果 switch (mode) { // 8种灯光效果实现 } RGB_PWM_Output(); // 更新LED输出 } }
- 主循环不断检测按键并更新灯光效果
- 每次循环都会调用RGB_PWM_Output()刷新LED显示
8种灯光效果详解
静态红色 (mode 0)
SetColor(255, 0, 0);
- 仅红色通道全亮,绿色和蓝色通道全灭
- 显示纯红色
静态绿色 (mode 1)
SetColor(0, 255, 0);
- 仅绿色通道全亮
- 显示纯绿色
静态蓝色 (mode 2)
SetColor(0, 0, 255);
- 仅蓝色通道全亮
- 显示纯蓝色
红色呼吸灯 (mode 3)
if (up) breathe += 5; else breathe -= 5; if (breathe >= 250) up = 0; if (breathe <= 5) up = 1; SetColor(breathe, 0, 0);
- 红色亮度在5-250范围内变化
- up变量控制亮度变化方向(增亮或减暗)
- 亮度达到250时反向减暗,达到5时反向增亮
- 效果:红色渐强渐弱,类似呼吸效果
RGB轮换 (mode 4)
static uchar rgb_state = 0; switch (rgb_state) { case 0: SetColor(255, 0, 0); break; // 红 case 1: SetColor(0, 255, 0); break; // 绿 case 2: SetColor(0, 0, 255); break; // 蓝 } rgb_state++; if (rgb_state > 2) rgb_state = 0; Delay_ms(300);
- 使用静态变量rgb_state保存当前颜色状态
- 轮流显示红、绿、蓝三种基色
- 每次切换延时300ms
- 效果:红→绿→蓝→红…循环变化
彩色渐变 (mode 5)
SetColor(breathe, 255 - breathe, breathe / 2); if (up) breathe += 3; else breathe -= 3; if (breathe >= 250) up = 0; if (breathe <= 5) up = 1;
- 使用同一个breathe变量控制所有通道
- 红色通道:从暗到亮(breathe)
- 绿色通道:从亮到暗(255 – breathe)
- 蓝色通道:半亮度(breathe / 2)
- 效果:红绿渐变,蓝色辅助的连续变化
随机闪烁 (mode 6)
SetColor(random(), random(), random()); Delay_ms(150);
- 调用random()生成RGB值(0-255)
- 每次随机设置颜色后延时150ms
- 效果:LED快速显示不同随机颜色
关闭LED (mode 7)
SetColor(0, 0, 0);
- RGB全部设置为0(全灭)
- LED熄灭
优化建议
- 增加按键消抖
- 使用硬件定时器改进PWM:
- 使用51单片机的定时器中断实现更精确的PWM
- 避免主循环被长时间阻塞
- 增加亮度平滑渐变:
- 在模式切换时添加过渡效果
- 避免颜色突变造成突兀感
- 保存最后模式:
- 在EEPROM保存最后选择的模式
- 重启后恢复之前的灯光效果