PS2接口协议
USB型PS2接口,5脚的称为AT键盘,6脚mini_din连接器称为PS2键盘;
都只有4个脚有意义,ACC,GND,CLK,DAT;CLK和DAT接上拉电阻,平时高;
CLK 15Khz,传输12位数据(起始位,8位数据,奇偶校验位,停止位,应答位),数据位1的个数为偶数个校验位为0,否则为1;
PS/2通讯协议是一种双向同步串行通讯协议.通讯的两端通过CLK同步,并通过DAT交换数据.任何一方如果想抑制另外一方通讯时,只需要把CLK拉到低电平.如果是PC机和PS/2键盘间的通讯,则PC机必须做主机,PC机可以抑制PS/2键盘发送数据,而PS/2键盘则不会抑制PC机发送数据.
PS/2设备的CLK和DAT数据脚 都是集电极开路的,平时都是高电平.当PS/2设备等待发送数据时,它首先检查CLK以确认其是否为高电平.如果是低电平,则认为是PC机抑制了通讯,此时它必须缓冲需要发送的数据直到重新获得总线的控制权(一般PS/2键盘有16个字节的缓冲区,而PS/2鼠标只有一个缓冲区仅存储最后一个要发送的数据).如果CLK为高电平,PS/2设备便开始将数据发送到PC机.一般都是由PS/2设备产生时钟信号.发送时一般都是按照数据帧格式顺序发送.其中数据位在CLK为高电平时准备好,在CLK的下降沿被PC机读入.
当时钟频率为15kHz时,从CLK的上升沿到数据位转变时间至少要5μs.数据变化到CLK下降沿的时间至少也有5 us,但不能大于25 us,这是由PS/2通讯协议的时序规定的.如果时钟频率是其它值,参数的内容应稍作调整.
上述讨论中传输的数据是指对特定键盘的编码或者对特定命令的编码.一般采用第二套扫描码集所规定的码值来编码.其中键盘码分为通码(Make)和断码(Break).通码是按键接通时所发送的编码,用两位十六进制数来表示,断码通常是按键断开时所发送的编码,用四位十六进制数来表示.
PS/2向PC机发送一个字节
(1)检测时钟线电平,如果时钟线为低,则延时50us;
(2)检测判断时钟信号是否为高,为高,则向下执行,为低,则转到(1);
(3)检测数据线是否为高,如果为高则继续执行,如果为低,则放弃发送(此时PC机在向PS/2设备发送数据,所以PS/2设备要转移到接收程序处接收数据);
(4)延时20us(如果此时正在发送起始位,则应延时40us);
(5)输出起始位0到数据线上.这里要注意的是:在送出每一位后都要检测时钟线,以确保PC机没有抑制PS/2设备,如果有则中止发送;
(6)输出8个数据位到数据线上;
(7)输出校验位;
(8)输出停止位(1);
(9)延时30us(如果在发送停止位时释放时钟信号则应延时50us);
发送单个位
(1)准备数据位(将需要发送的数据位放到数据线上);
(2)延时20us;
(3)把时钟线拉低;
(4)延时40us;
(5)释放时钟线;
(6)延时20us.
PS/2设备从PC机接收一个字节
由于PS/2设备能提供串行同步时钟,因此,如果PC机发送数据,则PC机要先把时钟线和数据线置为请求发送的状态.PC机通过下拉时钟线大于100μs来抑制通讯,并且通过下拉数据线发出请求发送数据的信号,然后释放时钟.当PS/2设备检测到需要接收的数据时,它会产生时钟信号并记录下面8个数据位和一个停止位.主机此时在时钟线变为低时准备数据到数据线,并在时钟上升沿锁存数据.而PS/2设备则要配合PC机才能读到准确的数据.具体连接 步骤如下:
(1)等待时钟线为高电平.
(2)判断数据线是否为低,为高则错误退出,否则继续执行.
(3)读地址线上的数据内容,共8个bit,每读完一个位,都应检测时钟线是否被PC机拉低,如果被拉低则要中止接收.
(4)读地址线上的校验位内容,1个bit.
(5)读停止位.
(6)如果数据线上为0(即还是低电平),PS/2设备继续产生时钟,直到接收到1且产生出错信号为止(因为停止位是1,如果PS/2设备没有读到停止位,则表明此次传输出错).
(7)输出应答位.
(8)检测奇偶校验位,如果校验失败,则产生错误信号以表明此次传输出现错误.
(9)延时45 μs,以便PC机进行下一次传输.
读数据线的步骤如下
(1)延时20μs;
(2)把时钟线拉低
(3)延时40μs
(4)释放时钟线
(5)延时20μs
(6)读数据线.
发出应答位
(1)延时15μs;
(2)把数据线拉低;
(3)延时5μs;
(4)把时钟线拉低;
(5)延时40μs;
(6)释放时钟线;
(7)延时5μs;
(8)释放数据线.
实例:接收解码数码管显示
#include<reg51.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit CLK=P3^2;sbit SDA=P1^6;
sbit DA=P2^2;sbit DB=P2^3;sbit DC=P2^4;
uint dat;
bit flag;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
void delay(uchar ms)
{
uchar i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}
void rupt0() interrupt 0
{
uchar i;
while(!CLK)
{
_nop_();
}
if(CLK==0)
{
dat=((dat>>1)&((uint)SDA<<8));
i++;
}
if(i==9)
{
i=0;
EX0=0;
flag=1;
}
}
void jiema()
{
uchar a,j;
switch(dat)
{
case 0x13f:a=0x3f;break;
case 0x106:a=0x06;break;
case 0x15b:a=0x5b;break;
case 0x14f:a=0x4f;break;
case 0x166:a=0x66;break;
case 0x16d:a=0x6d;break;
}
P0=table[a];
j=50;while(j--);
P0=0x00;
}
void main()
{
EA=1;EX0=1;IT0=1;
while(1)
{
uchar i;
if(flag==1)
{
if(i<=100)
{
jiema();
delay(1);
i++;
}
else
{
i=0;
EX0=1;
flag=0;
}
}
}
} |