delay函数检测按键状态,按下按键不松开函数会卡在那(delay函数里利用了死循环),只有等按键松开的时候才会继续执行。由于按键抖动的时间大概在20ms,所以在20ms一定能检测到按键的变化,那么我们就可以设置定时器在每20ms检测一次按键状态。
按照江科的代码实验出来会有很大误差,应该是新版晶振频率和旧版不同导致的,我在他代码的基础上改了定时器的初值,但是仍有误差(快了),可能还需要改一下最开始keil选择的单片机型号吧,不过之前做实验只能选c52,就习惯性选了,这里没改。
代码部分
main.c
#include <REGX52.H>
#include "timer.h"
#include "key.h"
#include "smgshow.h"
#include "I2C.h"
#include "AT24C02.h"
#include "delay.h"
unsigned char keynum;
unsigned char min,sec,ms;
unsigned char runflag;//开始标志
void main()
{
Timer0_Init();//初始化定时器
while(1)
{
keynum=keynumber();
if(keynum==1)//按键1控制开始
{
runflag=!runflag;
}
if(keynum==2)//按键2实现清0
{
min=0;
sec=0;
ms=0;
}
if(keynum==3)//按键3实现数据存储
{
AT24C02_writebyte(0,min);
delay(5);
AT24C02_writebyte(1,sec);
delay(5);
AT24C02_writebyte(2,ms);
delay(5);
}
if(keynum==4)//按键4实现数据读出
{
min=AT24C02_readbyte(0);
sec=AT24C02_readbyte(1);
ms=AT24C02_readbyte(2);
}
smg_setbuf(1,min/10);//显示数据
smg_setbuf(2,min%10);
smg_setbuf(3,11);
smg_setbuf(4,sec/10);
smg_setbuf(5,sec%10);
smg_setbuf(6,11);
smg_setbuf(7,ms/10);
smg_setbuf(8,ms%10);
}
}
void sec_loop()
{
if(runflag)
{
ms++;
if(ms>=100)//ms100进1位
{
ms=0;
sec++;
if(sec>=60)
{
sec=0;
min++;
if(min>=60)
{
min=0;
}
}
}
}
}
void timer0_routine() interrupt 1
{
static unsigned int T0count1,count2,count3;
TL0=0x80;
TH0=0xF0;
T0count1++;
if(T0count1>=20)//每隔20ms检测一次
{
T0count1=0;
key_loop();//每20ms跳转一次获取按键状态
}
count2++;
if(count2>=2)
{
count2=0;
smgshow_loop();
}
count3++;
if(count3>=10)//每隔10ms调用一次
{
sec_loop();
count3=0;
}
}
key.c
#include <REGF51RC.H>
#include "delay.h"
unsigned char key;//全局变量
unsigned char keynumber()//专门负责返回键(key)值的函数
{
unsigned char temp;
temp=key;
key=0;//每返回一次键值将key清零
return temp;
}
unsigned char key_getstate()//获取按键状态
{
unsigned char keynum=0;
if(P3_1==0){keynum=1;}
if(P3_0==0){keynum=2;}
if(P3_2==0){keynum=3;}
if(P3_3==0){keynum=4;}
return keynum;
}
void key_loop()
{
static unsigned char nowstate,laststate;
laststate=nowstate;//更新按键状态
nowstate=key_getstate();//获取按键值
if(laststate==1&& nowstate==0)//获取按键状态之后赋值给key
{
key=1;
}
if(laststate==2&& nowstate==0)
{
key=2;
}
if(laststate==3&& nowstate==0)
{
key=3;
}
if(laststate==4&& nowstate==0)
{
key=4;
}
}
smgshow.c
#include <REGX52.H>
#include "delay.h"
unsigned char smg_buf[9]={0,10,10,10,10,10,10,10,10};//显示缓存区
char num[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40};
void smg_setbuf(unsigned char location,number)//设置数码管显示的数字
{
smg_buf[location]=number;
}
void smgshow(unsigned char location,number)
{
P0=0x00;
switch(location)
{
case 1:P2_4=1 ;P2_3=1 ;P2_2=1 ;break;
case 2:P2_4=1 ;P2_3=1 ;P2_2=0 ;break;
case 3:P2_4=1 ;P2_3=0 ;P2_2=1 ;break;
case 4:P2_4=1 ;P2_3=0 ;P2_2=0 ;break;
case 5:P2_4=0 ;P2_3=1 ;P2_2=1 ;break;
case 6:P2_4=0 ;P2_3=1 ;P2_2=0 ;break;
case 7:P2_4=0 ;P2_3=0 ;P2_2=1 ;break;
case 8:P2_4=0 ;P2_3=0 ;P2_2=0 ;break;
}
P0=num[number];
}
void smgshow_loop()
{
static unsigned char i=1;
smgshow(i,smg_buf[i]);
i++;
if(i>8){i=1;}
}