进阶五 按键切换不同led流水效果
功能概述
- 初始化:
- 初始化外部中断0(INT0)为边沿触发方式。
- 开启全局中断。
- LED显示模式:
crol()
:将P1口的LED向左旋转一位。cror()
:将P1口的LED向右旋转一位。blink()
:使所有LED闪烁(全亮和全灭交替)。off()
:关闭所有LED。
- 模式切换:
- 每次按下连接到INT0的按钮时,会切换到下一个LED显示模式。
- 模式循环为:左旋转 -> 右旋转 -> 闪烁 -> 关闭 -> 左旋转 ...
详细分析
- 中断初始化:
IT0 = 1;
:设置INT0为边沿触发方式。EX0 = 1;
:启用INT0中断。EA = 1;
:启用全局中断。
- LED控制函数:
crol()
:使用_crol_
函数将P1口的值左移一位。cror()
:使用_cror_
函数将P1口的值右移一位。blink()
:使所有LED闪烁,亮500毫秒,灭500毫秒。off()
:关闭所有LED。
- 主循环:
main()
函数中初始化中断后,进入无限循环,调用fst()
函数。fst()
函数根据count
的值选择相应的LED显示模式。
- 中断服务程序:
ex0_isr()
是INT0的中断服务程序。- 包含简单的去抖动处理,通过延时和再次检查引脚状态来防止机械开关的抖动。
- 每次中断触发时,
count
递增,并在达到4时重置为0,确保模式循环。
潜在问题和改进建议
- 去抖动处理:
- 当前的去抖动处理是简单的延时,可能不够完善。可以考虑使用硬件去抖动或更复杂的软件去抖动算法。
- LED状态:
- 在
ex0_isr()
中,P1=0x7f;
会强制设置P1口的状态,这可能会干扰其他模式。建议移除或根据需要调整。
- 在
- 模式循环:
- 当前的模式循环是0到3,确保
count
的范围始终在0到3之间。
- 当前的模式循环是0到3,确保
#include<reg51.h>
#include<intrins.h>typedef unsigned char uchar;
typedef unsigned int uint;volatile uint count = 0; // Added volatile since it's modified in ISRvoid ex0_init(void);
void crol(void);
void cror(void);
void blink(void);
void off(void);
void fst(void);
void delayms(uint);void delayms(uint x)
{uint i;while(x--){for(i=89;i>0;i--);}
}void crol(void)
{P1 = _crol_(P1, 1);delayms(500);
}void cror(void)
{P1 = _cror_(P1, 1); // Fixed function namedelayms(500);
}void blink(void)
{P1=0x00;delayms(500);P1=0xff;delayms(500);
}void off(void)
{P1=0xff;
}void fst(void)
{switch(count){case 0: crol(); break;case 1: cror(); break;case 2: blink(); break;case 3: off();break;default: count = 0;}
}void main()
{ex0_init(); // Initialize external interrupt onceP1=0x80;while(1){fst();}
}void ex0_init(void)
{IT0 = 1; // Edge-triggered interruptEX0 = 1; // Enable EX0 interruptEA = 1; // Enable global interrupts
}void ex0_isr(void) interrupt 0
{delayms(10); // 延时去抖动if(INT0 == 0) // 再次检查引脚状态{count++;if(count >= 4){count = 0;} } P1=0x7f;while(!INT0);}