打印

关于主机对PS2键盘初始化的问题,着急

[复制链接]
12073|25
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
guantouren|  楼主 | 2008-3-15 11:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
大家好,我正在用51MCU模拟一个PS2键盘,遇到了键盘初始化的问题。
就是如果用一个标准PS2键盘带进系统,我做的键盘就可以使用,但是如果直接用MCU键盘启动,则不能用,我看了很多资料,但99%的都只讲到PS2协议的时序,没有详细讲启动时主机对PS2键盘发了那些命令,而键盘又回了哪些命令。还有键盘上电就要对主机发0XAA,但是什么时候发呢,主机还未开机,但是PS2口就有了5V,此时单片机就会发送0XAA,但主机能收到吗,难道是我发的时间不对吗?我用串口工具监测主机发过来的指令,收到的顺序是F6 F2 EE F4 ED ED F2,我也依次回复了,但和资料上的顺序不一样,因此通不过自检啊急死了,盼高手能给我一个准确的回复,感激不尽

相关帖子

沙发
jimsboy| | 2008-3-15 11:37 | 只看该作者

好象要把哪个脚拉一下作为开始信号的

我也是听朋友说我,我没弄过

使用特权

评论回复
板凳
guantouren|  楼主 | 2008-3-15 12:00 | 只看该作者

主机发送要拉低CLK信号

这都是发送字节时的要求,但我想知道主机发了些什么字节

使用特权

评论回复
地板
xxdcq| | 2008-3-15 12:21 | 只看该作者

这是ps/2协议的精华所在

慢慢捉摸吧!

使用特权

评论回复
5
wxj1952| | 2008-3-15 13:18 | 只看该作者

书上有

PC机接口大全,海淀图书城。

http://www.21ic.com/news/html/64/show771.htm
基于89C51的计算机可锁定加密键盘设计


网上搜索:
《PC机键盘接口深入分析与应用设计》

使用特权

评论回复
6
zgl7903| | 2008-3-15 13:51 | 只看该作者

主机上电后约0.5S左右发

看看这个网上的资料
http://www.computer-engineering.org/ps2protocol/

使用特权

评论回复
7
xxdcq| | 2008-3-15 14:49 | 只看该作者

有的电脑适应不了

http://www.computer-engineering.org/ps2protocol/
按照这上面的协议做还是有问题的
有的电脑适应不了
需要自己做点修改才能适应所有的电脑

使用特权

评论回复
8
huangqi412| | 2008-3-15 17:59 | 只看该作者

没做过

使用特权

评论回复
9
guantouren|  楼主 | 2008-3-15 20:58 | 只看该作者

请问有人用MCU做过相似的吗?

使用特权

评论回复
10
guantouren|  楼主 | 2008-3-15 21:06 | 只看该作者

请问有人用51的MCU做过相似的吗?

为什么我接收到的主机命令和资料上不一样呢
通过串口检测,初始化的接受发送都正常,按键后发第一个通码也正常发出,但是发断码的时候,主机立刻就把CLK拉低了,连鼠标都不动了。明天我把程序发过来让高手看看吧

使用特权

评论回复
11
常来21ic| | 2008-3-16 18:08 | 只看该作者

刚用51模拟了一个ps2鼠标

1、还有键盘上电就要对主机发0XAA,但是什么时候发呢,主机还未开机,但是PS2口就有了5V,此时单片机就会发送0XAA,但主机能收到吗,难道是我发的时间不对吗?

答:主机没有开机之前,主机是不能接收到数据的。你可以这样做,键盘上电后一直发0xAA,直到主机拉低CLK,说明主机要给你发数据2了,那你就应该开始接收,然后遵循协议把对应的响应字节发给主机,直到完成初始化。


2、我看了很多资料,但99%的都只讲到PS2协议的时序,没有详细讲启动时主机对PS2键盘发了那些命令,而键盘又回了哪些命令。

答:有份中英文对照的资料  《PS/2 技术参考》 (老古开发网有下载的),主机与PS2键盘的握手命令里面讲得很清楚的!
我当时还想找原版的协议规范,但是没有找到,哪位有的,希望能共享出来。


3、我用串口工具监测主机发过来的指令,收到的顺序是F6 F2 EE F4 ED ED F2,我也依次回复了,但和资料上的顺序不一样,因此通不过自检啊急死了,

答:串口工具的时序和ps2协议的时序对得上吗?对不上的话能接收正确吗?

上个星期我用51i/o口模拟ps2鼠标时候也很头痛,哎,做技术痛苦啊!
总之楼主不要太着急,ps2协议很简单的,模拟了一个简易的ps2鼠标/键盘不会太难。
认真看下资料,再检查一下自己的代码是否正确,祝你好运!

使用特权

评论回复
12
guantouren|  楼主 | 2008-3-16 21:46 | 只看该作者

今天有点成就了,但不适应所有主机

回复12楼:我的串口只是起检测作用,把主机发过来的命令字节显示出来,仅此而已,和PS2时序没有什么关系,所以我奇怪为什么我受到的命令顺序不对。
再问:我用标准键盘带入系统可以使用,是否能说明我发送的时序正确。而且我按CAPS键后也能收到主机随后的ED和04两个字节,是否能说明我接受的时序也是正确的。
再问:我发AA是在检测到主机第一次拉低发命令并回复后再发的AA,这样可以吗。
今天我把发通断码中间加入的发送串口命令注释掉,好了一台,但有的主机还不行,毛病是刚加电还在DOS模式下可以用,按DEL进入CMOS设置也都可以,但进入系统后就不行,看来没有找到问题根本所在。

使用特权

评论回复
13
guantouren|  楼主 | 2008-3-16 21:50 | 只看该作者

发程序给大家看看,帮我找找问题(接收函数)

/*  如果pc机发送数据,则pc机要先把时钟线和数据线置为请求发送的状态   */

/*  pc机通过下拉时钟线大于100μs来抑制通讯,并且通过下拉数据线发出
    请求发送数据的信号,然后释放时钟                                 */

/*  释放时钟后,即时钟=1,开始进行接收                               */

/*    Summary: Bus States
    Data = high, Clock = high: Idle state.                空闲状态,键盘可发送
    Data = high, Clock = low:  Communication Inhibited.      通讯禁止
    Data = low,  Clock = high: Host Request-to-Send          主机请求发送
*/

void Get_hostcode()           //同发送相比,多了一个ACK位
{
      byte i;
    byte temp=0; 
    byte temp1=0;

    PS2CLK  = 1;        //置输入状态
    PS2DATA = 1;

    //while(PS2CLK==0){putbyte(0x11);}    //如果检测到数据线为0且主机释放CLK则表示主机有发送请求
    if(PS2DATA)
    {
        status=NORMAL;
        return;
    }
                  
    else
    {
        DELAYUS(40);
        for(i=0;i<8;i++)    //====================================前8个时钟接收8位数据
        {
            PS2CLK=1;              //pull up clk
            DELAYUS(15);          //delay 20us
            PS2CLK=0;              //pull down clk     CLK第一个低电平后读取第0个数据
            DELAYUS(40);          //delay 40us
            PS2CLK=1;              //release clk
            DELAYUS(15);
            temp=temp>>1;       //先读最低位
            if(PS2DATA)              //主机在1->0改变数据,高电平稳定,所以键盘应该在CLK高电平时读取主机
            {
                temp=temp|0x80;      //0x80=10000000,如果DATA位是1则同最高位1相或
            }            
            readhost=temp;
            
            if(!PS2CLK)        //每读完一个位都检测时钟线是否被拉低
            {
                status=R8CLK_LOW;      //拉低则终止接收
                return;            
            }
        }
        temp1=temp;
   //=============================================================第9个时钟读取奇偶校验位
        DELAYUS(15);          //delay 20us
        PS2CLK=0;              //pull down clk
        DELAYUS(40);          //delay 40us
        PS2CLK=1;              //release clk
        DELAYUS(18);
        parity=PS2DATA;
        if(!PS2CLK)        //每读完一个位都检测时钟线是否被拉低
        {
            status=RpCLK_LOW;      //拉低则终止接收
            return;            
        }
   //==============================================================第10个时钟读取停止位
        DELAYUS(18);          //delay 20us
        PS2CLK=0;              //pull down clk
        DELAYUS(40);          //delay 40us
        PS2CLK=1;              //release clk
        DELAYUS(18);          // ! 未进行停止位校验
        STOPBIT=PS2DATA;
        if(!PS2CLK)        //每读完一个位都检测时钟线是否被拉低
        {
            status=RsCLK_LOW;      //拉低则终止接收
            return;            
        }
    //=============================================================
        if(!PS2DATA)
           {
              while(!PS2DATA)   //如数据为低产生时钟直到数据线为高
              {   
                 DELAYUS(18);
                 PS2CLK=0;
                 DELAYUS(40);
                 PS2CLK=1;
                 DELAYUS(18);
              }
              status=STOPERR;
            return;
           }

        DELAYUS(15);            //输出应答位
        PS2DATA=0;                //0
        nop;
        nop;
        nop;
        nop;
        nop;
        PS2CLK=0;
        DELAYUS(40);
        PS2CLK=1;                //释放时钟
        nop;
        nop;
        nop;
        nop;
        nop;
        PS2DATA=1;                //释放数据线
        //**************************************************//
        ACC=temp;
        if(P==parity)            //进行奇偶校验            
        {
            status=CHECKERR;
            return;
        }            
        DELAYUS(45);            //延时45us,以便PC机进行下一次传输
        hostcode=temp;
        //putbyte(0x99);
        //putbyte(temp1);
        //if(STOPBIT)
        //putbyte(0x91);
        //else putbyte(0x90);
        status=GETOK;
        return;
    }                
}

使用特权

评论回复
14
guantouren|  楼主 | 2008-3-16 21:51 | 只看该作者

发送程序

void Send_PS2byte(byte ps2byte)
{
    byte i=0; 
    byte temp=ps2byte;

    putbyte(ps2byte);
    ACC=ps2byte;
    parity=!P;         //求出奇偶校验位         

    PS2CLK=1;
    PS2DATA=1;
//=====================================检测主机是否发送请求====================
    /*while(!PS2CLK)                    //如果时钟线为低,则延时50us,再继续检测    
    {
        DELAYUS(50);
        if(!PS2CLK)
        {
            if(!PS2DATA)
            {
                status=GET_HOSTCODE;
                return;                      //数据低电平则放弃发送,转向读取主机数据
            }
            putbyte(0x88);
        }
        else break;                            //brea是跳出循环,继续执行循环外的语句    //而return是结束整个函数        
    }*/                                
    if(!PS2DATA) {status=SCANDATA_LOW;return;}        
//==============================================================================                  
    else                              //数据高电平就开始发送,从起始位开始
    {
        //PS2CLK=1;
        //DELAYUS(40);        //时钟高电平DATA改变 时钟低电平DATA被主机读取
        PS2DATA=0;            //发送start位要多用20us
        DELAYUS(20);        
        PS2CLK=0;            //拉低时钟
        DELAYUS(40);
        PS2CLK=1;            //释放时钟
        DELAYUS(15);
 //===============================================
        for(i=0;i<8;i++)    //高电平的中间即20US,DATA改变
        {
            if(temp&0x01)
                 PS2DATA=1;
              else
                 PS2DATA=0;
              temp>>=1;
      //============================================================        
            DELAYUS(20);        
            PS2CLK=0;            //拉低时钟
            DELAYUS(40);
            PS2CLK=1;            //释放时钟
            DELAYUS(13);
      //============================================================
              if(!PS2CLK)
            {
                status=S8CLK_LOW;
                return ;    //在送出每一位后都要检测时钟线,以确保pc机没有抑制ps/2设备,如果有则中止发送;
            }            
        }
 //============================================================
         nop;
        nop;
        PS2DATA=parity;        //输出校验位
        DELAYUS(20);        
        PS2CLK=0;            //拉低时钟
        DELAYUS(40);
        PS2CLK=1;            //释放时钟
        DELAYUS(20);    
        if(!PS2CLK)
        {
            status=SpCLK_LOW;
            return ;    //在送出每一位后都要检测时钟线,以确保pc机没有抑制ps/2设备,如果有则中止发送;
        }    
      //============================================================
        PS2DATA=1;            //输出停止位,总为1
        DELAYUS(20);        
        PS2CLK=0;            //拉低时钟
        DELAYUS(40);
        PS2CLK=1;            //释放时钟
        /*if(!PS2CLK)
        {
            DELAYUS(50);
            if(!PS2CLK)
            {
                status=SsCLK_LOW;
                return ;    //在送出每一位后都要检测时钟线,以确保pc机没有抑制ps/2设备,如果有则中止发送;
            }
            else
            {
                status=SENDOK;        
                return ;
            }
        }*/
        DELAYUS(50);    
            
      //============================================================
          status=SENDOK;        
        return ;    
    }                 
}

使用特权

评论回复
15
guantouren|  楼主 | 2008-3-16 21:53 | 只看该作者

检测程序

void Scanhost()
{
    if(PS2CLK==0)                 //等待主机释放时钟
    {
        DELAYUS(60);                 //等待100us后再检测
        if((PS2CLK==0)&&(PS2DATA==0))       /*通知键盘接受命令字节,同时也作为起始位*/
        {
            status=GET_HOSTCODE;
            putbyte(GET_HOSTCODE);
        }
    }
    else if((PS2CLK==1)&&(PS2DATA==1))
    status=NORMAL;
}

使用特权

评论回复
16
guantouren|  楼主 | 2008-3-16 21:54 | 只看该作者

主程序

    byte i=0;
   InitialCPU();
   InitialVariable();
   TempTurn(2);
   putbyte(0x55);
   putbyte(0xAA);
   putbyte(0x01);
   putbyte(readtemp[2]);
   TempCtrl(readtemp[2]);
   //delayms(800);
   //KeyInit();   
   //putstring("Serial Port is OK");
   //Send_PS2byte(0xAA);
   //putbyte(status);
   while(1)
   { 
        //Send_PS2byte(0xAA);     
     Scanhost();
     //putbyte(status);
     if(status==GET_HOSTCODE)     //0xC1
     {
         putbyte(0x01);
         Get_hostcode();
        putbyte(status);
        if(status==GETOK)
        {
            switch(hostcode)
            {
            case 0xF2:
                 Send_PS2byte(0xAB);
                 putbyte(status);
                 DELAYUS(50);
                 Send_PS2byte(0x83);
                 putbyte(status);
                 DELAYUS(50);
                 break;
            case 0xFF:
                 Send_PS2byte(0xAA);
                 putbyte(status);
                 DELAYUS(50);
                 fg_AAsent=1;
                 break;
            case 0xEE:
                 Send_PS2byte(0xEE);
                 putbyte(status);
                 DELAYUS(50);
                 break;
            case 0xF4:
                 Send_PS2byte(0xFA);
                 keyscan_enable=1;
                 putbyte(status);
                 DELAYUS(50);
                 break;
            case 0xED:
                 Send_PS2byte(0xFA);
                 putbyte(status);
                 DELAYUS(50);
                 break;
            case 0xF3:
                 Send_PS2byte(0xFA);
                 putbyte(status);
                 DELAYUS(50);
                 break;
            case 0x20:
                 Send_PS2byte(0xFA);
                 putbyte(status);
                 DELAYUS(50);
                 break;
            default:
                 Send_PS2byte(0xFA);
                 putbyte(status);
                 DELAYUS(50);
                 break;
            }
            if(fg_AAsent==0)
            {
                Send_PS2byte(0xAA);
                putbyte(status);
                DELAYUS(50);
                if(status==SENDOK)
                fg_AAsent=1;
            }            
        }
        
        /*if(status==OK)
        {
            putbyte(readhost[0]);
            putbyte(readhost[1]);
            putbyte(readhost[2]);
            putbyte(readhost[3]);
            putbyte(readhost[4]);
            putbyte(readhost[5]);
            putbyte(readhost[6]);
            putbyte(readhost[7]);
            Send_PS2byte(0xFA);
        }*/
     }
     else if(status==NORMAL)      //0xBD
     {         
        Keyscan();            
     }
     


     if((heatortime==0)&&(fg_heaton==1))
     {
         
         HEATOR=0;
        fg_heaton=0;
     }
   }
}

使用特权

评论回复
17
guantouren|  楼主 | 2008-3-16 21:55 | 只看该作者

请大家帮我找找问题吧,谢谢

使用特权

评论回复
18
xwj| | 2008-3-17 08:25 | 只看该作者

进Windows时会重新检测硬件,估计时你没有应答它的某个指令

使用特权

评论回复
19
gregy_cn| | 2008-7-21 13:17 | 只看该作者

翻老贴

我最近在做PS2键盘,使用的51单片机。原来初始化一直有问题,来这里翻了一阵儿老贴。现在基本解决了。
guantouren程序我看了看,程序在收到0xff复位命令时没有回复0xfa的应答。我现在在收到0xff之后立即回复了0xfa,然后延时500ms左右发0xaa。

使用特权

评论回复
20
tothen| | 2010-10-11 15:02 | 只看该作者
20  楼的,能QQ交流下吗,我也碰到和问题了,QQ:1104997876

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

11

帖子

2

粉丝