搜索
bottom↓
回复: 5

求助:51模拟PS2键盘,自检时电脑常死机,重拔插电源才通过

[复制链接]

出0入0汤圆

发表于 2014-5-16 20:59:32 | 显示全部楼层 |阅读模式
程序如下:

#include<reg52.h>    //包含单片机寄存器的头文件
#include<intrins.h>  //包含_nop_()函数定义的头文件
typedef    unsigned char  uint8 ;
typedef    unsigned int   uint16;
#define TURNON 1
#define TURNOFF 0
bit flag = TURNON;

//uint8 ctrl = 0x0;
static uint8 PS2RecChar1 = 0xCC;
/*******************************************************************************
以下是引脚定义
*******************************************************************************/
sbit PS2CLK1 = P1^4;         
sbit PS2DAT1 = P3^2;   
sbit ctrl0 = P1^5;
//sbit ctrl1 = P1^6;
//sbit ctrl2 = P1^7;
/*****************************************************
函数功能:延时
***************************************************/

void Delay_5us ()        //5.43us  晶振为11.0592M时调用一个函数要4个指令周期即4.34us,也就是说每多一个加一个指令周期(1/f)*12=1.085us
{        _nop_();
}
void Delay_10us ()        //
{        _nop_();_nop_();_nop_();_nop_();_nop_();
}

void Delay_20us ()       //19.53us
{         
        _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();
}
void Delay_15us ()       //15.19us
{         
        _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
}
void Delay_13us ()      //13.02
{         
        _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
}
void Delay_40us ()      //39.06
{         
        _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();
}
void Delay_50us ()      //50.1
{         
        _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();
}

void delay_ms ( uint16 t )
{
        uint16 i,j;
        for ( i = t; i > 0; i-- )
                for ( j = 110; j > 0; j-- )
                                ;               
}

void init_serial()
{
T2CON = 0x34;                           //Set the Counter/Timer2 for the baud rate generator
RCAP2H = 0xFF;                           //T2 baud is 38400          
RCAP2L = 0xF7;          
SCON = 0x50;                           //Serial port in Mode 2
EA=1;
ES = 1;                                  //Allow serial interrupt
}          

//==================================================
//    c51模拟PS2键盘和PC机通讯程序
//     发送程序代码
//==================================================

void OnPS2SendChar1 ( uint8 dat )
{
        uint8 h = 0, j;
        uint8 i = 8;
  bit bparity = 0 ;

ACC = dat;                                                                                   //获取字节的奇偶信息
if ( !P )                                                                                       //ACC中偶数时,P为0,但是PS2中时奇校验( 字节中的1的个数+校验位 = 奇数)
                bparity = 1;

if( PS2CLK1 && PS2DAT1 )                                                                     //发送前检测PS2总线
                 {
                                Delay_50us ();                                                             //50us   
                                if ( PS2CLK1 )                                    //时钟线空闲
                                                {
                                                         if ( PS2DAT1 )                              //数据线空闲
                                                                         {
                                                                                        for (j = 11;j > 0;j--)               //1共11个数据
                                                                                                        {
                                                                                                                 if ( h == 0 )                 // 送起始位
                                                                                                                                 {
                                                                                                                                                PS2DAT1 = 0;
                                                                                                                                                h++;
                                                                                                                                 }
                                                                                                                 else if ( h == 1 )            //送8位数据位
                                                                                                                                 {
                                                                                                                                                PS2DAT1 = dat & 0x01; //先LSB开始
                                                                                                                                                dat >>= 1;
                                                                                                                                                i--;
                                                                                                                                                if        (i == 0)           //发送完成
                                                                                                                                                                 h++;
                                                                                                                                 }
                                                                                                                 else if ( h == 2 )            //送校验位
                                                                                                                                 {
                                                                                                                                                PS2DAT1 = bparity;
                                                                                                                                                h++;
                                                                                                                                 }
                                                                                                                 else
                                                                                                                                 { PS2DAT1 = 1; }               //送停止位
                                                                                                                 //Delay_10us ();                 //10us
                                                                                                                 Delay_13us ();                   //数据改变后,到此处耗时6.51us
                                                                                                                 PS2CLK1 = 0;                   //拉低时钟线,设备发送
                                                                                                                 Delay_40us ();                 //40us
                                                                                                                 PS2CLK1 = 1;                    
                                                                                                                 Delay_5us ();                 //for循环到下一次DATA置1时程序本身要耗时约20us
                                                                                                                 if ( !PS2CLK1 )                //检测到时钟线变低
                                                                                                                                 {                                                                                             //主机不要这次通讯 (很罕见)
                                                                                                                                                break;                  //return;
                                                                                                                                 }
                                                                                                        }
                                                                                        //Delay_15us ();                        //发送完一包后延迟30us     
                                                                                        //Delay_15us ();               
                                                                         }//if(PS2DAT)
                                                         else
                                                                                return;                              //主机发送命令,KB转入接收程序
                                                 }//if(PS2CLK)
                 }//if(PS2CLK&&PS2DAT)
}//end

//======================================================================
//    c51模拟PS2键盘和PC机通讯程序
//     接收程序代码
//======================================================================

void OnPS2ReceChar1 (  )
{       
        bit bparity = 1 ; //奇偶校验错误,明天来确认。原来为0 改为1后进不了系统!
        bit ParityBit = 0 ;
        bit DATAFlag = 1;
        uint8 dat = 0x0, i;
        if  ( !PS2DAT1 )                                         
                        {
                                //标准键盘DATA线拉低250us后产生时钟,所以我在延迟约200us后再检测DATA
                                Delay_50us () ;   
                                Delay_50us () ;
                                Delay_50us () ;
                                if ( !PS2DAT1 )
                                                {                                               //data为低,则读取一个字节
                                                                for ( i = 0; i < 8; i ++ )//read 8bit
                                                                                 {
                                                                                                _nop_();          //1T
                                                                                                 Delay_20us ();
                                                                                                PS2CLK1 = 0;                      //1T
                                                                                                Delay_40us ();                    
                                                                                          PS2CLK1 = 1;                      //1T
                                                                                          dat = dat >> 1;                   //4T
                                                                                                if ( PS2DAT1 )                    //2T
                                                                                                        {
                                                                                                                dat|=0x80;                    //2T
                                                                                                                bparity = ~bparity;           //1T
                                                                                                        }
                                                                                                else
                                                                                                        {
                                                                                                                _nop_();_nop_();_nop_();
                                                                                                        }
                                                                                                if ( PS2CLK1 == 0 )               //2T
                                                                                                        { return; }             //如果时钟被拉低,则有错误发生,发送0XFE报错
                                                                                                //OnPS2SendChar1 ( 0xfe );
                                                                                 }                                    //6T
                                                                                                       
                                                                 Delay_20us ();                                     //读取校验位     
                                                                 PS2CLK1 = 0;           
                                                                 Delay_40us ();
                                                                 PS2CLK1 = 1;
                                                                 Delay_20us ();
                                                                 if ( PS2DAT1 )
                                                                                ParityBit = 1;
                                                                 else
                                                                                ParityBit = 0;
                                                                 
                                                                 Delay_20us ();                                     //越过停止位  
                                                                 PS2CLK1 = 0;           
                                                                 Delay_40us ();
                                                                 PS2CLK1 = 1;
                                                                 Delay_20us ();       //STOP BIT H_DATA 0 ERR
                                                                 /*
                                                                 if ( !PS2DAT1 )                                    //如果DATA线为低,输出CLK直到DATA线为高  
                                                                                {  
                                                                                         DATAFlag = 0;
                                                                                         Delay_20us ();                                    
                                                                                         PS2CLK1 = 0;           
                                                                                         Delay_40us ();
                                                                                         PS2CLK1 = 1;
                                                                                         Delay_20us ();      
                                                                                }               
                                                                 if ( DATAFlag == 0 )
                                                                         OnPS2SendChar1 ( 0xfe );
                                                                 */
                                                                 
                                                                 Delay_10us ();                                      //协议中要求15us后
                                                                 PS2DAT1 = 0;                                          //ACK bit
                                                                 Delay_10us ();                                      //协议中要求5us后
                                                                 PS2CLK1 = 0;
                                                                 Delay_40us ();
                                                                 PS2CLK1 = 1;
                                                                 Delay_10us ();                                      //协议中要求5us后,我发现5us时间太短,ASK上升沿会与CLK上升沿重合
                                                                 PS2DAT1 = 1;
                                                                 /*
                                                                 Delay_40us ();
                                                                 PS2CLK1 = 0;
                                                                 Delay_40us ();
                                                                 Delay_20us ();
                                                                 PS2CLK1 = 1;
                                                                 */
                                                                 if ( ParityBit == bparity )
                                                                         PS2RecChar1 = dat;
                                                                 else
                                                                         OnPS2SendChar1 ( 0xfe );                                                                                   //校验错误,请求重发,而不是报错0XFC
                                                                 Delay_40us ();                                         //延迟45us
                                                                 Delay_5us ();
                                                         }
                                        }
}

//======================================================================
//    c51模拟PS2键盘和PC机通讯程序
//     开机自检程序代码
//======================================================================

void ProcessPS21 ( void )
{
        if ( PS2RecChar1 != 0xCC )                             
        {
                switch ( PS2RecChar1 )
                {       
                        case 0xEE:                        
                        {
                                OnPS2SendChar1 ( 0xEE );
                                //Delay_50us () ;
                                delay_ms ( 1 );
                                PS2RecChar1 = 0xCC;
                        } break;
                        case 0xFE:                         //7 //resend
                        {
                                PS2RecChar1 = 0xCC;
                        } break;
                        case 0xAA:                           //12
                        {
                                OnPS2SendChar1 ( 0xAA );
                                //Delay_50us () ;
                                delay_ms ( 1 );
                                PS2RecChar1 = 0xCC;
                        } break;
                        case 0xEF:                         //5
                        {
                                OnPS2SendChar1 ( 0xFA );
                                //Delay_50us () ;
                                Delay_50us () ;Delay_50us () ;Delay_50us () ;Delay_50us () ;Delay_50us () ;
                                OnPS2SendChar1 ( 0xBF );
                                //Delay_50us () ;
                          Delay_50us () ;Delay_50us () ;Delay_50us () ;Delay_50us () ;Delay_50us () ;
                                OnPS2SendChar1 ( 0xB0 );
                                //Delay_50us () ;
                                delay_ms ( 1 );
                                PS2RecChar1 = 0xCC;
                        } break;
                        case 0xF2:
                        {
                                OnPS2SendChar1 ( 0xFA );
                                //Delay_50us () ;
                                Delay_50us () ;Delay_50us () ;Delay_50us () ;Delay_50us () ;Delay_50us () ;
                                OnPS2SendChar1 ( 0xAB );
                                //Delay_50us () ;
                                Delay_50us () ;Delay_50us () ;Delay_50us () ;Delay_50us () ;Delay_50us () ;
                                OnPS2SendChar1 ( 0x83 );
                                //Delay_50us () ;
                                delay_ms ( 1 );
                                PS2RecChar1 = 0xCC;
                        } break;
                        case 0xFF:
                        {
                                OnPS2SendChar1 ( 0xFA );
                                //Delay_50us () ;
                                Delay_50us () ;Delay_50us () ;Delay_50us () ;Delay_50us () ;Delay_50us () ;
                                OnPS2SendChar1 ( 0xAA );
                                //Delay_50us () ;
                                delay_ms ( 1 );
                                PS2RecChar1 = 0xCC;
                        } break;
                        default:
                        {
                                OnPS2SendChar1 ( 0xFA );
                                //Delay_50us () ;
                                delay_ms ( 1 );
                                PS2RecChar1 = 0xCC;
                        } break;       
                }
        }       
}


/*
void ProcessPS21 ( void )
{
       
                if( PS2RecChar1 == 0xF3 )//1
                {
                        OnPS2SendChar1 ( 0xFA );
                        PS2RecChar1 = 0xCC;
                }
                else if( PS2RecChar1 == 0x00 )//11
                {
                        OnPS2SendChar1 ( 0xFA );
                        PS2RecChar1 = 0xCC;
                }
                else if( PS2RecChar1 == 0x02 )//111
                {
                        OnPS2SendChar1 ( 0xFA );
                        PS2RecChar1 = 0xCC;
                }
                else if( PS2RecChar1 == 0x20 )//1111
                {
                        OnPS2SendChar1 ( 0xFA );
                        PS2RecChar1  = 0xCC;
                }
                else if( PS2RecChar1 == 0xED )//2
                {
                        OnPS2SendChar1 ( 0xFA );
                        PS2RecChar1 = 0xCC;
                }
                else if( PS2RecChar1 == 0xF0 )//3
                {
                        OnPS2SendChar1 ( 0xFA );
                        PS2RecChar1 = 0xCC;
                }
                else if( PS2RecChar1 == 0xF2 )//4
                {
                        OnPS2SendChar1 ( 0xFA );
//                        Delay30us();
                        OnPS2SendChar1 ( 0xAB );
//                        Delay30us();
                        OnPS2SendChar1 ( 0x83 );
                        PS2RecChar1 = 0xCC;
                }
                else if( PS2RecChar1 == 0xEF )//5
                {
                        OnPS2SendChar1 ( 0xFA );
//                        Delay30us();
                        OnPS2SendChar1 ( 0xBF );
//                        Delay30us();
                        OnPS2SendChar1 ( 0xB0 );
                        PS2RecChar1 = 0xCC;
                }
                else if ( PS2RecChar1 == 0xF3 )//6
                {
                        OnPS2SendChar1 ( 0xFA );
                        PS2RecChar1 = 0xCC;
                }
                else if(PS2RecChar1==0xFE)//7 //resend
                {
                        PS2RecChar1=0xCC;
                }
                else if(PS2RecChar1 == 0xEE)//8
                {
                        OnPS2SendChar1 ( 0xEE );
                        PS2RecChar1 = 0xCC;
                }
                else if(PS2RecChar1 == 0xEE)//9
                {
                        OnPS2SendChar1 ( 0xEE );
                        PS2RecChar1 = 0xCC;
                }
                else if (PS2RecChar1 == 0xF1)//10
                {
                        OnPS2SendChar1 ( 0xFA );
                        PS2RecChar1 = 0xCC;
                }
                else if (PS2RecChar1 == 0xF4)//11
                {
                        OnPS2SendChar1 ( 0xFA );
                        PS2RecChar1 = 0xCC;
                }
                else if (PS2RecChar1 == 0xAA )//12
                {
                        OnPS2SendChar1 ( 0xAA );
                        PS2RecChar1 = 0xCC;
                }
                else if ( PS2RecChar1 == 0xFF )//13
                {
                        OnPS2SendChar1 ( 0xFA );
//                        Delay30us();
                        OnPS2SendChar1 ( 0xAA );
//                        Delay30us();
                        PS2RecChar1 = 0xCC;
                }
                else ;
       
}
*/

/********************************************************************************************************************/
//                 主程序                                            
/********************************************************************************************************************/
void main(void)
{
        uint8 temp;
        uint8 code table[]={0x1c,0x32,0x21,0x23,0x24,0x2b,0x34,0x33,0x43,0x3b};         //     A,B,C,D,E,F,G,H,I,J                  
        //PS2Init ( );                                                //开中断
        ctrl0 = 0;
        PS2DAT1 = 1;
        PS2CLK1 = 1;
        init_serial();
        while(1)
        {
                if ( PS2DAT1 == 0 )
                {
                        Delay_50us () ;
                        if ( PS2DAT1 == 0 )
                        {
                                OnPS2ReceChar1 (  );
                        }                       
                }
                if ( PS2RecChar1 != 0xCC )                             
                {
                        TI=0;
                  SBUF = PS2RecChar1;
                  while( !TI );
                  TI = 0;
                        Delay_50us () ;
                        Delay_50us () ;
                        Delay_50us () ;
                        ProcessPS21 (  );
                }
                /*
                if ( ctrl0 == 1 )  //不停的发q
                        {
                                OnPS2SendChar1 ( 0X15 );                //按下通码
                                delay_ms ( 2 );
                                OnPS2SendChar1 ( 0xF0 );        //抬起,断码
                                delay_ms ( 1 );           //每发一包数据后,时钟会拉低约200us,如果立刻发下一包数据,将被忽略
                                OnPS2SendChar1 ( 0X15 );
                                delay_ms ( 1000 );
                        }
     */
       
                if ( ( ctrl0 == 1 ) && ( flag == TURNON ) )  //发送abcdefghij
                {
                        flag = TURNOFF;
                        for ( temp = 0; temp < 10; temp ++ )
                        {
                                OnPS2SendChar1 ( table[temp] );                //按下通码
                                delay_ms ( 2 );
                                OnPS2SendChar1 ( 0xF0 );        //抬起,断码
                          delay_ms ( 1 );           //每发一包数据后,时钟会拉低约200us,如果立刻发下一包数据,将被忽略
                                OnPS2SendChar1 ( table[temp] );
                                delay_ms ( 500 );
                        }
                }
                               
        }
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2014-5-16 21:16:40 | 显示全部楼层
楼主模拟PS2键盘有什么用呢?

出0入0汤圆

 楼主| 发表于 2014-5-16 21:21:02 | 显示全部楼层
当正常自检通过时,将收到的数据通过串口转发到其它电脑,可以确认的是收数正常;当进入系统后,把p1.5接高电平能正常发数。
个人觉得应该是程序其它部分有BUG,但就是找不出来,串口抓到的数据是00 F6 F2,到此就死机不动了,必须重拔插电源。

正常通过自检时主机发给键盘的数据奉献给需要的朋友:
依次是FF F6 F2 EE F2 ED 00 F4 F2 ED 02 F6
FF F3 00 ED 00 ED 00 F3 20 F3 20 ED 02

出0入0汤圆

 楼主| 发表于 2014-5-16 21:28:34 | 显示全部楼层
做一种产品测试工装,一次测8台,其中一项是测试PS2,做高低温应力筛选实验,同时接8个键盘就失去了自动测试的意义

出0入0汤圆

发表于 2014-5-16 21:47:09 | 显示全部楼层
关注中, 几年前我也用汇编写过模拟PS2键盘的程序, 实际连接到PC时有些PC可以通过开机检测, 有些PC通不过, 到现在还不清楚是什么原因!

出0入0汤圆

发表于 2014-5-23 00:32:43 | 显示全部楼层
与楼上相同的遭遇貌似是自检协议完整性不好。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 12:26

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表