你所遇到的问题的确可能是因为在执行 display_sos() 函数时,按键扫描没有被及时处理,导致按第三下按键时,LED没有熄灭。这个问题的根本原因是按键处理函数在 display_sos() 运行时没有机会执行,因为你的代码是单线程顺序执行的。display_sos() 函数中包含了长时间的延时操作,导致在这段时间内程序不能响应按键的变化。
要解决这个问题,可以采用中断处理或者使用一个状态机来管理LED的状态,而不是在 display_sos() 函数中使用阻塞延时。以下是使用状态机的方法的简化思路:
1. 移除阻塞的延时将阻塞延时改为非阻塞计数器方式,这样主循环可以继续检查按键状态。
2. 使用状态机使用状态机来管理LED的不同状态(比如长亮、SOS、熄灭),并根据按键的状态来切换。
代码实现 #include <STC8.h>
#include <intrins.h>
sbit KEY = P3^5;
sbit LED = P3^4;
unsigned int LED_flag = 0;
unsigned int sos_step = 0;
unsigned int delay_counter = 0;
void Init_IO()
{
P0M1 = 0x00; P0M0 = 0x00;
P1M1 = 0x00; P1M0 = 0x00;
P2M1 = 0x00; P2M0 = 0x00;
P3M1 = 0x00; P3M0 = 0x00;
P4M1 = 0x00; P4M0 = 0x00;
P5M1 = 0x00; P5M0 = 0x00;
P6M1 = 0x00; P6M0 = 0x00;
P7M1 = 0x00; P7M0 = 0x00;
}
void Delay10ms()
{
unsigned char i, j, k;
i = 2; j = 56; k = 172;
do { do { while (--k); } while (--j); } while (--i);
}
void LED_SOS_Handler()
{
switch (sos_step)
{
case 0: case 2: case 4:
LED = 1; delay_counter = 20; sos_step++; break; // LED on for 200ms
case 1: case 3: case 5:
LED = 0; delay_counter = 20; sos_step++; break; // LED off for 200ms
case 6: case 8: case 10:
LED = 1; delay_counter = 50; sos_step++; break; // LED on for 500ms
case 7: case 9: case 11:
LED = 0; delay_counter = 50; sos_step++; break; // LED off for 500ms
case 12: case 14: case 16:
LED = 1; delay_counter = 20; sos_step++; break; // LED on for 200ms
case 13: case 15: case 17:
LED = 0; delay_counter = 20; sos_step++; break; // LED off for 200ms
case 18:
delay_counter = 200; sos_step = 0; LED_flag = 3; break; // Wait 2s, then turn off LED
}
}
void display()
{
if (LED_flag == 1)
{
LED = 1; // Turn on LED
}
else if (LED_flag == 2)
{
LED_SOS_Handler(); // Handle SOS signal
}
else if (LED_flag == 3)
{
LED = 0; // Turn off LED
}
}
void KeyScan()
{
if(KEY == 0)
{
Delay10ms();
if(KEY == 0)
{
LED_flag++;
if (LED_flag > 3) LED_flag = 0;
}
while (!KEY);
}
}
void main()
{
Init_IO();
LED = 0;
while (1)
{
KeyScan();
if (delay_counter > 0)
{
delay_counter--;
}
else
{
display();
}
}
}解释:LED_SOS_Handler() 函数按步骤控制LED闪烁,实现SOS信号。
display() 函数根据 LED_flag 的值控制LED行为。
延时计数器 delay_counter 用于代替阻塞延时,让主循环能继续执行按键扫描。
这种设计能够在处理LED行为的同时,继续监控按键输入,避免按键在特定情况下失效。