题目要求
按键计数:
1.
用普通按键、数码管实现对于按键的计数
(范围
0 - 100
)
2.数码管在全程不可存在肉眼可见的熄灭
3.对按键连续快按,系统能正常计数
4.两个按键(按键
1
与按键
2
)分别实现加与减
5.加到
100
再加后变为
0
重新加,减到
0
后再减也是
0
6.对按键
1
长按,系统能保持固定频率加一
7.对按键
2
长按,系统只会减一,除非下一次按下
8.计数掉电保存
题目的解读
题目可以分为两个部分
单机的加减与长按的连加连减
我们先讨论单机的加减再讨论讨论如何实现按键的连加与连减的
单机加减的实现
单机加减中有一个需要注意的地方就是
总体思路为定义一个变量count
当按键加按下时,count++,按键减按下时count-- ;
达到100时取余,为零时判断
连击加减的实现
代码部分
主函数
#include <REGX52.H>
#include "Key.h"
#include "Show.h"
#include "I2C.h"
#include "AT24C02.h"
#include "Timer0.h"
#include "Delay.h"
#include "Nixie.h"
unsigned char Number,count;
unsigned char ge,shi,bai,i,j;
extern unsigned char Long_Press,Minor_Press;//外部变量不可赋值只能在定义处赋值
void main()
{ Timer0_Init();
count=18; //计数值
while(1)
{
ShowNum(count);//刷新处
Number=Key();
if(Number==1)
{
there: //防止出现加到100不能减的情况
count++;
ShowNum(count);
if(count==101)//101即为0
{
count=0;
Number = Key();
if(Number==1)
{
count=0;
}
else goto here;
}
}
if(Number==2)
{
here:
count--;
ShowNum(count);
if(count==-1)
{
Number=Key();
if(Number==2)
{
count=0;
}
else goto there;
}
}
if(Number==3)
{
AT24C02_WriteByte(1,count);//写入数据局与读出数据
Delay(5);
}
if(Number==4)
{
count=AT24C02_ReadByte(1);
}
if(count>=101){ count=0;} //连加并未有按键持续按下
if(count<=-1){count=100;} //因此在这里再加判断来解决
}
}
void Timer0_Routine(void) interrupt 1 //中断程序代码1ms
{
static unsigned int T0Count1=0,T0Count2=0,T0Count3=0,T0Count4=0;
//静态占据空间,要注意的是静态变量定义前不能有语句的存在
TL0=0x66;//1ms
TH0=0xFC;
T0Count1++;
if(T0Count1>=20)//20ms
{
T0Count1=0;
Key_Loop();//每隔20毫秒调用一次
}
T0Count2++;
if(T0Count2>=2)//2ms
{
T0Count2=0;
Nixie_Loop();
}
if(Long_Press)
{
T0Count3++;
if(T0Count3>=100)
{
T0Count3=0;//加加进行
count++;
}
}
if(Minor_Press>=2)
{
T0Count4++;
if(T0Count4>=100)
{
T0Count4=0;
count--;//减减进行
}
}
}
按键检测部分
#include <REGX52.H>
#include "Delay.h"
unsigned char Key_KeyNumber,Long_Press=0,Minor_Press=0,Countint1,Countint2;
unsigned char First,Second;
unsigned char Key(void) //返回Key Number的值
{ unsigned char Temp=0; //先清零按键值再返回按键的值
Temp=Key_KeyNumber; //中间变量为按键值
Key_KeyNumber=0; //否则会一直返回上一次的值
return Temp;
}
unsigned char Key_GetState()
{ unsigned char KeyNumber=0;
if(P3_1==0){KeyNumber=1;}
if(P3_0==0){KeyNumber=2;}
if(P3_2==0){KeyNumber=3;}
if(P3_3==0){KeyNumber=4;}
return KeyNumber;
}
void Key_Loop(void)
{
static unsigned char NowState,LastState;
LastState=NowState;
NowState=Key_GetState();
if(LastState && !NowState) //此处是松手检测的因此刚好可以将Long_Press置一
{
Key_KeyNumber=LastState;//一松手Long_Press就为0
Long_Press=0;
if(Minor_Press>=2)
{
Minor_Press=0;
}
}
if(LastState==1 && NowState)
{
Countint1++; //未松手状态
if(Countint1>=50)
{
Countint1=0;
Long_Press=1;
}
}
if(LastState==2 && NowState)
{
First=200; //第一次按下需要的时间80ms
Second=80; //也可以直接对按键值进行检测更加正确
Countint2++; //需要对两次按下进行不同的处理
if(Countint2>=First && Minor_Press==0)
{
Countint2=0; //一直按下也会触发count--;
Minor_Press++; //两次按下但是时间短的长按也能实现题目效果
}
if(Countint2>=Second && Minor_Press==1)
{
Countint2=0;
Minor_Press++;
}
}
}
Nixie数码管部分
#include <REGX52.H>
#include "Delay.h"
unsigned char Nixie_Buf[9]={10,10,10,10,10,10,10,10,10};//此函数调用NixieTable()函数Nixie_Loop中调用
//第十位即为不显示为0x00
unsigned char NixieTable[13]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40,0x08};
//点才是第一个然后往后推
//.,g,f,e,d,c,b,a,//0到9,不显示,显示中间一段,显示底下一段
void Nixie_SetBuf(unsigned char Location,Number)//配置数码数组
{
Nixie_Buf[Location]=Number;//制位Nixie_Buf
}
void Nixie_Scan(unsigned char Location,Number)//数码管需要循环扫描才能正常显示
{
P0=0x00;//清零 消影 单片机运行速度过快防止数据串到下一个数据位
switch(Location)位选
{
case 1:P2_4=1;P2_3=1;P2_2=1;break;//7
case 2:P2_4=1;P2_3=1;P2_2=0;break;//6
case 3:P2_4=1;P2_3=0;P2_2=1;break;//5
case 4:P2_4=1;P2_3=0;P2_2=0;break;//4
case 5:P2_4=0;P2_3=1;P2_2=1;break;//3
case 6:P2_4=0;P2_3=1;P2_2=0;break;//2
case 7:P2_4=0;P2_3=0;P2_2=1;break;//1
case 8:P2_4=0;P2_3=0;P2_2=0;break;//0
}
P0=NixieTable[Number];//段选
}
void Nixie_Loop(void) //2ms调用
{
static unsigned char i=1; //定时器充当Delay的角色 充分显示
Nixie_Scan(i,Nixie_Buf[i]); //NixieScan才为真正的显示
i++; //刷新值显示放入Nixie_Scan
if(i>=9){i=1;}
}
Show函数
#include <REGX52.H>
#include "Nixie.h"
//主要是用来将三位数的百位十位各位分开的
//如果位数小于三位缺失位则为零
extern unsigned char bai,ge,shi;
void ShowNum(unsigned char Num)
{
bai=Num/100;shi=Num/10%10;ge=Num%10;
Nixie_SetBuf(1,bai);
Nixie_SetBuf(2,shi);
Nixie_SetBuf(3,ge);
}
如果对于定时器扫描按键的方法还不是非常熟悉
可以参考下面的文章
https://blog.csdn.net/2301_79690545/article/details/135038604?spm=1001.2014.3001.5501