打印

单片机做PS/2键盘,初始化存在问题

[复制链接]
9213|43
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dosculler|  楼主 | 2012-1-4 14:36 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 dosculler 于 2012-1-14 15:08 编辑

产品:单片机做PS/2键盘,
前因后果:
    以前出现问题是开机后单片机向电脑发码,电脑死机
    或者是开机时,电脑进入不了出现蓝屏。
    后来修改了几个星期,没出现问题,
    只是一直存在一个旮旯,初始化时间慢了一点,
    一直觉得有隐患存在

事件:最近有一家客户反应没有插鼠标,该产品当PS/2键盘连接电脑,启动进入电脑后,单片机向电脑发键值没有反应。

电路图是直接IO口连接外部电脑。
硬件用的实时扫描,没用中断,不过没在其他地方浪费时间。
发送的程序在38楼,请问各位大侠是如何处理该段的。附上实例最好,非常感谢!
初始化程序如下:
void PS2_Init()    //串口检测开机,一般收到FF、ED、F3、F2、00
{
uchar command;
command=rev;
if(!command)
  return;
switch(command)
{
        //在上电或软件复位后,键盘执行诊断自检叫做BAT(基本保证测试)
  case 0xFF: //此时BAT 完成代码要么0xAA(BAT 成功) 或0xFC(有错误)被发送到主机
   PS2_Send(0xFA); //若去掉,开机接受数据卡死
   PS2_Send(0xAA); //BAT Self-Check successed
   break;
  case 0xED:     //Set/Reset Status Indicators  ;BIOS init
   PS2_Send(0xFA);
   break;
  case 0x00:    //1.Turn off all LEDs 2.250ms/30.0 reports/sec
   PS2_Send(0xFA);  
  // PS2_Send(0xFE);
   break;  
  case 0xF2:    //Read ID
   PS2_Send(0xFA);  //键盘回应两个字节的设备ID 0xAB 0x83
   PS2_Send(0xAB);
  //    PS2_Send(0x83);
   break;
  case 0x02:  //Turn on Num Lock LED
   PS2_Send(0xFA);
   break;
  case 0xF3:  //Set Typematic Rate/Delay ;Windows init
   PS2_Send(0xFA);
   break;
  case 0x20:  //500ms/30.0 reports/sec
   PS2_Send(0xFA);
   break;
  case 0xF4:  //Enable
   PS2_Send(0xFA);
   break;
  case 0xFE: //重发上次数据
   PS2_Send(0xFA);
//   PS2_Send(send_last_ps2);
   break;
  case 0xEE:  //键盘用"ECHO"(0xEE)回应
   //PS2_Send(0xFA);  //不用??
   PS2_Send(0xEE);
   break;
  case 0xFD:  
   PS2_Send(0xFA);  
   break;
  case 0xFC:  
   PS2_Send(0xFA);  
   break;
  case 0xFB:  
   PS2_Send(0xFA);  
   break;
  case 0xFA:  
   PS2_Send(0xFA);  
   break;
  case 0xF9:  
   PS2_Send(0xFA);  
   break;
  case 0xF8:  
   PS2_Send(0xFA);  
   break;
  case 0xF7:  
   PS2_Send(0xFA);  
   break;
  case 0xF6:  
   PS2_Send(0xFA);  
   break;
  case 0xF5:  
   PS2_Send(0xFA);  
   break;
//  case 0xF4:  
//   PS2_Send(0xFA);  
//   break;
//  case 0xF3:  
//   PS2_Send(0xFA);  
//   break;
//  case 0xF2:  
//   PS2_Send(0xFA);  
//   break;
  case 0xF0:  
   PS2_Send(0xFA);  
   break;
  default:
  // PS2_Send(0xFA);  //切记:一定要去掉,不然进入自己协议处理时误了电脑处理有时进不了桌面导致蓝屏
   rev_ps2_byte=command;
   rev_ps2_flag=1;
   break;
}
}
     

添附:
接收程序如下
void PS2_Rev() //interrupt 2    //DO3
{
uchar i=0;
    //bit r0,r1,r2,r3,r4,r5,r6,r7;
//bit rev[8];
bit stop_bit=0,PARITY=0;

    EA=0;
if(CLOCK_PS2)//判断高电平退出
{
  EA=1;
  return ;
}
  
/* while(!CLOCK_PS2); //1. 等待时钟线为高电平。 */
TF0=0;   
TH0=0x0b;
TL0=0x7f;           
    TR0=1;
while((!TF0)&&(!CLOCK_PS2));//拉高10ms内返回,越短越好便于循环检测
TR0=0;   
TF0=0;   
         
if(DATA_PS2)    //2. 判断数据线是否为低,为高则错误退出,否则继续执行
{
// PS2_Send(0xfe); //0xfe是接收错误,这里不是也不能用,鼠标动时会返回数据
  EA=1;
  return ;
}
Delay40Us();//延时时间不定,取40us等待设备把时钟线拉低,开始传数据
//CLOCK_PS2=1; 主机自动拉高
Delay40Us();
CLOCK_PS2=0;
Delay40Us();//低电平主机改变数据线状态
CLOCK_PS2=1;  
Delay10Us();
// Delay10Us();//Delay20Us();
if (!CLOCK_PS2)
{
  EA=1;
  return ;
}
rev0=DATA_PS2;//bit 0

Delay25Us();
CLOCK_PS2=0;
Delay40Us();//低电平主机改变数据线状态
CLOCK_PS2=1;
Delay10Us();
// Delay10Us();//Delay20Us();
if (!CLOCK_PS2)
{
  EA=1;
  return ;
}// if KBCLK pull down, mean Host cancelled this sending
rev1=DATA_PS2;//bit 1   

Delay25Us();
CLOCK_PS2=0;
Delay40Us();//低电平主机改变数据线状态
CLOCK_PS2=1;
Delay10Us();
// Delay10Us();//Delay20Us();
if (!CLOCK_PS2)
{
  EA=1;
  return ;
}
rev2=DATA_PS2;//bit 2

Delay25Us();
CLOCK_PS2=0;
Delay40Us();//低电平主机改变数据线状态
CLOCK_PS2=1;
Delay10Us();
// Delay10Us();//Delay20Us();
if (!CLOCK_PS2)
{
  EA=1;
  return ;
}
rev3=DATA_PS2;//bit 3

Delay25Us();
CLOCK_PS2=0;
Delay40Us();//低电平主机改变数据线状态
CLOCK_PS2=1;
// Delay10Us();//Delay20Us();
Delay10Us();
if (!CLOCK_PS2)
{
  EA=1;
  return ;
}
rev4=DATA_PS2;//bit 4

Delay25Us();
CLOCK_PS2=0;
Delay40Us();//低电平主机改变数据线状态
CLOCK_PS2=1;
Delay10Us();
// Delay10Us();//Delay20Us();
if (!CLOCK_PS2)
{
  EA=1;
  return ;
}
rev5=DATA_PS2;//bit 5

Delay25Us();
CLOCK_PS2=0;
Delay40Us();//低电平主机改变数据线状态
CLOCK_PS2=1;
Delay10Us();
// Delay10Us();//Delay20Us();
if (!CLOCK_PS2)
{
  EA=1;
  return ;
}
rev6=DATA_PS2;//bit 6

Delay25Us();
CLOCK_PS2=0;
Delay40Us();//低电平主机改变数据线状态
CLOCK_PS2=1;
// Delay10Us();//Delay20Us();
if (!CLOCK_PS2)
{
  EA=1;
  return ;
}
rev7=DATA_PS2;//bit 7
Delay10Us();
Delay25Us();
CLOCK_PS2=0;
Delay40Us();//低电平主机改变数据线状态
CLOCK_PS2=1;
Delay10Us();
// Delay10Us();//Delay20Us();
/* if (!CLOCK_PS2)
{
  EA=1;
  return ;
}*/
PARITY=DATA_PS2;//parity bit

Delay25Us();
CLOCK_PS2=0;
Delay40Us();//低电平主机改变数据线状态
CLOCK_PS2=1;
// Delay10Us();//Delay20Us();
stop_bit=DATA_PS2;//stop bit
/* if (!CLOCK_PS2)
{
  EA=1;
  return ;
}*/// if (stop_bit!=1)
// {
//  PS2_Send(0xfe); //接收错误
//  EA=1;
//  return ;
// }
/* Delay20Us();  //附加中间一个脉冲
CLOCK_PS2=0;
Delay40Us();
CLOCK_PS2=1;
Delay20Us();   */
Delay20Us();
Delay15Us(); //ACK bit
DATA_PS2=0;
Delay5Us();
CLOCK_PS2=0;
Delay40Us();
CLOCK_PS2=1;
Delay5Us();
DATA_PS2=1;
/* DATA_PS2=0;
Delay20Us(); //ACK bit
CLOCK_PS2=0;
Delay40Us();
CLOCK_PS2=1;
Delay20Us();
DATA_PS2=1;  */
Delay50Us();//延时时间不定,取40us延时以便PC机进行下一次传输
PS2_Init();
  EA=1;
/* if(PARITY==Parity(rev_byte)) //=函数()不会报错
{
  return rev_byte;
  //EA=1;
}
else
{
  PS2_Send(0xFE);
  //EA=1;
  return 0;
}*/
}

相关帖子

沙发
xxdcq| | 2012-1-4 14:49 | 只看该作者
呵呵!
ps2我花了4年时间才扯清!

使用特权

评论回复
板凳
dengm| | 2012-1-4 15:49 | 只看该作者
这类应用一般用asm才能精确接口!!!

使用特权

评论回复
地板
dengm| | 2012-1-4 16:03 | 只看该作者
本帖最后由 dengm 于 2012-1-4 16:25 编辑

http://www.computer-engineering.org/ps2protocol/ 的最后:

Referring to Figure 4, there's two time quantities the host looks for.  (a) is the time it takes the device to begin generating clock pulses after the host initially takes the Clock line low, which must be no greater than 15 ms. (b) is the time it takes for the  packet to be sent, which must be no greater than 2ms.  If either of these time limits is not met, the host should generate an error.  Immediately after the "ack" is received, the host may bring the Clock line low to inhibit communication while it processes data.  If the command sent by the host requires a response, that response must be received no later than 20 ms after the host releases the Clock line.  If this does not happen, the host generates an error.

http://www.computer-engineering.org/ps2keyboard/

使用特权

评论回复
5
yewuyi| | 2012-1-4 16:14 | 只看该作者
PS2不都是公开协议了吗?

按照协议写就是喽。

使用特权

评论回复
6
xxdcq| | 2012-1-4 16:30 | 只看该作者
没有一篇权威的**讲述过ps2上电连接的细节过程,需要精确到us级
得自己一点点去探索才行!

使用特权

评论回复
7
dosculler|  楼主 | 2012-1-4 17:40 | 只看该作者
呵呵!
ps2我花了4年时间才扯清!
xxdcq 发表于 2012-1-4 14:49


是啊,PS/2做出来不难,但经常有这个那个的问题,
前辈能不能把相应的程序发一下,如果涉及到公司机密,
就只发上电初始化的子函数给我考虑下就可以了,非常感谢。
mail:786772100@qq.com

使用特权

评论回复
8
dosculler|  楼主 | 2012-1-4 17:43 | 只看该作者
5# yewuyi
有很多资料,也公司协议的,不过在初始化那块有点模糊不清。

基本上做出来也不难,之前出现开机死机蓝屏以及开机后向电脑发送码值后电脑死机两个问题,现在基本也已经解决了。

不过最近又发现没有插鼠标时,只插这个单片机模拟的PS/2键盘,发现好像没有认到这个“键盘”一样,单片机向电脑发的码值没有反应。

请问怎么回事?

使用特权

评论回复
9
dosculler|  楼主 | 2012-1-4 19:01 | 只看该作者
6# xxdcq
虽然没有权威的,但前辈的实例对启发作用是很大的。
求赏赐,嘿嘿

使用特权

评论回复
10
SmartEnergy| | 2012-1-4 23:54 | 只看该作者
协议一般都比较合理的。关键自己要清楚全部细节,铁定、严谨地考虑哪里可能出问题。高手的差别就在这一点点。

使用特权

评论回复
11
dengm| | 2012-1-5 01:33 | 只看该作者
微秒(microsecond)级定时, The host may inhibit communication at any time, 用C
很难完成, clock要接中断线。
在设备向主机发数据过程中, 必须检查 inhibit communication 状态!!!
The clock frequency is 10-16.7 kHz.  The time from the rising edge of a clock pulse to a Data transition must be at least 5 microseconds.  The time from a data transition to the falling edge of a clock pulse must be at least 5 microseconds and no greater than 25 microseconds.  


The host may inhibit communication at any time by pulling the Clock line low for at least 100 microseconds.  If a transmission is inhibited before the 11th clock pulse, the device must abort the current transmission and prepare to retransmit the current "chunk" of data when host releases Clock.  A "chunk" of data could be a make code, break code, device ID, mouse movement packet, etc.  For example, if a keyboard is interrupted while sending the second byte of a two-byte break code, it will need to retransmit both bytes of that break code, not just the one that was interrupted.

使用特权

评论回复
12
dosculler|  楼主 | 2012-1-5 10:45 | 只看该作者
11# dengm
微秒级这个肯定是做到了,用的是22.1184MHz晶振,
用示波器看了,40Us放大了不多不少。并且在跟键盘的波形做了对比,确保做到一模一样。
可是就是出现这样问题,
有没有哪位大侠给个具体、实际的解决办法或者尝试办法。

使用特权

评论回复
13
dosculler|  楼主 | 2012-1-5 10:48 | 只看该作者
协议一般都比较合理的。关键自己要清楚全部细节,铁定、严谨地考虑哪里可能出问题。高手的差别就在这一点点。
SmartEnergy 发表于 2012-1-4 23:54

也许是我不够细心,不过我确信在所能及的范围内已经很小心很仔细地检查过,这条键盘通信程序没有改过1千次,也改过3、5百次了。感觉上确实存在局部的小细节没有处理到,恼火啊。

使用特权

评论回复
14
dosculler|  楼主 | 2012-1-5 10:54 | 只看该作者
6# xxdcq
标题内容上我另外添加了段 "接收协议",
大神稍微花几分钟帮我看下有没有哪里有明显要修改的地方。
公司产品不容我一点点探索啊。
非常感谢!

使用特权

评论回复
15
xxdcq| | 2012-1-5 11:06 | 只看该作者
14# dosculler
邮件已发!
你的ps2_send()和ps2_REV()
中要把判断,置位,清零,跳转等操作都要算进延时时间里去
不能光靠DELAY程序本身的延时,这样会有差异

我是汇编搞的

使用特权

评论回复
16
dengm| | 2012-1-5 12:25 | 只看该作者
ps2_Send() 必须检查 inhibit communication 状态,
     如有inhibit communication 状态(host 发出), 必须转到 PS2_REV(), 并 安排 重发 1 or 2 bytes.  
建议用状态机完成项目. Send & rev 都在中断中完成( clock 线用 P3.3 or p3.2), rev 回 buffer, Send
最多2 bytes.

使用特权

评论回复
17
pcblover.com| | 2012-1-5 15:17 | 只看该作者
不是很懂,友情顶贴

使用特权

评论回复
18
huan1| | 2012-1-5 17:38 | 只看该作者
这类应用一般用asm才能精确接口!!!

使用特权

评论回复
19
dosculler|  楼主 | 2012-1-6 09:50 | 只看该作者
16# dengm

??inhibit communication是指时钟、数据线状态是吧。
有没有相应的资料参考下,不怕重复

使用特权

评论回复
20
dengm| | 2012-1-6 14:17 | 只看该作者
在设备发给主机时, 由设备提供时钟, 在设备提供时钟高时, 如发现时钟低, 就是被主机拉低, 就是
主机发出inhibit communication状态.

Summary: Bus States
Data = high, Clock = high:  Idle state.
Data = high, Clock = low:  Communication Inhibited.
Data = low, Clock = high:  Host Request-to-Send

ref: http://www.computer-engineering.org/ps2protocol/
                  Figure 3:  Host-to-Device Communication 的最左的 100微秒.

使用特权

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

本版积分规则

0

主题

329

帖子

1

粉丝