本帖最后由 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;
}*/
} |