单片机竞赛备赛笔记:决赛试题与过渡模拟一
笔记说明:本笔记涵盖了《决赛一 Led彩灯控制系统》与《过渡一 电压采集器》两大核心模块的考点、代码逻辑及避坑指南。
第一部分:决赛一 Led 彩灯控制系统
1. 核心算法:位移与循环
在流水灯控制中,位移是最基础的操作。
-
指令函数:
-
_crol_(变量, 位数):循环左移 (Circle Rotate Left)。特点:移出的位会补回到另一端(首尾相接)。 -
_cror_(变量, 位数):循环右移。 -
注意:使用前必须包含头文件
#include <intrins.h>。
-
2. 重要原则:寄存器保护机制
-
规则:严禁直接对
P0寄存器进行位移操作。 -
原因:P0 端口状态可能受到负载影响,或者直接操作会导致显示不稳定(鬼影)。
-
正确做法(中间变量法):
unsigned char Led_Temp = 0xFE; // 定义中间变量 Led_Temp = _crol_(Led_Temp, 1); // 在变量上运算 P0 = Led_Temp; // 最后赋值给硬件
3. 经典 Bug 修复:模式切换复位
-
问题描述:当从 模式 4(或其他复杂模式)切换回 模式 1 时,流水灯往往不是从第一个灯(L1)开始亮,而是接着上一次的位置。
-
解决方案:“切换即复位”。
if (Key_Value == S_Mode_Switch) { Mode++; if (Mode > 4) Mode = 1; // 关键点:切换模式时,强制重置中间变量 Led_Temp = 0xFE; P0 = Led_Temp; }
4. 数码管闪烁控制
-
全部闪烁:利用定时器产生的标志位(如
Seg_Star_Flag)控制所有位的显示。 -
覆盖闪烁(指定位闪烁):
-
利用
Set_Flag判断当前是在设置哪一位。 -
三目运算符逻辑:
C
// 如果 Flag为1显示数据,为0显示“熄灭码(10)” Seg_Buf[Index] = (Seg_Star_Flag) ? Real_Data : 10;
-
5. 按键逻辑优化
-
防连跳 (
else if):- 在状态切换逻辑中,必须使用
else if。如果不加else,CPU 会在一次扫描中连续执行多个if,导致模式直接从 1 跳到 3。
- 在状态切换逻辑中,必须使用
-
一键开关 (
^=):-
利用按位异或实现状态翻转(启动/停止)。
-
Run_Flag ^= 1;(0 变 1,1 变 0)。
-
-
按键长按:
-
核心是计时器。按下开始计时,抬起时判断计时时长。
-
if (Time > 1000ms)→ 执行长按功能;else→ 执行短按功能。
-
6. 硬件常识
- LED 逻辑:
0是 亮,1是 灭。(共阳极接法)
第二部分:过渡一 电压采集器 (进阶逻辑)
1. 输入限制与处理
-
输入位数限制:防止用户输入超过 4 位导致溢出。
if (Input_Index < 4) { // 限制只能输4位 Input_Val = Input_Val * 10 + Key_Value; // 移位累加算法 Input_Index++; } -
输入时闪烁:提示用户当前正在编辑。同样使用“面具法”(定时器标志位覆盖数据)。
2. 非阻塞闪烁 (避免卡死)
-
严禁使用 Delay:在数码管刷新或主循环中,绝对不能使用
Delay_ms(500)来做闪烁,这会卡死按键扫描。 -
正确做法:利用定时器中断翻转标志位
Flash_Flag,主循环只根据这个 Flag 决定显示还是熄灭。
3. 数值处理技巧
-
四舍五入保留两位:
-
单片机处理浮点数很慢,通常放大 100 倍用整数处理。
-
核心公式:
Result = (Raw_Data + 5) / 10;(加 5 是为了实现四舍五入)。
-
-
Float 显示在数码管:
-
不要用
%f打印。 -
手动点亮小数点:控制
Seg_Point数组,在特定位(如第 2 位)赋值 0 点亮小数点。
-
4. 界面美化:高位熄灭 (Leading Zero Suppression)
-
需求:显示
25而不是0025。 -
算法逻辑:从最高位(千位)开始扫描。
// 伪代码示例 if (千位 == 0) { 熄灭千位; if (百位 == 0) { 熄灭百位; // ...以此类推,注意个位通常不灭 } }
5. 业务逻辑:计数值增加条件
-
边缘检测(下降沿):题目要求“当电压从大于 Vp 变为小于 Vp 时,计数加 1”。
-
需要两个变量:
Voltage_Old(旧值) 和Voltage_New(新值)。 -
判断公式:
if (Voltage_Old > Vp && Voltage_New < Vp) { Count++; // 只有在这个瞬间才计数 }
-
6. 高阶 LED 状态指示
-
根据电压范围点亮不同的 LED(如 L1, L2, L3)。
-
注意逻辑互斥:使用
if ... else if ... else结构,确保同一时间只有一个状态生效,避免 LED 乱闪。
总结回顾 (Cheat Sheet)
-
位移用
_crol_,记得包含intrins.h。 -
切换模式记得复位中间变量。
-
闪烁不要用延时,要用定时器 Flag + 三目运算符。
-
按键切换状态必加
else if。 -
电压输入算法:
Val = Val * 10 + Key。 -
边缘检测要存旧值:
if (Old > Ref && New < Ref)。