蓝桥杯单片机第三周笔记

蓝桥杯单片机第三周学习笔记

本周核心围绕电子钟程序实现展开,复现过程中遇到多个典型问题,同时掌握并巩固了单片机开发的关键基础逻辑,以下为问题复盘与核心知识点总结:

一、复现程序遇到的问题及解决方法

问题 1:按键 5/6 位数加减,三目运算符逻辑卡顿

按键 5 实现位数加、按键 6 实现位数减,核心是通过三目运算符判断小时 / 分钟的边界值(小时 0-23、分钟 0-59),复现时遗忘三目运算书写逻辑,需重点记忆。

case 5:  // 位数加,Seg_Mode1=时钟设置,Seg_Mode2=闹钟设置
    if (Seg_Mode == 1) {
        Clock_Set[Clock_Set_Index]++;
        // 索引0=小时(边界24),非0=分钟(边界60),达到边界置0
        if(Clock_Set[Clock_Set_Index] == (Clock_Set_Index == 0?24:60)) Clock_Set[Clock_Set_Index] = 0;
    }
    if (Seg_Mode == 2) {
        Alarm[Clock_Set_Index]++;
        if(Alarm[Clock_Set_Index] == (Clock_Set_Index == 0?24:60)) Alarm[Clock_Set_Index] = 0;
    }
    break;
case 6:  // 位数减,unsigned char减到0再减为255,以此为判断条件
    if(Seg_Mode == 1) {
        Clock_Set[Clock_Set_Index]--;
        if(Clock_Set[Clock_Set_Index] == 255) Clock_Set[Clock_Set_Index] = (Clock_Set_Index == 0?23:59);
    }
    if (Seg_Mode == 2) {
        Alarm[Clock_Set_Index]--;
        if(Alarm[Clock_Set_Index] == 255) Alarm[Clock_Set_Index] = (Clock_Set_Index == 0?23:59);
    }
    break;

问题 2:闹钟响铃 LED1s 周期闪烁,LED_Proc 与时间函数联动缺失

需通过中间变量(Alarm_Ring/LED) 实现两个函数的联动,复现时没想到中间变量的桥梁作用,解决后逻辑清晰:先通过标志位判断闹钟是否响铃,再由时间函数控制中间变量实现闪烁。

void LED_Proc() {
    // 时钟时间与闹钟时间完全匹配,置响铃标志位
    if (Clock_Seg[0] == Alarm_Set[0] && Clock_Seg[1] == Alarm_Set[1] && Clock_Seg[2] == Alarm_Set[2]) {
        Alarm_Ring = 1;
    }
    if (Alarm_Ring == 1) {  // 响铃时控制LED闪烁
        P2_3 = 0;  // 开启LED控制
        P1 = LED;  // 中间变量LED由时间函数控制,实现闪烁
    } else {  // 未响铃时关闭所有LED
        P2_3 = 1;
        P1 = 0xff;
    }
}

问题 3:闹钟响铃段位闪烁,多余条件导致 bug + 异或逻辑遗忘

问题点:

  1. 多余添加Alarm_Ring == 1判断,导致非目标段位常亮;

  2. 没想到通过异或赋值实现段位闪烁(0x0f 控制低四位、0xf0 控制高四位)。

核心逻辑:

根据小时是否≥12,分别控制前四位 / 后四位闪烁,依托 500ms 定时器实现 1s 周期(两次 500ms 异或完成一次亮灭)。

if (++Timer_500ms == 500) {
    Timer_500ms = 0;
    Seg_Flag ^= 1;
    if (Clock_Seg[0] < 12) {
        LED ^= 0x0f;  // 小时<12,低四位(后四位)闪烁
    } else if(Clock_Seg[0] >= 12) {
        LED ^= 0xf0;  // 小时≥12,高四位(前四位)闪烁
    }
}

二、已掌握需重点巩固的核心逻辑

1. 1s 周期执行语句实现(时间函数核心)

定义毫秒级定时器变量,自增到 1000 时置 0,后续紧跟需执行的语句,即可实现非阻塞 1s 周期执行,是定时操作的基础方法。

if (++Timer_1000ms == 1000) {
    Timer_1000ms = 0;
    // 此处添加1s周期需要执行的代码
}

2. 按键 / 数码管非阻塞性减速(防抖动 / 降刷新)

通过减速标志位 + 时间函数计数实现非阻塞延时,避免程序卡死,可灵活调整延时时间,提升按键响应与显示屏稳定性。

步骤 1:在 Proc 函数中添加减速判断

void Seg_Proc() {
    if(Seg_Slow_Down) return;  // 未到延时时间,直接返回
    Seg_Slow_Down = 1;         // 到延时时间,执行后续逻辑并置1
    // 数码管刷新核心代码
}

void Key_Proc() {
    if(Key_Slow_Down) return;
    Key_Slow_Down = 1;
    // 按键扫描核心代码
}

步骤 2:在时间函数中添加计数清零语句

// 按键10ms减速(防抖动),数码管500ms减速(降刷新)
if (++Key_Slow_Down == 10) Key_Slow_Down = 0;
if (++Seg_Slow_Down == 500) Seg_Slow_Down = 0;

关键技巧:

修改==后的数值,即可调整延时毫秒数,数值越小,响应 / 刷新速度越快。

3. 多模式开发核心原则

不同模式需定义独立变量,禁止共用

若多个模式(如时钟模式 / 闹钟模式 / 设置模式)共用同一变量,修改一个模式的变量值会直接影响其他模式的逻辑运行,导致程序混乱,需谨记并养成习惯。