📄 key205121.c
字号:
/*****************************************************************************************
Version2.1
电自院 校松华
2005.04.07
此程序是用AT89C2051来实现键盘电路,用其两个口P34、P35来模仿SPI总线,这样此键盘电路的接线就比较简单
这里借鉴两个MCU串行通信的思想,用电平判断来实现握手协议,
当键盘电路检测到有按键按下,CLK发一个下降沿去触发主机的中断,然后再发键值:
等待主机的回答,主机通过查询方式查询CLK位
是否为0,当查到为0是,就将DAT位置0,以示收到。
然后下位机就在CLK位的“护送”下,将键值通过DAT位送到主机。
主机也是通过CLK位的状态,将键值接受下来的
此版本是通过中断方式来实现按键功能的!
******************************************************************************************/
/******************************************************************************************
**版本号:Version3.0
**修改人:申红明
**日期:2006年12月8日10:28
**-----------------------------------------------------------------------------------------
**修改内容:(1)3*4键盘通过2051的P1.0~P1.7模拟SPI通信方式,从P3.4(CLK)、P3.5(DAT)口将数据送到
EASYARM2100板的P0.13(CLK)和P0.11(DAT)。起初,2051的发送和ARM的接受一直无法实现同
步,当本程序全速运行后,一直停在"while(DAT)"处,查看上位机ARM的程序发现问题:
在上位机中有如下一段程序:
IO0DIR = (IO0DIR&~CLK) | DAT; // DAT is output ,CLK is input
IO0CLR = DAT;
IO0DIR = IO0DIR & ~DAT; // DAT is input
问题出在第二句,在执行完第一句后,DAT变为了output,也许在此句之前,DAT是输入状态
的高电平,那么等到执行第三句的时候,DAT又变成了高电平,也就是说,在输出口线上出现
低电平的时间极短,下位机很难检测到。修改的方法是在上位机的ARM程序中,将第三句放到
时钟脉冲的高电平后执行,也就是说,当CLK信号准备好的时候才开始采样DAT信号,将DAT
信号由输出置为输入;
(2)当本程的senddata()函数执行结束的时候,CLK变为了低电平,而上位机就是通过查询
CLK是否为低电平来判断有没有键按下,所以必须在发送键值函数senddate()执行结束后将CLK
拉高,所以在主程序的末尾加上了"CLK=1;DAT=1"这两句,成功实现了上下位机的同步数据传输。
*******************************************************************************************/
#include <reg51.h>
#include <stdio.h>
#define uchar unsigned char
#define uint unsigned int
#define CLK p34
#define DAT p35
sbit p30=P3^0;
sbit p31=P3^1;
sbit p32=P3^2;
sbit p33=P3^3;
sbit p34=P3^4;
sbit p35=P3^5;
sbit p36=P3^6;
sbit p37=P3^7;
sbit p20=P2^0;
sbit p21=P2^1;
sbit p22=P2^2;
sbit p23=P2^3;
sbit p24=P2^4;
sbit p25=P2^5;
sbit p26=P2^6;
sbit p27=P2^7;
uchar code keycode[12]={0x91,0xa1,0xc1, //1,2,3
0x92,0xa2,0xc2, //4,5,6
0x94,0xa4,0xc4, //7,8,9
0x98,0xa8,0xc8}; //*,0,#
void delay(uint);
uchar scankey(void);
void senddata(uchar);
void main(void)
{
uchar key;
uchar keyvalue=0;
while(1)
{ while((key=scankey())==0);
if(key==keycode[0]) keyvalue=1; //把键码转变为键值,注意‘*’,‘#’的键值!!!
if(key==keycode[1]) keyvalue=2;
if(key==keycode[2]) keyvalue=3;
if(key==keycode[3]) keyvalue=4;
if(key==keycode[4]) keyvalue=5;
if(key==keycode[5]) keyvalue=6;
if(key==keycode[6]) keyvalue=7;
if(key==keycode[7]) keyvalue=8;
if(key==keycode[8]) keyvalue=9;
if(key==keycode[9]) keyvalue=0x0a; //'*'键按下
if(key==keycode[10]) keyvalue=0; //'0'键按下
if(key==keycode[11]) keyvalue=0x0b; //'#'键按下
senddata(keyvalue); //向上位机发送键值
// CLK=1; //发送完毕,置位时钟信号
// DAT=1;
}
}
void delay(uint i)
{
for(i;i>0;i--){;} //这个地方用i-而不用i++,看一下它的汇编就知道它的妙处!!!
}
uchar scankey(void)
{
uchar sccode,recode;
P1=0xf0;
if((P1&0xf0)!=0xf0) //有键被按下吗?
{ delay(5000); //有则延时10MS
if((P1&0xf0)!=0xf0) //键是真的被按下了吗?
{ sccode=0xfe; //是则扫描键码。
while((sccode&0x10)!=0)
{ P1=sccode;
if((P1&0xf0)!=0xf0)
{ recode=(P1&0xf0)|0x0f;
delay(5000);
while((P1&0xf0)!=0xf0);
return((~sccode)+(~recode));
}
else
sccode=(sccode<<1)|0x01;
}
}
delay(5000);
while((P1&0xf0)!=0xf0); //键被放开了吗?没有则等待!!!
}
return (0);
}
void senddata(uchar i)
{
uchar j;
CLK=1; //发一个下降沿去触发主机的中断
delay(2);
CLK=0;
delay(2);
DAT=1; //先发一个信号给ARM,告知有键被按下,并且开始发键值
while(DAT); //等待ARM的应答信号!!!
for(j=0;j<8;j++)
{
if((bit)(i&0x80)) DAT=1;
else DAT=0;
i<<=1;
CLK=1;
delay(50);
CLK=0;
delay(50);
}
CLK=1; //发送完毕,置位时钟信号
DAT=1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -