目录
一、实验环境与实验器材
环境:Keli,STC-ISP烧写软件,Proteus.
器材:TX-1C单片机(STC89C52RC)、电脑。
图1.1 工具
二、实验内容及实验步骤
1.独立键盘检测
用数码管的前两位显示一个十进制数,变化范围为00~59,开始时显示00,每按下S2一次,数值加1;每按下S3键一次,数值减1;每按下S4键一次;数值归零;按下S5一次,利用定时器功能使数值开始自动每秒加1,再次按下S5键,数值停止自动加1。
#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
sbit key1=P3^4;
sbit key2=P3^5;
sbit key3=P3^6;
sbit key4=P3^7;
sbit dula=P2^6; // 申明U1锁存器的锁存端
sbit wela=P2^7; // 申明U2锁存器的锁存端
uchar code table[]={ 0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
void delayms(uint);
uchar numt0,num;
void display(uchar numdis) // 显示子函数
{
uchar shi,ge; // 分离两个分别要显示的数
shi=numdis/10;
ge=numdis%10;
dula=1;
P0=table[shi]; // 送十位选段数据
dula=0;
P0=0xff; // 送位选数据前关闭所有显示,防止打开位选锁存时
wela=1; // 原来段选数据通过位选锁存器造成混乱
P0=0xfe;
wela=0;
delayms(100); // 延时
dula=1;
P0=table[ge]; // 送个位段选数据
dula=0;
P0=0xff;
wela=1;
P0=0xfd;
wela=0;
delayms(100);
}
void delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--) // i=xms即延时约xms毫秒
for(j=110;j>0;j--);
}
void init() // 初始化函数
{
TMOD=0x01; // 设置定时器0为工作方式1(0000 0001)
TH0=(65536-45872)/256; // 初装值50ms一次中断
TL0=(65536-45872)%256;
EA=1; // 开总中断
ET0=1; // 开定时器0中断
}
void keyscan()
{
if(key1==0)
{
delayms(10);
if(key1==0)
{
num++;
if(num==60) // 当到60时重新归0
num=0;
while(!key1); // 等待按键释放
}
}
if(key2==0)
{
delayms(10);
if(key2==0)
{
if(num==0) // 当到0时重新归60
num=60;
num--;
while(!key2);
}
}
if(key3==0)
{
delayms(10);
if(key3==0)
{
num=0; // 清0
while(!key3);
}
}
if(key4==0)
{
delayms(10);
if(key4==0)
{
while(!key4)
TR0=~TR0; // 停止或启动定时器0
}
}
}
void main()
{
init(); // 初始化函数
while(1)
{
keyscan();
display(num);
}
}
void T0_time() interrupt 1
{
TH0=(65536-45872)/256; // 重装初值
TL0=(65536-45872)%256;
numt0++;
if(numt0==20) // 如果到了20次,说明1秒时间到
{
numt0=0; // 然后把num清0重新再计20次
num++;
if(num==60)
num=0;
}
}
图2.1.2 烧录
图2.1.3实体按键和数码管初始显示
图2.1.4 实体按键功能说明
Proteus因为延时原因,数码管第一位会闪。(截图不显示)按键从上到下依次为S1,S2,S3,S4,S5
图2.1.1 proteus仿真图
仿真视频:
独立键盘检测
2.独立键盘(简易版本)
现象:每按一次键盘数码管数值加1.
代码:
#include "reg52.h"
sbit key0=P1^0;
unsigned char s[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //共阴0-9
//unsigned char str[]={0x76,0x79,0x38,0x38,0x3F}; // HELLO
//unsigned char wei[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
unsigned char num=0,flag=0;
void delay(int n)
{
int i=0,j=0;
for (i=0;j<120;j++)
{
for (j=0;j<120;j++);
}
}
void seg()
{
P2=s[num];
if(num==10)
{
num=0;
}
}
/*void key()
{
if(key0==0)
{
delay(200);
if(key0==0)
{
num++;
}
}
}*/
void key()
{
if(key0==0 && flag==0)
{
flag=1;
}
if(flag==1 && key0==1)
{
num++;
flag=0;
}
}
void main()
{
while(1)
{
key();
seg();
}
}
图2.2.1 独立键盘简易仿真图
仿真视频:
独立键盘简易仿真
3.矩阵键盘检测
实验板上电时,数码管不显示,顺序按下矩阵键盘后,在数码管上依次显示0~F,6个数码管同时静态显示。
#include"reg52.h"
#define uchar unsigned char
#define uint unsigned int
sbit dula=P2^6; // 申明U1锁存器的锁存端
sbit wela=P2^7; // 申明U2锁存器的锁存端
uchar code table[]={ 0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
void delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--) //i=xms即延时约xms毫秒
for(j=110;j>0;j--);
}
void display(uchar num)
{
P0=table[num]; //显示函数只送段选数据
dula=1;
dula=0;
}
void matrixkeyscan()
{
uchar temp,key;
P3=0xfe;
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
delayms(10);
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xee:
key=0;
break;
case 0xde:
key=1;
break;
case 0xbe:
key=2;
break;
case 0x7e:
key=3;
break;
}
while(temp!=0xf0) //等待按键释放
{
temp=P3;
temp=temp&0xf0;
}
display(key); // 显示
}
}
P3=0xfd;
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
delayms(10);
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xed:
key=4;
break;
case 0xdd:
key=5;
break;
case 0xbd:
key=6;
break;
case 0x7d:
key=7;
break;
}
while(temp!=0xf0)
{
temp=P3;
temp=temp&0xf0;
}
display(key);
}
}
P3=0xfb;
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
delayms(10);
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xeb:
key=8;
break;
case 0xdb:
key=9;
break;
case 0xbb:
key=10;
break;
case 0x7b:
key=11;
break;
}
while(temp!=0xf0)
{
temp=P3;
temp=temp&0xf0;
}
display(key);
}
}
P3=0xf7;
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
delayms(10);
temp=P3;
temp=temp&0xf0;
if(temp!=0xf0)
{
temp=P3;
switch(temp)
{
case 0xe7:
key=12;
break;
case 0xd7:
key=13;
break;
case 0xb7:
key=14;
break;
case 0x77:
key=15;
break;
}
while(temp!=0xf0)
{
temp=P3;
temp=temp&0xf0;
}
display(key);
}
}
}
void main()
{
P0=0; //关闭所有数码管段选
dula=1;
dula=0;
P0=0xc0; // 位选中所有数码管
wela=1;
wela=0;
while(1)
{
matrixkeyscan(); //不停调用键盘扫描程序
}
}
图2.3.1 上电现象(实体)
图2.3.2 按第一个按钮现象(实体)
图2.3.3 最后一个按钮现象(实体)
Proteus仿真:
图2.3.4 矩阵键盘仿真图
仿真视频:
矩阵键盘
4.矩阵键盘(简单版,单数码管):
图2.4.1 简易版矩阵键盘仿真图
#include "reg52.h"
unsigned char s[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7c,0x39,0x5e,0x79,0x71};//共阴0-9
unsigned char num=99;
void delay(unsigned int n)
{
unsigned int i=0,j=0;
for(i=0;i<n;i++)
{
for(j=0;j<120;j++);
}
}
void key_scan()
{
unsigned char temp0=0,temp1=0,temp=0;
P1=0xf0;
if(P1!=0xf0) //检测按键是否被按下
{
delay(20);
temp0=P1;
P1=0x0f;
if(P1!=0x0f);
{
temp1=P1;
}
}
temp=temp0+temp1;
if(temp==0xEE)
{
num=0;
}
if(temp==0xED)
{
num=1;
}
if(temp==0xEB)
{
num=2;
}
if(temp==0xE7)
{
num=3;
}
if(temp==0xDE)
{
num=4;
}
if(temp==0xDD)
{
num=5;
}
if(temp==0xDB)
{
num=6;
}
if(temp==0xD7)
{
num=7;
}
if(temp==0xBE)
{
num=8;
}
if(temp==0xBD)
{
num=9;
}
if(temp==0xBB)
{
num=10;
}
if(temp==0xB7)
{
num=11;
}
if(temp==0x7E)
{
num=12;
}
if(temp==0x7D)
{
num=13;
}
if(temp==0x7B)
{
num=14;
}
if(temp==0x77)
{
num=15;
}
}
void display()
{
P2=s[num];
}
void main()
{
while(1)
{
key_scan();
display();
}
}
这个代码冗余很高,if判断很多,明白逻辑即可。(仿真启动时间较长)
代码解释
在代码中,
temp
的值是通过将temp0
和temp1
相加得到的。具体来说:
temp0
的获取:
- 将
P1
端口的高 4 位设置为高电平(P1 = 0xF0
)。- 如果有按键按下,
P1
的值会改变,此时读取P1
的值并存储到temp0
中。
temp1
的获取:
- 将
P1
端口的低 4 位设置为高电平(P1 = 0x0F
)。- 再次读取
P1
的值并存储到temp1
中。
temp
的计算:
temp = temp0 + temp1
。按键矩阵的常见设计
在按键矩阵中,通常会有 4 行和 4 列,共 16 个按键。每个按键的位置可以通过行和列的交叉点来确定。假设按键矩阵的设计如下:
- 行:
P1.4
到P1.7
(高 4 位)- 列:
P1.0
到P1.3
(低 4 位)当某个按键被按下时,
P1
的值会反映出行和列的状态。
按键位置 | temp0 (高 4 位) | temp1 (低 4 位) | temp = temp0 + temp1 |
---|---|---|---|
第 1 行第 1 列 | 0xE0 | 0x0E | 0xEE |
第 1 行第 2 列 | 0xE0 | 0x0D | 0xED |
第 1 行第 3 列 | 0xE0 | 0x0B | 0xEB |
第 1 行第 4 列 | 0xE0 | 0x07 | 0xE7 |
第 2 行第 1 列 | 0xD0 | 0x0E | 0xDE |
第 2 行第 2 列 | 0xD0 | 0x0D | 0xDD |
第 2 行第 3 列 | 0xD0 | 0x0B | 0xDB |
第 2 行第 4 列 | 0xD0 | 0x07 | 0xD7 |
第 3 行第 1 列 | 0xB0 | 0x0E | 0xBE |
第 3 行第 2 列 | 0xB0 | 0x0D | 0xBD |
第 3 行第 3 列 | 0xB0 | 0x0B | 0xBB |
第 3 行第 4 列 | 0xB0 | 0x07 | 0xB7 |
第 4 行第 1 列 | 0x70 | 0x0E | 0x7E |
第 4 行第 2 列 | 0x70 | 0x0D | 0x7D |
第 4 行第 3 列 | 0x70 | 0x0B | 0x7B |
第 4 行第 4 列 | 0x70 | 0x07 | 0x77 |
表2.4.1 temp值计算
仿真视频:
矩阵键盘(简易版)