新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 51單片機(jī)模擬PS2協(xié)議制作5X5矩陣工業(yè)鍵盤

        51單片機(jī)模擬PS2協(xié)議制作5X5矩陣工業(yè)鍵盤

        作者: 時(shí)間:2016-11-23 來源:網(wǎng)絡(luò) 收藏
        根據(jù)客戶的要求利用單片機(jī)制作一個(gè)小的工控鍵盤,將下面對(duì)應(yīng)的鍵值發(fā)送到電腦顯示,利用的協(xié)議就是PS2,單片機(jī)型號(hào)為stc89c52rc,晶振為12M;
           10
        65432
        789減號(hào)等號(hào)
        yuiop
        qwert


        #include
        #include "PS2.H"

        本文引用地址:http://www.104case.com/article/201611/320263.htm

        BYTE PS2RecChar=0xCC;
        BOOL KeyBoardFlag=FALSE;
        #define Key_line P0//鍵盤行入口
        #define Key_list P2//鍵盤列入口

        #define PS2_1 0 //16
        #define PS2_0 1 //45
        #define PS2_6 2//36
        #define PS2_5 3 //2e
        #define PS2_4 4 //25
        #define PS2_3 5 //26
        #define PS2_2 6 //1e
        #define PS2_7 7 //3d
        #define PS2_8 8 //3e
        #define PS2_9 9 //46
        #define PS2_dec 10 //4e
        #define PS2_eq 11 //55
        #define PS2_y 12 //35
        #define PS2_u 13//3c
        #define PS2_i 14 //43
        #define PS2_o 15 //44
        #define PS2_p 16//4d
        #define PS2_q 17 //15
        #define PS2_w 18//1d
        #define PS2_e 19 //24
        #define PS2_r 20 //2d
        #define PS2_t 21 //2c

        //第二套鍵盤碼

        unsigned char PS2Value[22]={0x16,0x45,0x36,0x2e,0x25,0x26,0x1e,0x3d,0x3e,0x46,0x4e,0x55,0x35,0x3c,
        0x43,0x44,0x4d,0x15,0x1d,0x24,0x2d,0x2c};

        unsigned char Key_Press(void)
        {
        unsigned temp3;
        unsigned char flag=0; //設(shè)定標(biāo)志位
        Key_line=0xe0; //將P0口低5位全部設(shè)置位0
        temp3=Key_list; //讀取P2口的狀態(tài),若果P2口的值temp3:(temp3&0xff)!=0xff成立,表示有鍵按下
        if(((temp3&0xff)!=0xff)) //有鍵按下條件判斷
        {
        flag=1;
        //Key_line=0XFF; //清零鍵盤行端口
        Key_list=0xff; //清零鍵盤列端口
        }
        else
        flag=0; //無鍵按下標(biāo)志
        return flag;
        }
        void delay(unsigned int ms)
        {
        unsigned int i,j;
        for(i=ms;i>0;i--)
        for(j=100;j>0;j--);
        }

        unsigned char Key_Scan(void)
        {
        unsigned char temp2=0,temp3=0; //temp2用來保存行鍵盤數(shù)據(jù),temp3保存列鍵盤數(shù)據(jù)
        unsigned char temp=0,flag=0; //函數(shù)返回值temp
        unsigned char i=0,key=0; //i位循環(huán)控制變量,給行送數(shù)據(jù),key保存檢測(cè)鍵盤按下的標(biāo)志位
        if((key=Key_Press())!=0) //判斷是否有鍵按下
        {
        delay(30);
        if((key=Key_Press())!=0)
        {
        for(i=0x01;i!=0x20;i=i<<1) //循環(huán)控制變量,掃描5行
        {
        Key_line=(~i); //將循環(huán)控制變量賦值行地址
        temp2 =(~i); //保存行地址
        //temp2=Key_line;
        temp3=Key_list;//讀取列地址數(shù)據(jù)
        switch((temp3&0xff))//判斷是那列有鍵按下
        {
        case 0xfe://第一列有鍵按下
        switch((temp2&0xff)) //判斷第一列有鍵按下時(shí),對(duì)應(yīng)的行按鍵
        {
        case 0xfe:
        temp=23; //第一行有鍵按下
        break; //該鍵無鍵盤號(hào)定義
        case 0xfd: //第二行有鍵按下
        temp=PS2_6;flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字6,對(duì)應(yīng)的鍵盤掃描碼為0x36
        break;
        case 0xfb: //第三行有鍵按下
        temp=PS2_7; flag=1;//對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字7,對(duì)應(yīng)的鍵盤掃描碼為0x3d
        break;
        case 0xf7: //第四行有鍵按下
        temp=PS2_y; flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的字母y,對(duì)應(yīng)的鍵盤掃描碼為0x35
        break;
        case 0xef: //第五行有鍵按下
        temp=PS2_q ;flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的字母q,對(duì)應(yīng)的鍵盤掃描碼為0x15
        break;
        }
        break;

        case 0xfd:
        switch((temp2&0xff)) // 第二列有鍵按下
        {
        case 0xfe: //第一行有鍵按下
        temp=23; //該鍵無鍵盤號(hào)定義
        break;
        case 0xfd: //第二行有鍵按下
        temp=PS2_5;flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字5,對(duì)應(yīng)的鍵盤掃描碼為0x2e
        break;
        case 0xfb: //第三行有鍵按下
        temp=PS2_8;flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字8,對(duì)應(yīng)的鍵盤掃描碼為0x8e
        break;
        case 0xf7: //第四行有鍵按下
        temp=PS2_u;flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的字母u,對(duì)應(yīng)的鍵盤掃描碼為0x3c
        break;
        case 0xef: //第五行有鍵按下
        temp=PS2_w ; flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的字母w,對(duì)應(yīng)的鍵盤掃描碼為0x1d
        break;
        }
        break;

        case 0xfb:
        switch((temp2&0xff)) // 第三列有鍵按下
        {
        case 0xfe: //第一行有鍵按下
        temp=23;//該鍵無鍵盤號(hào)定義
        break;
        case 0xfd: //第二行有鍵按下
        temp=PS2_4;flag=1;//對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字4,對(duì)應(yīng)的鍵盤掃描碼為0x25
        break;
        case 0xfb: //第三行有鍵按下
        temp=PS2_9;flag=1;//對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字9,對(duì)應(yīng)的鍵盤掃描碼為0x46
        break;
        case 0xf7: //第四行有鍵按下
        temp=PS2_i;flag=1;//對(duì)應(yīng)鍵值位PS2鍵盤的字母i,對(duì)應(yīng)的鍵盤掃描碼為0x43
        break;
        case 0xef: //第五行有鍵按下
        temp=PS2_e; flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的字母e,對(duì)應(yīng)的鍵盤掃描碼為0x24
        break;
        }
        break;

        case 0xf7:
        switch((temp2&0xff)) // 第四列有鍵按下
        {
        case 0xfe: //第一行有鍵按下
        temp=PS2_1;flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字1,對(duì)應(yīng)的鍵盤掃描碼為0x16
        break;
        case 0xfd: //第二行有鍵按下
        temp=PS2_3;flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字3,對(duì)應(yīng)的鍵盤掃描碼為0x26
        break;
        case 0xfb: //第三行有鍵按下
        temp=PS2_dec;flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的減號(hào),對(duì)應(yīng)的鍵盤掃描碼為0x4e
        break;
        case 0xf7: //第四行有鍵按下
        temp=PS2_o;flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的字母o,對(duì)應(yīng)的鍵盤掃描碼為0x44
        break;
        case 0xef: //第五行有鍵按下
        temp=PS2_r; flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的字母r,對(duì)應(yīng)的鍵盤掃描碼為0x2d
        break;
        }
        break;

        case 0xef:
        switch((temp2&0xff)) // 第五列有鍵按下
        {
        case 0xfe: //第一行有鍵按下
        temp=PS2_0;flag=1;//對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字0,對(duì)應(yīng)的鍵盤掃描碼為0x45
        break;
        case 0xfd: //第二行有鍵按下
        temp=PS2_2;flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字2,對(duì)應(yīng)的鍵盤掃描碼為0x1e
        break;
        case 0xfb: //第三行有鍵按下
        temp=PS2_eq;flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的等號(hào),對(duì)應(yīng)的鍵盤掃描碼為0x55
        break;
        case 0xf7: //第四行有鍵按下
        temp=PS2_p;flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的字母p,對(duì)應(yīng)的鍵盤掃描碼為0x4d
        break;
        case 0xef: //第五行有鍵按下
        temp=PS2_t;flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的字母t,對(duì)應(yīng)的鍵盤掃描碼為0x2c
        break;
        }
        break;
        }
        //P0=0XFF; //每當(dāng)檢測(cè)完一行時(shí)清零行端口和列端口
        //P2=0xff;
        if((key=Key_Press())!=0);
        delay(30);
        }
        }
        }
        else temp=23; //無鍵按下返回?cái)?shù)字23,對(duì)應(yīng)數(shù)組內(nèi)的0;
        if(flag==1)
        return temp;//返回按鍵掃描值
        else
        return 23;
        }
        void OnKeyBoardOnline(BOOL i)
        {
        KeyBoardFlag=i;
        }
        //---------------------------------------------------------------------------
        void OnPS2ReceiveChar(BYTE ReceChar,BOOL P)
        {
        BOOL ParityBit=0;
        ACC=ReceChar;
        CY=P;
        ParityBit=(BOOL)(CY?0x00:0x80);//奇校驗(yàn)位
        if(P==ParityBit);
        PS2RecChar=ReceChar;
        }
        //---------------------------------------------------------------------------
        void OnPS2SendChar(BYTE dat)
        {
        BOOL ParityBit;
        BYTE i;
        ACC=dat;
        CY=P;
        ParityBit=(BOOL)(CY?0x00:0x80);//奇校驗(yàn)位

        CLSSIGNAL();

        CT_KB=OFF;
        EX0=0;

        H_DATA=0;Delay10us();//start bit
        H_CLK=1;
        Delay10us();
        H_CLK=0;
        Delay30us();

        for(i=0;i<8;i++)
        {
        if(dat&0x01==0x01){H_DATA=1;Delay10us();}
        else {H_DATA=0;Delay10us();}
        dat>>=1;
        H_CLK=1;
        Delay10us();
        H_CLK=0;
        Delay30us();
        }

        H_DATA=ParityBit;Delay10us();//parity bit
        H_CLK=1;
        Delay10us();
        H_CLK=0;
        Delay30us();

        H_DATA=1;Delay10us();//stop bit
        H_CLK=1;
        Delay10us();
        H_CLK=0;
        Delay30us();

        IE0=0;
        EX0=1;
        H_CLK=1;
        H_DATA=1;
        CT_KB=ON;
        Delay30us();
        }
        //---------------------------------------------------------------------------
        void ExternInterrupt0(void) interrupt 0
        {
        BOOL ParityBit=0,CLKFlag=1;
        BYTE i=0,j=8,dat=0x00;

        EX0=0;

        while(CLKFlag)
        {
        i++;
        if(H_CLK==1)CLKFlag=0;
        if(i>0xEE)
        {
        IE0=0;
        EX0=1;
        return ;
        }
        }
        while(j--)//延時(shí)等待大鍵盤的動(dòng)作
        {
        for(i=0;i<0x88;i++)//檢查是否有數(shù)據(jù)處理0x88
        {
        if(H_CLK==0)//有動(dòng)作則是大鍵盤存在
        {
        OnKeyBoardOnline(TRUE);//大鍵盤存在,開機(jī)由大鍵盤應(yīng)答
        IE0=0;
        EX0=1;
        return ;//存在的話置標(biāo)志位,并返回
        }
        }
        }
        OnKeyBoardOnline(FALSE);//大鍵盤不存在,由小鍵盤應(yīng)答

        //轉(zhuǎn)到接收
        for(i=0;i<8;i++)//read 8bit
        {
        Delay30us();
        H_CLK=0;
        Delay30us();
        H_CLK=1;
        dat=dat>>1;
        if(H_DATA)dat|=0x80;

        if(H_CLK==0){return;}//如果時(shí)鐘被拉低,則有錯(cuò)誤發(fā)生
        }

        Delay30us();
        H_CLK=0;
        Delay30us();
        H_CLK=1;
        if(H_DATA)ParityBit=1;
        else ParityBit=0;

        Delay30us();
        H_CLK=0;
        Delay30us();
        H_CLK=1;//STOP BIT H_DATA 0 ERR

        Delay10us();
        H_DATA=0;//ACK bit
        Delay10us();
        H_CLK=0;
        Delay30us();Delay30us();
        H_CLK=1;
        Delay30us();
        H_DATA=1;

        OnPS2ReceiveChar(dat,ParityBit);

        IE0=0;
        EX0=1;
        return ;
        }
        //---------------------------------------------------------------------------
        void ProcessPS2(void)
        {
        if(KeyBoardFlag==FALSE)//大鍵盤不存在
        {
        if(PS2RecChar==0xF3)//1
        {
        OnPS2SendChar(0xFA);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0x00)//11
        {
        OnPS2SendChar(0xFA);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0x02)//111
        {
        OnPS2SendChar(0xFA);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0x20)//1111
        {
        OnPS2SendChar(0xFA);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0xED)//2
        {
        OnPS2SendChar(0xFA);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0xF0)//3
        {
        OnPS2SendChar(0xFA);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0xF2)//4
        {
        OnPS2SendChar(0xFA);
        Delay30us();
        OnPS2SendChar(0xAB);
        Delay30us();
        OnPS2SendChar(0x83);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0xEF)//5
        {
        OnPS2SendChar(0xFA);
        Delay30us();
        OnPS2SendChar(0xBF);
        Delay30us();
        OnPS2SendChar(0xB0);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0xF3)//6
        {
        OnPS2SendChar(0xFA);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0xFE)//7 //resend
        {
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0xEE)//8
        {
        OnPS2SendChar(0xEE);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0xEE)//9
        {
        OnPS2SendChar(0xEE);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0xF1)//10
        {
        OnPS2SendChar(0xFA);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0xF4)//11
        {
        OnPS2SendChar(0xFA);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0xAA)//12
        {
        OnPS2SendChar(0xAA);
        PS2RecChar=0xCC;
        }
        else if(PS2RecChar==0xFF)//13
        {
        OnPS2SendChar(0xFA);
        Delay30us();
        OnPS2SendChar(0xAA);
        Delay30us();
        PS2RecChar=0xCC;
        }
        else ;
        }
        }
        //---------------------------------------------------------------------------
        void PS2Init(void)
        {
        IT0=0;//低電平觸發(fā)中斷
        PX0=1;
        EX0=1;
        }
        //---------------------------------------------------------------------------

        extern void ProcessPS2(void);
        extern void PS2Init(void);
        void main(void)
        {
        unsigned char tem;
        PS2Init();
        ProcessPS2();
        while(1)
        {
        tem=Key_Scan();
        switch(tem&0xff)
        {
        case 23 :
        break;
        default:
        {
        OnPS2SendChar(PS2Value[tem]);
        }
        break;
        }
        //開機(jī)應(yīng)答,使電腦能識(shí)別到鍵盤
        //other code
        }
        }
        仿真矩陣鍵盤電路圖,該電路未連接PS2,但可通過LED燈觀察每個(gè)按鍵按下之后的鍵值返回知否和第二套鍵盤碼對(duì)應(yīng)一致


        第二套鍵值碼對(duì)應(yīng)表:




        評(píng)論


        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 蒙阴县| 大理市| 黎平县| 朝阳区| 灵台县| 革吉县| 乌拉特中旗| 纳雍县| 虎林市| 巫溪县| 聂拉木县| 乌兰浩特市| 陇西县| 滨州市| 察雅县| 武乡县| 阿拉善左旗| 乳山市| 绥宁县| 德令哈市| 手游| 巴林右旗| 江源县| 乌拉特前旗| 朝阳县| 宁武县| 青铜峡市| 斗六市| 宾阳县| 漠河县| SHOW| 惠州市| 安图县| 轮台县| 灵宝市| 乐安县| 泾源县| 东港市| 蒙山县| 丁青县| 武乡县|