|
PS2接口協(xié)議
USB型PS2接口,5腳的稱為AT鍵盤,6腳mini_din連接器稱為PS2鍵盤;
都只有4個(gè)腳有意義,ACC,GND,CLK,DAT;CLK和DAT接上拉電阻,平時(shí)高;
CLK 15Khz,傳輸12位數(shù)據(jù)(起始位,8位數(shù)據(jù),奇偶校驗(yàn)位,停止位,應(yīng)答位),數(shù)據(jù)位1的個(gè)數(shù)為偶數(shù)個(gè)校驗(yàn)位為0,否則為1;
PS/2通訊協(xié)議是一種雙向同步串行通訊協(xié)議.通訊的兩端通過CLK同步,并通過DAT交換數(shù)據(jù).任何一方如果想抑制另外一方通訊時(shí),只需要把CLK拉到低電平.如果是PC機(jī)和PS/2鍵盤間的通訊,則PC機(jī)必須做主機(jī),PC機(jī)可以抑制PS/2鍵盤發(fā)送數(shù)據(jù),而PS/2鍵盤則不會(huì)抑制PC機(jī)發(fā)送數(shù)據(jù).
PS/2設(shè)備的CLK和DAT數(shù)據(jù)腳 都是集電極開路的,平時(shí)都是高電平.當(dāng)PS/2設(shè)備等待發(fā)送數(shù)據(jù)時(shí),它首先檢查CLK以確認(rèn)其是否為高電平.如果是低電平,則認(rèn)為是PC機(jī)抑制了通訊,此時(shí)它必須緩沖需要發(fā)送的數(shù)據(jù)直到重新獲得總線的控制權(quán)(一般PS/2鍵盤有16個(gè)字節(jié)的緩沖區(qū),而PS/2鼠標(biāo)只有一個(gè)緩沖區(qū)僅存儲(chǔ)最后一個(gè)要發(fā)送的數(shù)據(jù)).如果CLK為高電平,PS/2設(shè)備便開始將數(shù)據(jù)發(fā)送到PC機(jī).一般都是由PS/2設(shè)備產(chǎn)生時(shí)鐘信號(hào).發(fā)送時(shí)一般都是按照數(shù)據(jù)幀格式順序發(fā)送.其中數(shù)據(jù)位在CLK為高電平時(shí)準(zhǔn)備好,在CLK的下降沿被PC機(jī)讀入.
當(dāng)時(shí)鐘頻率為15kHz時(shí),從CLK的上升沿到數(shù)據(jù)位轉(zhuǎn)變時(shí)間至少要5μs.數(shù)據(jù)變化到CLK下降沿的時(shí)間至少也有5 us,但不能大于25 us,這是由PS/2通訊協(xié)議的時(shí)序規(guī)定的.如果時(shí)鐘頻率是其它值,參數(shù)的內(nèi)容應(yīng)稍作調(diào)整.
上述討論中傳輸?shù)臄?shù)據(jù)是指對(duì)特定鍵盤的編碼或者對(duì)特定命令的編碼.一般采用第二套掃描碼集所規(guī)定的碼值來編碼.其中鍵盤碼分為通碼(Make)和斷碼(Break).通碼是按鍵接通時(shí)所發(fā)送的編碼,用兩位十六進(jìn)制數(shù)來表示,斷碼通常是按鍵斷開時(shí)所發(fā)送的編碼,用四位十六進(jìn)制數(shù)來表示.
PS/2向PC機(jī)發(fā)送一個(gè)字節(jié)
(1)檢測時(shí)鐘線電平,如果時(shí)鐘線為低,則延時(shí)50us;
(2)檢測判斷時(shí)鐘信號(hào)是否為高,為高,則向下執(zhí)行,為低,則轉(zhuǎn)到(1);
(3)檢測數(shù)據(jù)線是否為高,如果為高則繼續(xù)執(zhí)行,如果為低,則放棄發(fā)送(此時(shí)PC機(jī)在向PS/2設(shè)備發(fā)送數(shù)據(jù),所以PS/2設(shè)備要轉(zhuǎn)移到接收程序處接收數(shù)據(jù));
(4)延時(shí)20us(如果此時(shí)正在發(fā)送起始位,則應(yīng)延時(shí)40us);
(5)輸出起始位0到數(shù)據(jù)線上.這里要注意的是:在送出每一位后都要檢測時(shí)鐘線,以確保PC機(jī)沒有抑制PS/2設(shè)備,如果有則中止發(fā)送;
(6)輸出8個(gè)數(shù)據(jù)位到數(shù)據(jù)線上;
(7)輸出校驗(yàn)位;
(8)輸出停止位(1);
(9)延時(shí)30us(如果在發(fā)送停止位時(shí)釋放時(shí)鐘信號(hào)則應(yīng)延時(shí)50us);
發(fā)送單個(gè)位
(1)準(zhǔn)備數(shù)據(jù)位(將需要發(fā)送的數(shù)據(jù)位放到數(shù)據(jù)線上);
(2)延時(shí)20us;
(3)把時(shí)鐘線拉低;
(4)延時(shí)40us;
(5)釋放時(shí)鐘線;
(6)延時(shí)20us.
PS/2設(shè)備從PC機(jī)接收一個(gè)字節(jié)
由于PS/2設(shè)備能提供串行同步時(shí)鐘,因此,如果PC機(jī)發(fā)送數(shù)據(jù),則PC機(jī)要先把時(shí)鐘線和數(shù)據(jù)線置為請(qǐng)求發(fā)送的狀態(tài).PC機(jī)通過下拉時(shí)鐘線大于100μs來抑制通訊,并且通過下拉數(shù)據(jù)線發(fā)出請(qǐng)求發(fā)送數(shù)據(jù)的信號(hào),然后釋放時(shí)鐘.當(dāng)PS/2設(shè)備檢測到需要接收的數(shù)據(jù)時(shí),它會(huì)產(chǎn)生時(shí)鐘信號(hào)并記錄下面8個(gè)數(shù)據(jù)位和一個(gè)停止位.主機(jī)此時(shí)在時(shí)鐘線變?yōu)榈蜁r(shí)準(zhǔn)備數(shù)據(jù)到數(shù)據(jù)線,并在時(shí)鐘上升沿鎖存數(shù)據(jù).而PS/2設(shè)備則要配合PC機(jī)才能讀到準(zhǔn)確的數(shù)據(jù).具體連接 步驟如下:
(1)等待時(shí)鐘線為高電平.
(2)判斷數(shù)據(jù)線是否為低,為高則錯(cuò)誤退出,否則繼續(xù)執(zhí)行.
(3)讀地址線上的數(shù)據(jù)內(nèi)容,共8個(gè)bit,每讀完一個(gè)位,都應(yīng)檢測時(shí)鐘線是否被PC機(jī)拉低,如果被拉低則要中止接收.
(4)讀地址線上的校驗(yàn)位內(nèi)容,1個(gè)bit.
(5)讀停止位.
(6)如果數(shù)據(jù)線上為0(即還是低電平),PS/2設(shè)備繼續(xù)產(chǎn)生時(shí)鐘,直到接收到1且產(chǎn)生出錯(cuò)信號(hào)為止(因?yàn)橥V刮皇?,如果PS/2設(shè)備沒有讀到停止位,則表明此次傳輸出錯(cuò)).
(7)輸出應(yīng)答位.
(8)檢測奇偶校驗(yàn)位,如果校驗(yàn)失敗,則產(chǎn)生錯(cuò)誤信號(hào)以表明此次傳輸出現(xiàn)錯(cuò)誤.
(9)延時(shí)45 μs,以便PC機(jī)進(jìn)行下一次傳輸.
讀數(shù)據(jù)線的步驟如下
(1)延時(shí)20μs;
(2)把時(shí)鐘線拉低
(3)延時(shí)40μs
(4)釋放時(shí)鐘線
(5)延時(shí)20μs
(6)讀數(shù)據(jù)線.
發(fā)出應(yīng)答位
(1)延時(shí)15μs;
(2)把數(shù)據(jù)線拉低;
(3)延時(shí)5μs;
(4)把時(shí)鐘線拉低;
(5)延時(shí)40μs;
(6)釋放時(shí)鐘線;
(7)延時(shí)5μs;
(8)釋放數(shù)據(jù)線.
實(shí)例:接收解碼數(shù)碼管顯示
#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;
}
}
}
} |
|