PS/2 Overview
PS/2 is divided into master and slave devices. The master device uses female sockets and male plug from the device. currently, the widely used PS/2 keyboard and mouse work in the device mode. PS/2 interface clock
It is an open-collector structure and must be connected to the pull-up resistor (generally, the pull-up resistor is set in the main device ). data communication between master and slave devices is transmitted in two-way synchronous serial mode, and clock signals are generated by the slave devices.
1.1 Communication from the device to the master device
When the device sends data to the master device, first check the clock line to confirm whether the clock line is high. if it is a high level, data can be transmitted from the device; otherwise, the device must wait for control of the bus to start data transmission. each frame is composed of 11 digits. The sending sequence and the meaning of each digit are as follows: 2.
The starting position of each frame of data is always 0. The data verification adopts the odd verification method, and the stop position is always 1. when the device communicates with the master device, the status of the data line is always changed when the clock line is high.
1.2 communication between the master device and the Slave Device
When the master device communicates with the slave device, the master device first sets the clock line and data line to the "Send request" status. The specific method is: first drop down the clock line to at least us to suppress communication, then, pull down the data line "send requests" and release the clock line. in this process, the device must check this status within the interval of 10 us. When the device detects this status, it will start to generate a clock signal. at this time, each frame of data transmission is composed of 12 digits. the time sequence and meaning of each frame are as follows: 3.
Compared with the communication from the device to the master device, each frame of data has an ACK bit. this is the response bit received from the device. It is generated by pulling the data line from the device, and the total number of response bits is ack.
The value is 0. During the communication from the master device to the slave device, the master device always changes the data line status when the clock line is low, and the slave device reads the data line status when the clock rises.
Encoding of the 2.1 PS/2 Keyboard
Currently, the PS/2 keyboards used by PCS use 2nd sets of scanning code sets by default. there are two different types of scan codes: Make code and break code )". when a key is pressed or pressed continuously, the keyboard will send the passcode of the Key to the host. When a key is released, the keyboard will send the broken code of the Key to the host. based on the scan code of the keyboard key, the buttons can be divided into three categories:
The 1st-type key Tong code is a byte, with the broken code in the form of 0xf0 +. For example, if the key, its Tong code is 0x1c, and the broken code is 0xf0 0x1c.
The 2nd-type key code is in the form of two bytes 0xe0 + 0xxx. The broken code is in the form of 0xe0 + 0xf0 + 0xxx. for example, if the right ctrl key is used, its passcode is 0xe0 0x14, and its broken code is 0xe0 0xf0 0x14.
There are two special 3rd buttons, the print screen key, with the passcode 0xe0 0x12 0xe0 0x7c; the broken code is 0xe0 0xf0 0x7c 0xe0 0xf0 0x12. pause key. The passcode is 0xe1 0x14 0x77 0xe1 0xf0 0xl4 0xf0 0x77. The disconnection code is empty.
The combination of key scan codes is sent according to the order in which keys occur. For example, press left shift 10 A in the following order: ① press left shift key; ② press a key; ③ release a key; ④ release the Left Shift key, and the string of data received on the computer is 0x12 0x1c 0xf0 0x1c 0xf0 0x12.
2.2 PS/2 Keyboard Command set
The host can set the keyboard or obtain the keyboard status by sending commands to the PS/2 keyboard. Each byte sent, the host will get a response 0xfa from the keyboard ("resend"
Resend and echo response commands ). command Used by the driver during keyboard initialization: 0xed. After this command, the host sends a parameter byte to indicate the statuses of Num Lock, caps lock, and scroll lock LEDs on the keyboard; 0xf3: the host sends a byte parameter after this command to define the speed and latency of the keyboard. 0xf4 is used to re-enable the keyboard when the host sends 0xf5 to disable the keyboard.
Connection circuit diagram:
Design Program ideas:
Decode a frame of data using a state machine, and define four states: ps_idle, ps_start, ps_parity, and ps_stop.
The ps_idle status accepts the start code and determines whether the start code is valid. The ps_start status accepts 8-bit data. The ps_parity status accepts the parity bit. The ps_stop status accepts the stop as and the parity data, simultaneously handles shift keys and code disconnection issues;
Define struct
Typedef struct ps2_frame
{
Uchar state; // status
Uchar data; // data
Uchar temp; // used for shift
Uchar parity; // parity bit
Uchar count; // The number of digits of 1 due to parity
Uchar ready; // one frame of data is accepted
Uchar shift; // whether the Shift key is pressed
Uchar down; // whether the button is displayed
} Ps2_frame;
The following is a program:
Header file
# Include "Main. H"
# Define ps_data ra1
# Define ps_clk rb0
# Define ps_idle 0x01
# Define ps_start 0x02
// # Define ps_data 0x03
# Define ps_parity 0x04
# Define ps_stop 0x05
// # Define ps_ack
Typedef struct ps2_frame
{
Uchar state; // status
Uchar data; // data
Uchar temp; // used for shift
Uchar parity; // parity bit
Uchar count; // The number of digits of 1 due to parity
Uchar ready; // one frame of data is accepted
Uchar shift; // whether the Shift key is pressed
Uchar down; // whether the button is displayed
} Ps2_frame;
Void init_ps2 ();
Uchar ps_decoding (uchar data, uchar shift );
# Endif
Initialize the decode subprogram and decode table
# Include "ps2.h"
Const uchar unshifted [] [2] = // Shift key does not press the conversion table
{
0x0e ,''',
0x15, 'Q ',
0x16, '1 ',
0x1a, 'z ',
0x1b,'s ',
0x1c, 'A ',
0x1d, 'w ',
0x1e, '2 ',
0x21, 'C ',
0x22, 'x ',
0x23, 'D ',
0x24, 'E ',
0x25, '4 ',
0x26, '3 ',
0x29 ,'',
0x2a, 'V ',
0x2b, 'F ',
0x2c,'t ',
0x2d, 'R ',
0x2e, '5 ',
0x31, 'n ',
0x32, 'B ',
0x33, 'h ',
0x34, 'G ',
0x35, 'y ',
0x36, '6 ',
0x39 ,',',
0x3a, 'M ',
0x3b, 'J ',
0x3c, 'U ',
0x3d, '7 ',
0x3e, '8 ',
0x41 ,',',
0x42, 'k ',
0x43, 'I ',
0x44, 'O ',
0x45, '0 ',
0x46, '9 ',
0x49 ,'.',
0x4a ,'/',
0x4b, 'l ',
0x4c ,';',
0x4d, 'P ',
0x4e ,'-',
0x52 ,'/'',
0x54 ,'[',
0x55, '= ',
0x5b, ']',
0x5d ,'//',
0x61, '<',
0x69, '1 ',
0x6b, '4 ',
0x6c, '7 ',
0x70, '0 ',
0x71 ,'.',
0x72, '2 ',
0x73, '5 ',
0x74, '6 ',
0x75, '8 ',
0x79, '+ ',
0x7a, '3 ',
0x7b ,'-',
0x7c ,'*',
0x7d, '9 ',
0, 0
};
Const uchar shifted [] [2] = // Shift key press the conversion table
{
0x0e ,'~ ',
0x15, 'Q ',
0x16 ,'! ',
0x1a, 'z ',
0x1b,'s ',
0x1c, 'A ',
0x1d, 'w ',
0x1e ,'@',
0x21, 'C ',
0x22, 'x ',
0x23, 'D ',
0x24, 'E ',
0x25, '$ ',
0x26 ,'#',
0x29 ,'',
0x2a, 'V ',
0x2b, 'F ',
0x2c,'t ',
0x2d, 'R ',
0x2e, '% ',
0x31, 'n ',
0x32, 'B ',
0x33, 'h ',
0x34, 'G ',
0x35, 'y ',
0x36, '^ ',
0x39, 'l ',
0x3a, 'M ',
0x3b, 'J ',
0x3c, 'U ',
0x3d ,'&',
0x3e ,'*',
0x41, '<',
0x42, 'k ',
0x43, 'I ',
0x44, 'O ',
0x45 ,')',
0x46 ,'(',
0x49, '> ',
0x4a ,'? ',
0x4b, 'l ',
0x4c ,':',
0x4d, 'P ',
0x4e ,'_',
0x52 ,'"',
0x54 ,'{',
0x55, '+ ',
0x5b ,'}',
0x5d, '| ',
0x61, '> ',
0x69, '1 ',
0x6b, '4 ',
0x6c, '7 ',
0x70, '0 ',
0x71 ,'.',
0x72, '2 ',
0x73, '5 ',
0x74, '6 ',
0x75, '8 ',
0x79, '+ ',
0x7a, '3 ',
0x7b ,'-',
0x7c ,'*',
0x7d, '9 ',
0, 0
};
Void init_ps2 ()
{
Adcon1 = 0x07; // The a port is a common Io
Trisa1 = 1;
Intcon = 0;
Intedg = 1;
Inte = 1;
Peie = 1;
Gie = 1;
}
Uchar ps_decoding (uchar data, uchar shift)
{
Uchar temp, I = 0;
If (shift)
{
While (I! = 255)
{
If (shifted [I] [0] = data)
{
Temp = shifted [I] [1];
Break;
}
I ++;
}
}
Else
{
While (I! = 255)
{
If (unshifted [I] [0] = data)
{
Temp = unshifted [I] [1];
Break;
}
I ++;
}
}
Return temp;
}
Main Program:
# Include "Main. H"
# Include "t232.h"
# Include "ps2.h"
Ps2_frame ps_frame;
Void interrupt main_int ()
{
If (INTF) // triggered by descent edge
{
Gie = 0;
INTF = 0;
Switch (ps_frame.state)
{
Case ps_idle:
If (! Ps_data)
{
Ps_frame.ready = 0;
Ps_frame.state = ps_start;
Ps_frame.temp = 1;
Ps_frame.count = 0;
Ps_frame.data = 0;
}
Else
Ps_frame.state = ps_idle;
Break;
Case ps_start:
If (ps_data)
{
Ps_frame.data = ps_frame.data | ps_frame.temp;
Ps_frame.count ++;
}
Ps_frame.temp = ps_frame.temp <1;
If (! Ps_frame.temp)
Ps_frame.state = ps_parity;
Break;
Case ps_parity:
Ps_frame.parity = ps_data;
Ps_frame.state = ps_stop;
Break;
Case ps_stop:
If (ps_data)
{
If (ps_frame.parity)
{
If (ps_frame.count % 2 = 0)
Ps_frame.ready = 1;
}
Else
{
If (ps_frame.count % 2 = 1)
Ps_frame.ready = 1;
}
Switch (ps_frame.data) // process the passcode and disconnection code
{
Case 0xf0:
Ps_frame.down = 0;
Ps_frame.ready = 0;
Break;
Case 0x12:
If (! Ps_frame.down)
Ps_frame.shift = 0;
Else
Ps_frame.shift = 1;
Ps_frame.ready = 0;
Break;
Case 0x59:
If (! Ps_frame.down)
Ps_frame.shift = 0;
Else
Ps_frame.shift = 1;
Ps_frame.ready = 0;
Break;
Default:
If (! Ps_frame.down)
{
Ps_frame.ready = 0;
Ps_frame.down = 1;
}
Break;
}
}
Ps_frame.state = ps_idle;
Break;
Default:
Break;
}
}
Gie = 1;
}
Void init_all ()
{
Init_232 ();
Init_ps2 ();
Ps_frame.state = ps_idle;
Ps_frame.shift = 0;
Ps_frame.down = 0;
}
Void main ()
{
Const char STR [] = "Hello world! ";
Uchar temp;
Init_all ();
Send_str (STR); // test the serial port
While (1)
{
If (ps_frame.ready)
{
Temp = ps_decoding (ps_frame.data, ps_frame.shift );
Put_char (temp );
Ps_frame.ready = 0;
}
}
}