九层妖塔 起于垒土
J5
的2
和3
相连,即为独立键盘模式(BTN)。
按键S7,S6,S5,S4用作独立按键,分别对应P30,P31,P32,P33
●代码:
//独立按键--普通软件延时消抖
#include
#include
#define uchar unsigned char
#define uint unsigned int
sbit S4 = P3^3;
uchar SEG_Array[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//数码管段码
uchar yi,er,san,si,wu,liu,qi,ba;
uchar LED_num; //LED流水计数标志
void All_Init(void); //开发板初始化
void SEG_Init(void); //数码管初始化,熄灭所有数码管
void Delay1ms(); //@11.0592MHz
void Delay10ms(); //@11.0592MHz
void SEG_1_2(uchar yi,uchar er);//数码管1,2驱动
void LED_Water(void); //按键LED流水灯驱动
void main(void)
{
All_Init(); //开发板初始化
while(1)
{
if(S4==0)
{
Delay10ms();
if(S4==0)
{
LED_num++;
if(LED_num==10) LED_num=0;
while(!S4);
}
}
LED_Water();
SEG_1_2(LED_num,2);
SEG_Init();
}
}
//-------------------------------延时-------------------------------//
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
void Delay10ms() //@11.0592MHz
{
unsigned char i, j;
i = 108;
j = 145;
do
{
while (--j);
} while (--i);
}
//----------------------------------初始化---------------------------------//
//----------------------------------开发板初始化--------------------------//
void All_Init(void)
{
P2&=0X1F; //关573
P0=0XFF; //预送数据
P2|=0X80;
P2&=0X9F; //开LED的573
P0=0XFF; //关LED
P2&=0X1F; //关573
P2&=0X1F; //关573
P0=0X00; //预送数据
P2|=0XA0;
P2&=0XBF; //开蜂鸣器继电器的573
P0=0X00; //关蜂鸣器,继电器
P2&=0X1F; //关573
P2&=0X1F; //关573
P0=0X00; //预送数据
P2|=0XC0;
P2&=0XDF; //开数码管位选573
P0=0X00; //位选,全部不选
P2&=0X1F; //关573
P2&=0X1F; //关573
P0=0XFF; //预送数据
P2|=0XE0;
P2&=0XFF; //开数码管段选573
P0=0XFF;
P2&=0X1F; //关573
}
//----------------------------------数码管初始化--------------------------//
void SEG_Init(void) //关闭熄灭所有数码管
{
P2&=0X1F; //关573
P0=0X00; //预送数据
P2|=0XC0;
P2&=0XDF; //开数码管位选573
P0=0X00; //位选,全部不选
P2&=0X1F; //关573
P2&=0X1F; //关573
P0=0XFF; //预送数据
P2|=0XE0;
P2&=0XFF; //开数码管段选573
P0=0XFF;
P2&=0X1F; //关573
}
//------------------------------------动态数码管驱动-----------------------//
//------------------------------------动态数码管驱动------第一二个---------//
void SEG_1_2(uchar yi,uchar er)
{
//-------第一个数码管---------//
P2&=0X1F; //关573
P0=SEG_Array[yi]; //预送段选数据
P2|=0XE0;
P2&=0XFF; //开数码管段选573
P0=SEG_Array[yi]; //送段选数据
P2&=0X1F; //关573
P0=0X00; //消影
P2|=0XC0;
P2&=0XDF; //开数码管位选573
P0=0X01; //送位选数据
P2&=0X1F; //关573
Delay1ms();
//-------第二个数码管---------//
P2&=0X1F; //关573
P0=SEG_Array[er]; //预送段选数据
P2|=0XE0;
P2&=0XFF; //开数码管段选573
P0=SEG_Array[er]; //送段选数据
P2&=0X1F; //关573
P0=0X00; //消影
P2|=0XC0;
P2&=0XDF; //开数码管位选573
P0=0X02; //送位选数据
P2&=0X1F; //关573
Delay1ms();
}
//-------------------------------按键流水灯驱动--------------//
void LED_Water(void)
{
P2&=0X1F; //关573
P0=0XFF; //预送数据
P2|=0X80;
P2&=0X9F; //开LED的573
P0=~(0X01<<LED_num);
P2&=0X1F; //关573
}
●流程图:
●松手检查:while(!KEY)
等待按键释放。等按键确认释放后再去执行相应代码。防止重入。
●CPU在按键按下抖动时进行10ms的软件延时消抖,在数百ms的稳定期以及松手抖动时停滞在松手检测while(!KEY)
中,占用CPU资源过多;也就是在整个按键检测期间内,没有再执行其他指令。
●按键检测时是借助while(1)
死循环进行反复检测。
●若是采用普通软件延时消抖10ms的软件延时和松手检测都会占用CPU资源,对其它同样借助while(1)
死循环进行反复运行的模块代码产生了挤占影响,比如动态数码管。
●稳定期取决于是否松手,若不松手,则数码管将一直保持进入按键检测前最后一次对数码管的操作。
●代码:
//独立按键--标志位软件延时消抖
#include
#include
#define uchar unsigned char
#define uint unsigned int
sbit S4 = P3^3;
uchar SEG_Array[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//数码管段码
uchar yi,er,san,si,wu,liu,qi,ba;
uchar LED_num; //LED流水计数标志
uchar S4_down; //S4按键按下标志位
void All_Init(void); //开发板初始化
void SEG_Init(void); //数码管初始化,熄灭所有数码管
void Delay1ms(); //@11.0592MHz
void Delay10ms(); //@11.0592MHz
void SEG_1_2(uchar yi,uchar er);//数码管1,2驱动
void LED_Water(void); //按键LED流水灯驱动
void main(void)
{
All_Init(); //开发板初始化
while(1)
{
if(S4==0 && S4_down==0)
{
Delay10ms();
if(S4==0)
{
S4_down=1;
}
}
if(S4==1 && S4_down==1)
{
Delay10ms();
if(S4==1)
{
S4_down=0;
LED_num++;
if(LED_num==10) LED_num=0;
}
}
LED_Water();
SEG_1_2(LED_num,2);
SEG_Init();
}
}
//-------------------------------延时-------------------------------//
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
void Delay10ms() //@11.0592MHz
{
unsigned char i, j;
i = 108;
j = 145;
do
{
while (--j);
} while (--i);
}
//----------------------------------初始化---------------------------------//
//----------------------------------开发板初始化--------------------------//
void All_Init(void)
{
P2&=0X1F; //关573
P0=0XFF; //预送数据
P2|=0X80;
P2&=0X9F; //开LED的573
P0=0XFF; //关LED
P2&=0X1F; //关573
P2&=0X1F; //关573
P0=0X00; //预送数据
P2|=0XA0;
P2&=0XBF; //开蜂鸣器继电器的573
P0=0X00; //关蜂鸣器,继电器
P2&=0X1F; //关573
P2&=0X1F; //关573
P0=0X00; //预送数据
P2|=0XC0;
P2&=0XDF; //开数码管位选573
P0=0X00; //位选,全部不选
P2&=0X1F; //关573
P2&=0X1F; //关573
P0=0XFF; //预送数据
P2|=0XE0;
P2&=0XFF; //开数码管段选573
P0=0XFF;
P2&=0X1F; //关573
}
//----------------------------------数码管初始化--------------------------//
void SEG_Init(void) //关闭熄灭所有数码管
{
P2&=0X1F; //关573
P0=0X00; //预送数据
P2|=0XC0;
P2&=0XDF; //开数码管位选573
P0=0X00; //位选,全部不选
P2&=0X1F; //关573
P2&=0X1F; //关573
P0=0XFF; //预送数据
P2|=0XE0;
P2&=0XFF; //开数码管段选573
P0=0XFF;
P2&=0X1F; //关573
}
//------------------------------------动态数码管驱动-----------------------//
//------------------------------------动态数码管驱动------第一二个---------//
void SEG_1_2(uchar yi,uchar er)
{
//-------第一个数码管---------//
P2&=0X1F; //关573
P0=SEG_Array[yi]; //预送段选数据
P2|=0XE0;
P2&=0XFF; //开数码管段选573
P0=SEG_Array[yi]; //送段选数据
P2&=0X1F; //关573
P0=0X00; //消影
P2|=0XC0;
P2&=0XDF; //开数码管位选573
P0=0X01; //送位选数据
P2&=0X1F; //关573
Delay1ms();
//-------第二个数码管---------//
P2&=0X1F; //关573
P0=SEG_Array[er]; //预送段选数据
P2|=0XE0;
P2&=0XFF; //开数码管段选573
P0=SEG_Array[er]; //送段选数据
P2&=0X1F; //关573
P0=0X00; //消影
P2|=0XC0;
P2&=0XDF; //开数码管位选573
P0=0X02; //送位选数据
P2&=0X1F; //关573
Delay1ms();
}
//-------------------------------按键流水灯驱动--------------//
void LED_Water(void)
{
P2&=0X1F; //关573
P0=0XFF; //预送数据
P2|=0X80;
P2&=0X9F; //开LED的573
P0=~(0X01<<LED_num);
P2&=0X1F; //关573
}
●波形图:
●通过引入按下标志位,省去了while(!KEY)
的松手检测,将按下时稳定期的数百ms释放出来,只占用了按下和松手时的共20ms的消抖时间。
●若采用10ms消抖,按下和松手时刻,数码管仍然会有轻微闪动。
//独立按键--标志位软件延时消抖
sbit S4 = P3^3;
sbit S5 = P3^2;
sbit S6 = P3^1;
sbit S7 = P3^0;
void keyscan_4(void); //独立按键扫描
//-------------------------------------独立按键扫描---------------------//
void keyscan_4(void)
{
static uchar S4_down,S5_down,S6_down,S7_down; //S4-S7独立按键按下标志位
if(S4==0 && S4_down==0) //S4
{
Delay10ms();
if(S4==0)
{
S4_down=1;
}
}
if(S4==1 && S4_down==1)
{
Delay10ms();
if(S4==1)
{
S4_down=0;
SEG_num1++;
if(SEG_num1==10) SEG_num1=0;
}
}
if(S5==0 && S5_down==0) //S5
{
Delay10ms();
if(S5==0)
{
S5_down=1;
}
}
if(S5==1 && S5_down==1)
{
Delay10ms();
if(S5==1)
{
S5_down=0;
SEG_num2++;
if(SEG_num2==10) SEG_num2=0;
}
}
if(S6==0 && S6_down==0) //S6
{
Delay10ms();
if(S6==0)
{
S6_down=1;
}
}
if(S6==1 && S6_down==1)
{
Delay10ms();
if(S6==1)
{
S6_down=0;
SEG_num3++;
if(SEG_num3==10) SEG_num3=0;
}
}
if(S7==0 && S7_down==0) //S7
{
Delay10ms();
if(S7==0)
{
S7_down=1;
}
}
if(S7==1 && S7_down==1)
{
Delay10ms();
if(S7==1)
{
S7_down=0;
SEG_num4++;
if(SEG_num4==10) SEG_num4=0;
}
}
}
参考1
参考2
参考3
参考4
参考5