?? ps2-01.c
字號:
/*******************************************
. PS/2鍵盤第2套編碼接口程序,適用于LPC930單片機
. 鍵值通過串口發送到上位機
*******************************************/
#include <reg931.h>
#include "ps2-01.h"
#define uchar unsigned char
#define uint unsigned int
// 鍵盤鍵值的宏定義
#define CTRL 0x14
#define ALT 0x11
#define CAPS_LOCK 0x58
#define LSHIFT 0x12
#define RSHIFT 0x59
#define NUM_LOCK 0x77
#define ENTER 0x5a
#define RESET 0xff //鍵盤進入reset
#define SETTING 0xfa //所有使能
#define KEY_SPEED 0xf3 //機打速率設置
#define KEY_CODE 0xf0 //設定掃描碼集
#define STATE 0xed //鍵盤狀態
#define TXBUF_LEN 0x30 //RS232串口發送緩存的長度
#define RXBUF_LEN 0x10 //RS232串口接收緩存的長度
#define KEYBUF_LEN 0x28 //PS2鍵盤接收緩存的長度
// I/O口定義
sbit BUZZ = P1^6; // 蜂鳴器 -
sbit K_DATA = P2^2; // PS2數據線,用于輸出,設置為集電極開路輸出
sbit K_CLK = P2^3; // PS/2時鐘線,用于輸出,設置為集電極開路輸出
bdata unsigned char get,sendto; //get 接收字; sendto 發送字;
sbit key=get^7;
sbit sd0=sendto^0;
bit b_odd=0;
bit b_capslock=0; //1=大寫鍵
bit b_shift=0; //1=shift鍵有效
bit b_num=1; //1=小鍵盤的數字鍵有效
bit b_ctrl=0; //1=ctrl鍵有效
bit b_alt=0; //1=ALT鍵有效
bit b_esp=0; //1=特殊鍵(E0?
bit b_up=0; //1=斷碼(F0?
bit b_e=0; //1=鍵PAUSE BREAK(E1?
uchar wrtxbuf_pointer = 0; //寫數據到232發送緩存時的指針
uchar rdtxbuf_pointer = 0; //讀232發送緩存時的指針
uchar wrrxbuf_pointer = 0; //接收時,寫數據到232接收緩存時的指針
uchar rdrxbuf_pointer = 0; //讀232接收緩存時的指針
idata uchar txbuf[TXBUF_LEN]; //232發送緩存
idata uchar rxbuf[RXBUF_LEN]; //232接收緩存
data unsigned char mode=0x02; // mode=Caps Num Scroll(0x00 ~ 0x06);
data unsigned char key_buf[KEYBUF_LEN]; //鍵值接收緩沖
data unsigned char keywrpoint=0,keyrdpoint=0; //
unsigned char addkey[3]; //地址輸入法的3個鍵值
unsigned char addkeypoint = 0; //地址輸入法的3個鍵值的指針位置
void set_state(unsigned char y);
void delay_us(unsigned int degree);
unsigned char getkey(void);
unsigned char receive(void);
void question(void);
void send(unsigned char x);
void start(void);
unsigned char cc_0(unsigned char ff);
unsigned char cc_1(unsigned char ff);
unsigned char cc_2(unsigned char ff);
unsigned char cc_3(unsigned char ff);
unsigned char character(unsigned char cc);
void ps2_rev_byte(void);
void SendTo_232(void);
/*-----------------------------------
延時子程序
指令周期為0.27126us 當內部RC時(7.373MHz)
-----------------------------------*/
void delay_n(uint xn)
{
for(;xn > 0 ;xn--){;}
SendTo_232();
}
/*------------------------------------------------
發聲程序
------------------------------------------------*/
void sound(void) //發聲程序
{
BUZZ = 1;
delay_n(3000);
BUZZ = 0;
}
/*------------------------------------------------
NAME: sendto_232(void)
FUNCTION: 檢測232接口,若空閑,且發送隊列不空,則發送一字節
IN:
OUT:
其它:
------------------------------------------------*/
void SendTo_232(void)
{
if(!TI) return; //正在發送,則退出
TI = 0;
if(rdtxbuf_pointer != wrtxbuf_pointer)
{ SBUF = txbuf[rdtxbuf_pointer];
rdtxbuf_pointer ++;
if(rdtxbuf_pointer >= TXBUF_LEN) rdtxbuf_pointer = 0;
}
}
/*------------------------------------------------
NAME: write_txbuf(uchar xd)
FUNCTION: 寫一個數據到發送隊列中
IN: xd - 數據
OUT:
其它: 寫數據前若數據滿,則等待
------------------------------------------------*/
void write_txbuf(uchar xd)
{ uint xi;
uchar xa;
for(xi = 0; xi < 0xfff0; xi ++) //約140ms
{ xa = wrtxbuf_pointer + 1; if(xa >= TXBUF_LEN) xa = 0;
if(xa != rdtxbuf_pointer) break;
}
txbuf[wrtxbuf_pointer] = xd;
wrtxbuf_pointer ++;
if(wrtxbuf_pointer >= TXBUF_LEN) wrtxbuf_pointer = 0;
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
P0 = 0xff;
P1 = 0xff;
P2 = 0xff;
P3 = 0xff;
BRGCON = 0x00;
SCON = 0x50; //串口配置:模式1;115.2k, 專用波特率發生器.
BRGR0 = 48;
BRGR1 = 0;
BRGCON = 0x03;
EA = 1;
BUZZ = 0;
start();
keyrdpoint=0;
key_buf[keyrdpoint]=0;
K_CLK = 1;K_DATA = 1;
while(1)
{
ps2_rev_byte();
question();
SendTo_232();
}
}
void question(void) //查詢鍵盤是否有鍵按下
{
unsigned char kk=0;
kk=getkey();
if(kk > 0) //鍵值有效,則通過COM口發送到主機
{ sound();
write_txbuf(kk);
}
}
unsigned char getkey(void) //處理鍵盤接收緩存,把掃描碼轉換為鍵值
{
unsigned char f,char_ok=0;
if(keyrdpoint == keywrpoint) return 0;
f=key_buf[keyrdpoint];
keyrdpoint++;
if(keyrdpoint>=KEYBUF_LEN) keyrdpoint=0;
if(f==0)
return 0;
else
{
if(f==0x83) //F7
{ if(b_up) char_ok = 0;
else char_ok=7;
b_up = 0;
}
else if(f&0x80)
{
switch(f)
{
case 0xe1: b_esp=1;b_up=1;b_e=1;break; //PAUSE
case 0xe0: b_esp=1;b_e=0;break; //特殊鍵
case 0xf0: b_up=1;b_e=0;break; //斷碼
default: break;
}
}
else
{
if(!b_esp) //b_esp==0;
{
if(!b_up) char_ok=cc_0(f); //b_esp==0;b_up==0;
else {b_up=0;cc_1(f);} //b_esp==0;b_up==1;
}
else //b_esp==1;
{
b_esp=0;
if(!b_up) char_ok=cc_2(f); //b_esp==1;b_up==0;
else {b_up=0;char_ok=cc_3(f);} //b_esp==1;b_up==1;
}
}
return (char_ok);
}
}
unsigned char cc_0(unsigned char ff)
{
unsigned char ch=0;
switch(ff)
{
case LSHIFT:
case RSHIFT: b_shift=1;break;
case CTRL: b_ctrl=1; addkeypoint = 0; break; //
case ALT: b_alt=1;addkeypoint = 0; break; //
case 0x6e:
case NUM_LOCK: b_num=~b_num;
if(b_num)
{ mode = mode | 0x02; //位1 - 點亮數字燈
}
else
{ mode = mode & 0xfd; //位1 - 關閉數字燈
}
set_state(mode);
ch=0;
break;
case 0x58: //CAPS_LOCK鍵
b_capslock=~b_capslock;
if(b_capslock)
{
mode = mode | 0x04; //位2為點亮大寫燈
}
else
{
mode = mode & 0xfb; //位2 - 關閉大寫燈
}
set_state(mode);
ch=31; //發送大/小寫狀態到ARM
break;
default: ch=character(ff);break;
}
return (ch);
}
unsigned char cc_1(unsigned char ff)
{ unsigned char ch=0;
switch(ff)
{
case LSHIFT:
case RSHIFT: b_shift=0;break;
case CTRL: b_ctrl=0;addkey_ascii();break;
case ALT: b_alt=0;addkey_ascii();break;
default: break;
}
return (ch);
}
unsigned char cc_2(unsigned char ff)
{
unsigned char ch=0;
switch(ff)
{
case CTRL: b_ctrl=1;addkeypoint = 0;break;
case ALT: b_alt=1;addkeypoint = 0; break;
case 0x12: ch=ASCII_0[61];break; //Print Screen
case 0x7c: break;
default: ch=ASCII_0[ff];
break;
}
return (ch);
}
unsigned char cc_3(unsigned char ff)
{
unsigned char ch=0;
switch(ff)
{
case CTRL: if(b_e){b_esp=1;b_up=1;b_e=0;ch=ASCII_0[ff];}
else {addkey_ascii();b_ctrl=0;}
break;
case ALT: b_alt=0;addkey_ascii();break;
default: b_e=0;break;
}
return (ch);
}
unsigned char character(unsigned char cc) //字符鍵的處理
{
data unsigned char hh=0;
if(b_shift)
{
switch(cc)
{
case 0x0e: hh='~';break;
case 0x16: hh='!';break;
case 0x1e: hh='@';break;
case 0x26: hh='#';break;
case 0x25: hh='$';break;
case 0x2e: hh='%';break;
case 0x36: hh='^';break;
case 0x3d: hh='&';break;
case 0x3e: hh='*';break;
case 0x46: hh='(';break;
case 0x45: hh=')';break;
case 0x4e: hh='_';break;
case 0x55: hh='+';break;
case 0x5d: hh='|';break;
case 0x54: hh='{';break;
case 0x5b: hh='}';break;
case 0x4c: hh=':';break;
case 0x52: hh='"';break;
case 0x41: hh='<';break;
case 0x49: hh='>';break;
case 0x4a: hh='?';break;
default: switch(mode)
{
case 0: hh=ASCII_0[cc];
if((hh > 96) && (hh < 123)) hh-= 0x20; //把小寫轉換為大寫
break;
case 0x02: hh=ASCII_1[cc];
if((hh > 96) && (hh < 123)) hh-= 0x20; //把小寫轉換為大寫
break;
case 0x04: hh=ASCII_0[cc];break;
case 0x06: hh=ASCII_1[cc];break;
default: break;
}
break;
}
}
else
{
switch(mode)
{
case 0: hh=ASCII_0[cc];break;
case 0x02: hh=ASCII_1[cc];break;
case 0x04: hh=ASCII_0[cc];
if((hh > 96) && (hh < 123)) hh-= 0x20; //把小寫轉換為大寫
break;
case 0x06: hh=ASCII_1[cc];
if((hh > 96) && (hh < 123)) hh-= 0x20; //把小寫轉換為大寫
break;
default: break;
}
}
return (hh);
}
void set_state(unsigned char y) //設置鍵盤狀態
{
send(STATE);
send(y);
}
void start(void)
{
send(RESET); //鍵盤復位:第2套,標準機打,使能機打/通碼/斷碼
send(0xf6); //(Set Default) 載入缺省的機打速率/延時10.9cps/500ms 按鍵類型(所有按鍵都使能機打/通碼/斷碼) 以及第二套掃描碼集
set_state(mode);
}
/*------------------------------------------------
NAME: void send(unsigned char x)
FUNCTION: 發送一個字節到鍵盤
IN: x - 發送的數據
發送數據到鍵盤的步驟:
1) 把時鐘線拉低至少100 微秒
2) 把數據線拉低
3) 釋放數據線
4) 等待設備把時鐘線拉低
5) 設置/復位數據線發送第一個數據位
6) 等待設備把時鐘拉高
7) 等待設備把時鐘拉低
8) 重復 5-7 步 發送剩下的7 個數據位和校驗位
9) 釋放數據線
10) 等待設備把數據線拉低
11) 等待設備把時鐘線拉低
12) 等待設備釋放數據線和時鐘線
------------------------------------------------*/
void send(unsigned char x) //發送一個字節到鍵盤
{ unsigned char xi;
unsigned int xn;
sendto=x;
K_CLK = 1;
K_DATA = 1;
SendTo_232();
K_CLK=0; //把時鐘和數據線設置為請求發送狀態:時鐘線拉低至少100 微秒
delay_n(120); //延時100us
K_DATA=0; //把時鐘和數據線設置為請求發送狀態:把數據線拉低
delay_n(40);
K_CLK=1; //把時鐘和數據線設置為請求發送狀態:釋放數據線
delay_n(40);
b_odd = 0;
for(xn = 0; xn < 0x4000; xn++) { if(K_CLK == 0) break;}
if(xn >= 0x4000) return;
for(xi = 0; xi < 10; xi++)
{
for(xn = 0; xn < 0x1f0; xn++) { if(K_CLK == 0) break;}
if(xi < 8) //發送8位數據
{ K_DATA=sd0;
if(sd0)b_odd=~b_odd;
sendto= sendto >> 1;
}
else if(xi == 8) //發送校驗位
{ K_DATA = ~b_odd; }
else if(xi == 9) //發送停止位
{ K_DATA = 1; }
for(xn = 0; xn < 0x1f0; xn++) { if(K_CLK) break;}
}
delay_n(10); K_DATA = 1;
for(xn = 0; xn < 0xf0; xn++) { if(K_DATA == 0) break; }
for(xn = 0; xn < 0xf0; xn++) { if(K_CLK == 0) break; }
for(xn = 0; xn < 0x1f0; xn++) { if(K_DATA) break; }
for(xn = 0; xn < 0x1f0; xn++) { if(K_CLK) break; }
delay_n(60000); //延時10ms
}
void ps2_rev_byte(void) //從PS2鍵盤接收一字節數據,查詢方式
{ unsigned char xi;
unsigned int xn;
K_CLK = 1; K_DATA = 1;
for(xn = 0; xn < 0xfff0; xn++) { if(K_CLK == 0) break; } //檢測時鐘線是否為低
if(xn >= 0xfff0) return;
for(xn = 0; xn < 0x1f0; xn++) { if(K_DATA == 0) break; }//檢測數據線是否為低
if(xn >= 0x1f0) return;
for(xn = 0; xn < 0x1f0; xn++) { if(K_CLK) break;}
//已收到開始位
get = 0; b_odd = 0;
for(xi = 0; xi < 9; xi++)
{
for(xn = 0; xn < 0x1f0; xn++) { if(K_CLK == 0) break;}
if(xi < 8)
{ get = get >> 1;
key=K_DATA;
if(key) b_odd=~b_odd;
}
else
{ if(K_DATA) b_odd=~b_odd;
}
for(xn = 0; xn < 0x1f0; xn++) { if(K_CLK) break;}
}
for(xn = 0; xn < 0x1f0; xn++) { if(K_CLK == 0) break;}
for(xn = 0; xn < 0x1f0; xn++) { if(K_DATA) break;}
for(xn = 0; xn < 0x1f0; xn++) { if(K_CLK) break;}
K_CLK = 0; //抑制鍵盤立即發送下一字節,(鍵盤在CLK變高50ms后再發送)
//前后兩個值相同,則不寫入.即取消 機打功能
xi = keywrpoint;
if(xi==0) xi = KEYBUF_LEN;
xi--;
if(key_buf[xi] == get)
{ if(keywrpoint != keyrdpoint) return; //上一鍵還未處理
if((b_ctrl) && (get == 0x14)) return; //前后兩個鍵盤為ctrl
}
key_buf[keywrpoint]=get;
keywrpoint++;
if(keywrpoint>=KEYBUF_LEN) keywrpoint=0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -