彩灯控制系统编程笔记
项目概述
彩灯控制系统 ——实现LED灯的不同流转模式,配合按键控制、数码管显示和参数设置功能。
一、按键控制技巧
1.1 避免按键重复执行问题
问题 :按键按下后默认会多执行一次
要求 :S6为"设置"键,按顺序切换:运行界面 → 模式设置 → 时间设置 → 保存退出
// 核心逻辑:if-else结构确保每次按键只执行一个分支
unsigned char Seg_Disp_Mode; // 0-运行界面 1-设置界面 2-数据界面
case 6: // S6设置键
if(Seg_Disp_Mode == 0) // 第一次按:进入设置
{
for(i=0;i<4;i++)
Led_Time_Set[i] = Led_Time_Data[i]; // 备份当前数据
Seg_Disp_Mode = 1; // 进入设置界面
}
else if(Seg_Disp_Mode == 1) // 已在设置界面中
{
Set_Flag ^= 1; // 切换设置项:0=模式编号 1=流转间隔
if(Set_Flag == 0) // 第三次按:保存并退出
{
for(i=0;i<4;i++)
Led_Time_Data[i] = Led_Time_Set[i]; // 保存设置
Seg_Disp_Mode = 0; // 返回运行界面
}
}
break;
执行流程 :
按键1 → 进入设置(模式编号) → Set_Flag=0
按键2 → 切换项(流转间隔) → Set_Flag=1
按键3 → 保存退出 → Set_Flag=0 → 返回运行界面
1.2 按键长按功能
要求 :S4在系统停止时长按显示数据,松手恢复
bit Data_Disp_Flag; // 0=状态界面 1=数据界面
if(System_Flag == 0) // 系统暂停状态
{
if(Key_Old == 4 && Seg_Disp_Mode == 0)
Data_Disp_Flag = 1; // 长按S4显示数据
else
Data_Disp_Flag = 0; // 其他情况显示状态
}
else
Data_Disp_Flag = 0; // 运行状态只显示状态界面
二、数码管显示技巧
2.1 数码管闪烁效果
要求 :当前选中项以0.8秒间隔亮灭(0.4秒亮,0.4秒灭)
// 设置界面显示
case 1: // 流转时间设置界面
// 正常显示所有内容
Seg_Buf[0] = 13; // 特殊字符
Seg_Buf[1] = Led_Time_Set_Index + 1; // 模式编号
Seg_Buf[2-5] = 时间值的千/百/十/个位;
// 根据选择项设置闪烁
if(Set_Flag == 0) // 选中模式编号
{
Seg_Buf[0] = Seg_Star_Flag ? 13 : 10; // 10=熄灭
Seg_Buf[1] = Seg_Star_Flag ? (Led_Time_Set_Index+1) : 10;
}
else // 选中流转间隔
{
// 四个时间位同时闪烁
for(i=2; i<=5; i++)
Seg_Buf[i] = Seg_Star_Flag ? 原值 : 10;
}
break;
2.2 闪烁定时控制
// 400ms触发一次,0.8秒一个完整周期
if(++Timer_400Ms == 400)
{
Timer_400Ms = 0;
Seg_Star_Flag ^= 1; // 取反:0→1→0→1...
}
2.3 高位灭零处理
i = 0;
while(Seg_Buf[i] == 0) // 高位为0时熄灭
{
Seg_Buf[i] = 10; // 10表示熄灭
i++;
if(i >= 数码管位数) break; // 防止越界
}
三、LED控制技巧
unsigned char Led_Pos; // LED位置变量
unsigned char Led_Mode; // 当前模式0-3
switch(Led_Mode)
{
case 0: // 模式1:L1→L8顺序点亮
if(++Led_Pos == 8) // 每次+1,到8时切换
{
Led_Pos = 7; // 为模式2准备:从L8开始
Led_Mode = 1; // 切换到模式2
}
// LED显示:1<<Led_Pos 对应的LED亮
break;
case 1: // 模式2:L8→L1逆序点亮
if(--Led_Pos == 255) // 每次-1,减到-1(255)时切换
{
Led_Pos = 7; // 注意:7=0111(L8和L1的中间状态)
Led_Mode = 2; // 切换到模式3
}
break;
case 2: // 模式3:对称外扩 07→16→25→34
Led_Pos += 9; // 神奇的数字9!让两个灯对称移动
if(Led_Pos > 34) // 超过最大对称位置
{
Led_Pos = 34; // 模式4起始:34对称(L3,L4亮)
Led_Mode = 3; // 切换到模式4
}
break;
case 3: // 模式4:对称内缩 34→25→16→07
Led_Pos -= 9; // 反向减9
if(Led_Pos > 200) // 无符号数减到小于0会变成255
{
Led_Pos = 0; // 模式1起始:L1亮
Led_Mode = 0; // 切换回模式1,完成循环
}
break;
}
其中亮灯操作如下
if(Led_Mode<=1)//系统处于前两种流转模式
{
for(i==0;i<8;i++)
{
ucLed[i]=(i==Led_Pos);
}
}
else//处于后两种流转模式
{
for(i==0;i<8;i++)
{
ucLed[i]=(i==(Led_Pos/10))||(i==(Led_Pos%10));
}
}
数字9的奥秘
为什么用±9 实现对称移动?
二进制思考: 原始位置 左移1位 结果(对称位置)
00000111 (7) → 00010000 (16) = 差9
00010000 (16) → 00011001 (25) = 差9
00011001 (25) → 00100010 (34) = 差9
五、编程要点总结
- 按键防抖 :使用
if-else结构避免重复执行 - 状态管理 :合理使用标志位(
bit类型) - 显示优化 :闪烁效果、高位灭零
- 数据安全 :设置时先备份,确认后再保存
- 模式循环 :注意模式切换时的状态初始化
小提示 :调试时可以先固定时间间隔,测试单个模式,确保每个LED都能正确点亮,再组合成完整系统。