第四周 总结笔记

第四周两套题笔记

:bar_chart: LED控制部分

四种炫酷的流水灯效果

switch (led_mode)
{
    // 模式1:从左向右流动(像跑马灯)
    case 0:
        if(ucled == 0x7e)          // 灯流到最右边了?
        {
            ucled = 0xfe;          // 回到最左边重新开始
        }
        else
        {
            ucled = _crol_(ucled, 1);  // 灯往右移一位
            if(ucled == 0x7e)      // 又流到最右边了?
            {
                led_mode = 1;      // 切换到下一个模式
            }
        }
        break;
  
    // 模式2:从右向左流动(倒着流)
    case 1:
        ucled = _cror_(ucled, 1);  // 灯往左移一位
        if(ucled == 0xfe)          // 回到最左边了?
        {
            led_mode = 2;          // 再换模式
        }
        break;
  
    // 模式3:两边向中间合拢(像关门)
    case 2:
        ucled = ucled_data[ucled_data_index];  // 从预设的"关门"图案中取一个
        ucled_data_index++;                    // 准备显示下一幅图案
        if(ucled_data_index == 4)              // 4幅图都显示完了?
        {
            led_mode = 3;                      // 切换到"开门"模式
            ucled_data_index = 3;              // 从最后一幅图开始往回放
        }
        break;
  
    // 模式4:中间向两边展开(像开门)
    case 3:
        ucled = ucled_data[ucled_data_index];  // 从预设的"开门"图案中取一个
        ucled_data_index--;                    // 往回取图案
        if(ucled_data_index == 255)            // 已经取到第一个了?
        {
            led_mode = 0;                      // 回到模式1重新开始
            ucled_data_index = 0;              // 从头开始
        }
        break;
}

通俗理解:LED有4种花样玩法,自动轮流切换,就像灯光秀一样!

:1234: 数字处理技巧

四舍五入的小窍门

// 想把3.141变成3.14(四舍五入到两位小数)
电压 = (3141 + 5) / 1000.0;  // 先加5毫伏,再除以1000
// 结果是3.146,但显示时会截成3.14

为什么加5? 因为我们是四舍五入,加5等于在千分位上加0.005,这样刚好实现四舍五入的效果。

保留两位小数的方法

// 方法1:直接砍掉多余的小数位
int 临时变量 = (int)(3.141 * 100);  // 3.141×100=314.1,取整→314
float 结果 = 临时变量 / 100.0;      // 314÷100=3.14

// 方法2:真正的四舍五入
int 临时变量 = (int)(3.141 * 100 + 0.5);  // 3.141×100+0.5=314.6,取整→315
float 结果 = 临时变量 / 100.0;            // 315÷100=3.15

:high_voltage: 三目运算符(问号冒号运算符)

// 问号运算符:如果...就...否则...
Seg_Buf[位置] = Seg_Flag ? 显示数字 : 显示空白;

// 相当于:
if(Seg_Flag == 1) {
    Seg_Buf[位置] = 显示数字;
} else {
    Seg_Buf[位置] = 显示空白;
}

使用场景:在输入电压时,让当前输入位置一闪一闪的,提示用户该输入哪里了。

:wrench: 常用编程符号

不等于符号(!=)

if(a != b)  // 如果a不等于b
{
    // 执行这里
}

if-else 家族的区别

类型 用途 例子
if-else 二选一 如果是白天就开灯,否则关灯
if-else if 多选一 成绩≥90为A,≥80为B,≥70为C,否则D

:input_latin_uppercase: 数码管显示秘籍

常用字符编码表

0-9 :数字0到9
10  :什么都不显示(空白)
11  :减号(-)
12  :字母U(表示电压)
13  :字母P(表示参数)
14  :字母n(表示数量)

:bullseye: 计数显示优化

去掉多余的零

原始显示:n 0 0 1 2 3
优化后:  n    1 2 3

代码实现

// 从左边开始检查,遇到0就换成空白
while(显示数组[位置] == 0)
{
    显示数组[位置] = 10;  // 10表示空白
    位置++;
    if(位置 == 5) break;  // 检查到十位就停止
}
// 注意:个位的0要保留,因为0也是一个有效的数字

:light_bulb: LED状态指示灯

三个LED的不同含义

void Led_Proc()
{
    // LED0:电压过低警报灯
    if(电压 < 设定电压) {
        if(计时 >= 5000)     // 等了5秒钟
            LED0 = 1;        // 点亮报警灯
    } else {
        计时 = LED0 = 0;     // 电压正常,关灯
    }
  
    // LED1:计数奇偶指示灯
    LED1 = 计数 % 2;  // 计数是奇数时亮,偶数时灭
  
    // LED2:操作错误提示灯
    LED2 = 错误次数 / 3;  // 连错3次以上就亮
}

:alarm_clock: 系统心跳——定时器中断

1毫秒定时器做什么?

void Timer0Server() interrupt 1
{
    // 1. 按键防抖:每10ms才检查一次按键
    if(++按键计时 == 10) 按键计时 = 0;
  
    // 2. 显示更新:每500ms才更新一次显示内容
    if(++显示计时 == 500) 显示计时 = 0;
  
    // 3. 数码管扫描:轮流点亮6个数码管
    if(++数码管位置 == 6) 数码管位置 = 0;
    点亮数码管(数码管位置, 要显示的数字, 小数点);
  
    // 4. LED扫描:轮流控制8个LED
    if(++LED位置 == 8) LED位置 = 0;
    控制LED(LED位置, 亮灭状态);
  
    // 5. 低电压计时
    if(电压 < 设定电压) 计时器++;
  
    // 6. 闪烁控制:每500ms切换一次
    if(++闪烁计时 == 500) {
        闪烁计时 = 0;
        闪烁标志 = !闪烁标志;  // 0变1,1变0
    }
}

通俗理解:定时器就像乐队的指挥,每1毫秒挥一下指挥棒,让不同的乐器(按键、显示、LED)按节奏演奏。

:circus_tent: 显示驱动函数

数码管显示函数

// 点亮指定的数码管,显示指定的内容
点亮数码管(第几个管, 显示什么, 要不要小数点);
// 例子:点亮第3个数码管,显示数字5,带小数点
点亮数码管(3, 5, 1);

LED显示函数

// 控制指定的LED亮或灭
控制LED(第几个灯, 亮还是灭);
// 例子:点亮第2个LED
控制LED(2, 1);

:clipboard: 总结表格

功能 实现方法 通俗理解
按键处理 10ms检查一次 防止手抖按太快
数码管显示 6个数码管轮流点亮 6个演员轮流上台
LED控制 8个LED轮流控制 8个灯泡轮流闪
输入提示 500ms闪烁一次 一闪一闪提示你
错误提示 连错3次亮灯 老师提醒你错了
电压报警 低电压5秒后亮灯 电压太低会报警

:graduation_cap: 学习要点

  1. 分层设计:底层驱动和上层逻辑分开
  2. 定时扫描:用定时器统一管理时间
  3. 状态机:用状态变量控制不同模式
  4. 用户友好:有提示、有反馈、防止误操作
  5. 代码复用:同样的功能写成函数,多处调用

终极秘诀:把复杂的系统拆分成简单的小模块,每个模块做好一件事,然后让定时器像心脏一样有节奏地推动整个系统运行!

1 个赞