文章内容如有错误或排版问题,请提交反馈,非常感谢!
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保存最后选择的模式
- 重启后恢复之前的灯光效果



