一、功能概述
概述:通过按下矩阵键盘输入数字让数码管显示,然后按下独立键盘通过定时器开始倒计时,倒计时结束蜂鸣器响。
二、所使用的功能模块
矩阵键盘、独立键盘、蜂鸣器、数码管
三、编程过程中所遇到的问题及改进措施
问题1: 如何通过矩阵键盘点亮数码管并将按键值传递给定时模块?
措施:(代码模块如下)
(1)矩阵键盘扫描 0~15。
注意:<1>受单片机I/O口数量所限,注意到矩阵键盘第一排和独立键盘共用一组I/O口,所以如果忽略,当按下矩阵键盘第一排后会自动进入倒计时模块。
<2>扫描末尾要将P3口拉高,否则在程序执行过程中由于程序段开始时进行列扫描将P3口部分拉高,导致矩阵键盘二、三、四排其中一个按键被按下时都有可能自动进入倒计时模块。
uchar KeyScan(uint KeyValue)
{
P3 = 0XF0;//列扫描
if(P3 != 0XF0)//判断按键是否被按下
{
delay(10);//软件消抖10ms
if(P3 != 0XF0)//判断按键是否被按下
{
switch(P3) //判断那一列被按下
{
case 0xe0: KeyValue = 0; break;//第一列被按下
case 0xd0: KeyValue = 1; break;//第二列被按下
case 0xb0: KeyValue = 2; break;//第三列被按下
case 0x70: KeyValue = 3; break;//第四列被按下
}
P3 = 0X0F;//行扫描
switch(P3) //判断那一行被按下
{
case 0x0e: KeyValue = KeyValue; break;//第一行被按下
case 0x0d: KeyValue = KeyValue + 4; break;//第二行被按下
case 0x0b: KeyValue = KeyValue + 8; break;//第三行被按下
case 0x07: KeyValue = KeyValue + 12; break;//第四行被按下
}
while(P3 != 0X0F);//松手检测 /***重点***/
}
}
P3=0xff; /***重点***/
return KeyValue;
}
(2)按键数字显示和值传递
uchar Key_input(uint z)
{
uint temp1=0;
uint temp2=0;
while(!temp1)
{
P0=0xfe;
WE=1;
WE=0;
temp1=KeyScan(temp1);
P0=tabel[temp1];
DU=1;
DU=0;
temp1=temp1 * 10;
}
while(!temp2)
{
P0=0xfd;
WE=1;
WE=0;
temp2=KeyScan(temp2);
P0=tabel[temp2];
DU=1;
DU=0;
}
z=temp1+temp2;
return z;
}
问题2: 如何精确控制倒计时的时间间隔(1s)?
措施:(代码模块如下)
(1) 使用定时器0,通过配置16位定时器的初始值,溢出一次为50ms,溢出二十次即为1s。
(2)具体转换步骤:
<1> 50ms=50 000us
<2>一个机器周期为1.085us(晶振频率为11.0592)
<3>50 000/1.085=46082 个机器周期
<4>16位定时器,1111 1111 1111 1111 转换为十进制为65535,所以65535-46082=19453 转换为二进制为4BFD, 故高八位为 0x4B, 低八位为0xFD.
void timer0() interrupt 1 //T0溢出中断,中断入口为1
{
TH0=(65535-46080)/256; //高四位
TL0=(65535-46080)%256; //低四位
m++;
}
//定时器开关
void timer_open()
{
TMOD=0x01; //定时器工作模式1,16位定时器计数模式
TR0=1; //启动定时器0
TH0=(65536-46080)/256;//4bfd
TL0=(65536-46080)%256;//定时50ms
EA=1; //cpu的总中断允许控制位,开放中断
ET0=1; //T0的溢出中断允许?
}
(4)主程序段
*注意标志位flag的使用
void main()
{
uchar a1,a0;
uchar flag=0;
while(1) /***重点***/
{
if(flag==0) /***重点***/
{
Sec=Key_input(Sec);
flag=1; /***重点***/
}
if(flag==1) /***重点***/
{
if(Key_s2==0)
{
delay(20);
if(Key_s2==0)
{
timer_open();
while(1)
{
if(m==20) //中断20次,1秒
{
m=0;//m置零
Sec--;//秒减一
}
a0=Sec%10;//实时显示十位数字
a1=Sec/10;//实时显示个位数字
display(a1,a0);
if(Sec==0)//倒计时结束
{
TR0=0;//关闭定时器0
beep=0;
}
}
}
}
}
}
}
//完整代码如下:
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit DU = P2^6;
sbit WE = P2^7;
sbit beep=P2^3;
sbit Key_s2=P3^0;
uint i,m,KeyValue;
uint Sec;
//共阴数码管段选表
uchar code tabel[]= {
//0 1 2 3
0x3F, 0x06, 0x5B, 0x4F,
//4 5 6 7
0x66, 0x6D, 0x7D, 0x07,
//8 9 A B
0x7F, 0x6F, 0x77, 0x7C,
//C D E F
0x39, 0x5E, 0x79, 0x71};
void delay(uint z)
{
uint x,y;
for(x = z; x > 0; x--)
for(y = 114; y > 0 ; y--);
}
//定时器0初始化
void timer0() interrupt 1 //T0溢出中断,中断入口为1
{
TH0=(65535-46080)/256; //高四位
TL0=(65535-46080)%256; //低四位
m++;
}
//定时器开关
void timer_open()
{
TMOD=0x01; //定时器工作模式1,16位定时器计数模式
TR0=1; //启动定时器0
TH0=(65536-46080)/256;//4bfd
TL0=(65536-46080)%256;//定时50ms
EA=1; //cpu的总中断允许控制位,开放中断
ET0=1; //T0的溢出中断允许位
}
//4*4矩阵键盘扫描
uchar KeyScan(uint KeyValue)
{
P3 = 0XF0;//列扫描
if(P3 != 0XF0)//判断按键是否被按下
{
delay(10);//软件消抖10ms
if(P3 != 0XF0)//判断按键是否被按下
{
switch(P3) //判断那一列被按下
{
case 0xe0: KeyValue = 0; break;//第一列被按下
case 0xd0: KeyValue = 1; break;//第二列被按下
case 0xb0: KeyValue = 2; break;//第三列被按下
case 0x70: KeyValue = 3; break;//第四列被按下
}
P3 = 0X0F;//行扫描
switch(P3) //判断那一行被按下
{
case 0x0e: KeyValue = KeyValue; break;//第一行被按下
case 0x0d: KeyValue = KeyValue + 4; break;//第二行被按下
case 0x0b: KeyValue = KeyValue + 8; break;//第三行被按下
case 0x07: KeyValue = KeyValue + 12; break;//第四行被按下
}
while(P3 != 0X0F);//松手检测
}
}
P3=0xff;
return KeyValue;
}
uchar Key_input(uint z)
{
uint temp1=0;
uint temp2=0;
while(!temp1)
{
P0=0xfe;
WE=1;
WE=0;
temp1=KeyScan(temp1);
P0=tabel[temp1];
DU=1;
DU=0;
temp1=temp1 * 10;
}
while(!temp2)
{
P0=0xfd;
WE=1;
WE=0;
temp2=KeyScan(temp2);
P0=tabel[temp2];
DU=1;
DU=0;
}
z=temp1+temp2;
return z;
}
void display(uchar sh,uchar g)
{
P0=tabel[sh];
DU=1;
DU=0;
P0=0xfe;
WE=1;
WE=0;
delay(5);
P0=tabel[g];
DU=1;
DU=0;
P0=0xfd;
WE=1;
WE=0;
delay(5);
}
void main()
{
uchar a1,a0;
uchar flag=0;
while(1)
{
if(flag==0)
{
Sec=Key_input(Sec);
flag=1;
}
if(flag==1)
{
if(Key_s2==0)
{
delay(20);
if(Key_s2==0)
{
timer_open();
while(1)
{
if(m==20)
{
m=0;
Sec--;
}
a0=Sec%10;
a1=Sec/10;
display(a1,a0);
if(Sec==0)//
{
TR0=0;
beep=0;
}
}
}
}
}
}
}