第十三届省赛(第一场)刷题总结

第十三届省赛 - Led_Proc 刷题总结

一、题目需求拆解

Led_Proc 承载了 3个LED指示 + 继电器控制 共4个子功能:

功能 触发条件 行为
L2 工作模式指示 Work_Mode == 0(温控模式) 常亮;否则灭
继电器(温控) 温控模式下,温度 >= 参数 开启继电器
L1 整点指示 分==0 且 秒==0 亮 5 秒后熄灭
继电器(整点) 定时模式(Work_Mode==1)下整点 开启 5 秒
L3 继电器状态 Relay_Enable == 1 100ms 翻转闪烁;继电器关则灭

二、实现思路逐段分析

2.1 L2 + 温控继电器(互斥两模式)

if(Work_Mode == 0)          // 温度控制模式
{
    ucLed[1] = 1;           // L2 常亮
    if(Temperature_10x/10 >= Temperature_Parameter)
        Relay_Enable = 1;   // 温度 >= 参数 → 开继电器
    else
        Relay_Enable = 0;
}else                       // 定时控制模式
{
    ucLed[1] = 0;           // L2 灭
    // 注意:这里不操作 Relay_Enable
    // 定时模式下继电器由下方整点逻辑控制
}

要点:

  • Temperature_10x 是温度放大10倍的值(如 25.6°C → 256),除以10得到整数部分与参数比较
  • 温控模式下继电器由温度实时决定开关
  • 定时模式下此处不干预 Relay_Enable,留给整点逻辑处理

2.2 整点检测(触发 5 秒计时)

if((ucRtc[1] == 0) && (ucRtc[2] == 0))   // 分==0 且 秒==0
{
    Time5000_Flag = 1;                     // 置标志,启动5s倒计时
}

要点:

  • 仅做置位,不做清零 → 标志一旦置1,由后续超时逻辑自行清除
  • Led_Proc 每1ms执行一次,整点那1秒内会反复进入,但 Time5000_Flag 已经是1,重复赋值无副作用
  • Timer5000 在中断里自增(见 ISR),这里只负责启停

2.3 整点 5 秒动作(L1 + 定时继电器)

if(Time5000_Flag == 1)
{
    if(Work_Mode == 1) Relay_Enable = 1;   // 定时模式 → 开继电器
    ucLed[0] = 1;                          // L1 亮

    if(Timer5000 == 5000)                  // 5000ms = 5秒到
    {
        ucLed[0] = 0;                      // L1 灭
        Time5000_Flag = 0;                 // 清标志
        Timer5000 = 0;                     // 清计数
        Relay_Enable = 0;                  // 关继电器
    }
}

要点:

  • Timer5000 由 1ms 中断累加,到 5000 即 5 秒
  • 超时后一次性清理所有状态:标志、计数器、继电器、LED
  • 温控模式下也会亮 L1(ucLed[0]=1 不受 Work_Mode 限制),但继电器仅在定时模式下由此开启

2.4 L3 继电器闪烁指示

if(Relay_Enable)
{
    if(Timer100 == 100)     // 100ms 到
    {
        Timer100 = 0;       // 清计数
        ucLed[2] ^= 1;     // L3 翻转
    }
}else ucLed[2] = 0;        // 继电器关 → L3 立刻灭

要点:

  • Timer100 同样由 1ms 中断累加,到 100 即 100ms
  • ^= 1 异或翻转实现闪烁,周期 = 100ms×2 = 200ms
  • 继电器关闭瞬间 L3 立刻熄灭(不等下一个周期)

三、配合的中断代码

void Timer1_Isr(void) interrupt 3
{
    // ... 数码管扫描 ...

    if(Time5000_Flag == 1)  Timer5000++;   // 整点5秒计时
    if(Relay_Enable)        Timer100++;    // 闪烁100ms计时

    Relay(Relay_Enable);    // 继电器实际输出
    Led_Disp(ucLed);        // LED实际输出
}

关键设计:

  • 计时器(Timer5000/Timer100)在中断中累加,保证精度
  • 比较判断在主循环 Led_Proc 中执行,避免中断处理过长
  • Relay()Led_Disp() 在中断中调用,实现1ms级刷新

四、编程模式总结

4.1 标志位 + 计时器模式

整点检测 → 置 Flag=1 → 中断累加计时器 → 主循环判超时 → 清 Flag + 清计时器

这是蓝桥杯中延时动作的标准范式,适用于:

  • 整点动作(本题)
  • 按键长按计时
  • 报警持续时间

4.2 异或翻转闪烁

ucLed[x] ^= 1;   // 每个周期翻转一次

比用计数器判奇偶更简洁。注意闪烁实际周期 = 定时周期 × 2

4.3 分层架构

层级 职责 执行环境
决策层 Led_Proc 设置 ucLed[]Relay_Enable 主循环(1ms调度)
驱动层 Led_Disp()Relay() 操作硬件 定时器中断(1ms)
计时层 Timer5000++Timer100++ 定时器中断(1ms)

决策和驱动分离,主循环只写数组/标志,中断只读数组/标志并输出硬件,避免竞态。


五、易错点

  1. 整点重复触发Led_Proc 每1ms执行一次,整秒内会反复检测到 分==0 && 秒==0。靠 Time5000_Flag 的"已置位则无副作用"来规避,但 Timer5000 在中断中持续累加,不会被重置(因为清零只在5秒到时)。
  2. 两个模式对继电器的冲突:温控模式下 Relay_Enable 由温度实时控制,但整点超时清零时会强制 Relay_Enable = 0。如果此时温度仍高于参数,下一轮 Led_Proc 会立刻再次置1 → 实际表现为继电器闪断一瞬。
  3. Timer100 不清零:当 Relay_Enable 从0变1时,Timer100 可能残留上次的值,导致首次闪烁周期不准。建议在 Relay_Enable 置1时同时清零 Timer100
1 个赞