|
|
View previous topic :: View next topic |
Author |
Message |
stevenm86
Joined: 11 Jun 2006 Posts: 11
|
PS/2 keyboard driver/decoder, interrupt driven, 16F and up |
Posted: Sat Jul 08, 2006 8:03 pm |
|
|
Hello.
I have written a nice PS/2 keyboard driver for the PIC. This reads data from a PS/2 keyboard, decodes it, and makes it available to whatever needs it. It decodes the scancodes, tracks shift and caps lock keys, and outputs pure ASCII of what is typed. The whole thing is interrupt driven so the program does not need to spend time waiting for keyboard input to happen while doing other things. Keys are read into a 16 byte circular buffer in memory which can be accessed with several simple functions.
The sendByte function was used to set the LED status on the keyboard (for caps lock) but it is currently turned off because it only worked with some of my keyboard. Some sort of timing issue? I don't know.. Whatever.
There are two pins you want from the keyboard- Clock and Data, and these are set with simple Defines. Data can be reassigned to anything, but Clock needs to be set to the External interrupt pin, which is usually B0. I know pic18 has multiple external interrupts, so you can use any one of those, assuming you also set the interrupt handler function to work on that interrupt.
The RS232 in the program is simply my debug console. You can get rid of it (as well as any printfs) if you wish.
The driver supports most basic input keys such as A-Z, 0-9, Space, and all punctuation marks. I think Escape and Backspace are also tracked. It is possible to add support for other keys pretty easily, you just need the scan code of the key. The scan code map is coded a bit weirdly, but this is mainly to make the code and tables as small as possible. Look at translate(), you will figure it out.
Functions you'll want to use-
keyhit() - tells you if there are any bytes in the buffer.
waitKey() - returns the next character in the buffer. If there is no data in the buffer, this will keep on waiting and will return whenever the next key is pressed. Shift and Caps Lock do not count, they are not considered keys that produce characters.
Again, you get back the full ASCII value of what was typed. Pressing A returns 'a', Pressing Shift+A returns 'A', pressing Capslock, Shift+A returns 'a', just like on a computer. Pressing Shift+1 returns '!'.
The program uses interrupts to read the keyboard, so as soona s a key is pressed, your code will pause running while the keyboard driver reads the incoming data. Normally this is not a problem, but if something is typed in the middle of a serial transmission, that transmission may be garbled. To fix this, simply disable interrupts during any operation that you do not want interrupted, and re-enable them after. Turning off interrupts disables the kebyoard driver, so any keys typed when they are disabled will not be processed.
I probably will not maintain this anymore, it worked well enough for me.. there may be occasional bugs, but you can fix them easily enough, and this thing works well enough anyway.
Here is the code, I hope you like it.
Steve
Code: |
#include <16f877a>
#fuses HS,NOWDT,NOPROTECT,NOLVP,NOBROWNOUT,NOPUT
#use delay(clock=4096000)
#use RS232(Baud=2400,Xmit=PIN_D2,BITS=8,INVERT)
//D0 - Clock
//D1 - Data
// Clock must be the interrupt pin
#define CLOCK PIN_B0
#define DATA PIN_D3
unsigned char bData[16];
unsigned char idx=0;
unsigned char tmp=0;
unsigned char readByte();
unsigned char processByte();
unsigned char waitKey();
byte keyhit();
unsigned char translate(unsigned char scancode);
volatile byte shiftSet = 0;
byte kbBuffer[16];
byte kbPos = 0;
byte kbSize = 0;
byte capsSet = 0;
volatile byte extFlag = 0;
volatile byte relFlag = 0;
volatile byte key=0;
void sendByte(byte b)
{
byte a=0;
byte p = 1;
byte t = 0;
return; // THIS IS NOT FULLY WORKING ON ALL KEYBOARDS
// SO IT IS COMMENTED OUT
// Some kind of timing issue or something. Whatever, they're just LEDs
disable_interrupts(GLOBAL);
output_low(CLOCK);
delay_us(300);
output_low(DATA);
input(CLOCK);
for(a=0; a<8; a++)
{
t = b&(1<<a);
while(input(CLOCK) == 1); //wait for 0
output_bit(DATA, t);
if(t)
p++;
while(input(CLOCK) == 0); //wait for 1
}
while(input(CLOCK) == 1); //wait for 0
output_bit(DATA, p&0x01);
while(input(CLOCK) == 0); //wait for 1
input(DATA);
while(input(DATA) == 1); //wait for 0
while(input(CLOCK) == 1); //wait for 0
delay_ms(10);
clear_interrupt(INT_EXT);
enable_interrupts(GLOBAL);
}
main()
{
int i=0;
unsigned char k=0;
printf("READY >");
output_b(0x00);
input(CLOCK);
delay_ms(100);
ext_int_edge(H_to_L);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
while(1)
{
k = waitKey();
printf("%c", k);
while(keyhit())
printf("%c", waitKey());
}
}
byte keyhit()
{
return kbSize != 0;
}
unsigned char waitKey()
{
unsigned char k = 0;
while(kbSize == 0);
k = kbBuffer[(kbPos - kbSize)&0x0F];
kbSize--;
return k;
}
#int_ext
void kbInterrupt()
{
volatile byte k=0;
k = processByte();
if(k != 0)
{
kbBuffer[kbPos] = k;
kbPos = ++kbPos & 0x0F;
kbSize++;
}
return;
}
unsigned char readByte()
{
int i=0, t=0;
idx=0;
tmp=0;
i=0;
goto dataread;
// while(INPUT(CLOCK) != 0); // Wait for a keypress
t=0;
while(INPUT(CLOCK) != 0 && t<255) // Wait for clock, time out if needed
{
delay_us(1);
t++;
}
for(i=0; i<11; i++)
{
t=0;
while(INPUT(CLOCK) != 0 && t<255) // Wait for clock, time out if needed
{
delay_us(1);
t++;
}
dataread:
bData[idx]=INPUT(DATA);
idx++;
if(idx==9)
{
for(idx=1; idx<9; idx++)
if(bData[idx]!=0)
tmp|=(1<<(idx-1));
return tmp;
idx=0;
tmp=0;
}
// while(INPUT(CLOCK) == 0);
t=0;
while(INPUT(CLOCK) == 0 && t<255) // Wait for clock, time out if needed
{
delay_us(1);
t++;
}
}
}
static const unsigned char scantableAZ[]={
0x1C, 0x32, 0x21, 0x23, 0x24, 0x2B, 0x34, 0x33, 0x43, 0x3B, 0x42, 0x4B, 0x3A, // A-Z
0x31, 0x44, 0x4D, 0x15, 0x2D, 0x1B, 0x2C, 0x3C, 0x2A, 0x1D, 0x22, 0x35, 0x1A};
// Normal numeric scancodes, starting with ',' .
static const unsigned char scantable09n[]=
{
0x41, 0x4E, 0x49, 0x4A, // , - . /
0x45, 0x16, 0x1E, 0x26, 0x25, 0x2E, 0x36, 0x3D, 0x3E, 0x46, //Digits 0-9
0x00, 0x4C, 0x00, 0x55 // 0 ; 0 =
};
// Shift scancodes, starting at '!'
static const unsigned char scantable09s[]=
{
0x16, 0x52, 0x26, 0x25, 0x2E, 0x3D, 0x00, 0x46, 0x45, 0x3E, 0x55
};
// Normal misc. scancode map. Scancode, ASCII value
static const unsigned char scanmapn[]=
{0x54, '[', 0x5B, ']', 0x0E, '`', 0x5D, '\\', 0x52, '\''};
// Shifted misc. scancode map. Scancode, ASCII value
static const unsigned char scanmaps[]=
{0x1E, '@', 0x36, '^', 0x4E, '_', 0x54, '{', 0x5B, '}', 0x5D, '|',
0x4C, ':', 0x41, '<', 0x49, '>', 0x4A, '?', 0x0E, '~'};
// Scancode map independent of Shift
static const unsigned char scanmapx[]=
{0x29, ' ', 0x5A, '\r', 0x0D, '\t', 0x76, 27, 0x66, 0x08};
// Extended scancode map
static const unsigned char scanmape[]=
{
0x71, 0x7F
};
unsigned char translate(unsigned char scancode)
{
int i=0;
if(extFlag == 0)
{
for(i=0; i<10; i+=2)
if(scanmapx[i] == scancode)
return scanmapx[i+1];
for(i=0; i<26; i++)
if(scantableAZ[i] == scancode)
if(shiftSet ^ capsSet)
return i+65;
else
return i+65 + 32;
if(shiftSet)
{
for(i=0; i<11; i++)
if(scantable09s[i] == scancode)
return i+'!';
for(i=0; i<22; i+=2)
if(scanmaps[i] == scancode)
return scanmaps[i+1];
} else
{
for(i=0; i<18; i++)
if(scantable09n[i] == scancode)
return i+',';
for(i=0; i<10; i+=2)
if(scanmapn[i] == scancode)
return scanmapn[i+1];
}
} else // Extended keys
{
for(i=0; i<2; i+=2)
if(scanmape[i] == scancode)
return scanmape[i+1];
}
return '?';
}
unsigned char processByte()
{
unsigned char i, j;
i = readByte();
if(i == 0xF0) //A key is being released
{
relFlag = 1;
return 0;
}
if(i == 0xE0) // Extended key operation
{
extFlag = 1;
relFlag = 0; //0xE0 always first in sequence, OK to clear this
return 0;
}
if(relFlag == 0) // Pressing a key
{
if(extFlag == 0) // Non-extended key pressed
{
if(i == 0x12 || i == 0x59)
{
shiftSet = 1;
return 0;
}
if(i == 0x58)
{
sendByte(0xED);
if(capsSet == 0)
{
capsSet = 1;
sendByte(0x04);
} else
{
capsSet = 0;
sendByte(0x00);
}
return 0;
}
}
j = translate(i);
extFlag = 0;
return j;
}
if(relFlag == 1) //Releasing a key
{
relFlag = 0; //If a flag was set but not handled, we wouldn't have gotten here
extFlag = 0; //OK to clear this here
if(extFlag == 0) // Releasing a nonextended key
{
if(i == 0x12 || i == 0x59)
{
shiftSet = 0;
return 0;
}
}
// } else // Releasing an extended key
// {
// return 0;
// }
// return 0;
}
return 0;
}
| [/code] |
|
|
tranhuyky
Joined: 25 Dec 2006 Posts: 4
|
Please help me, turn on Numlock led |
Posted: Mon Dec 25, 2006 7:35 am |
|
|
I connect a PS/2 Keyboard (Mitsumi) with PIC 16F877A. I want to turn on Numlock led, but i can't. i try many way but now is not Ok. Anyone else did it, Would you please help me. |
|
|
foodwatch
Joined: 18 Apr 2006 Posts: 66
|
Keyboard program |
Posted: Sun Jan 14, 2007 7:40 pm |
|
|
Steve,I tried your program on an 18f4550 and it works fine. In my project I need to read a stand alone numeric keypad. I am a C novice and am having trouble figuring out how to modify/add the scan table to allow numeric keypad scan codes. I dont need any of the codes for a full keyboard. Thanks |
|
|
smtpl04
Joined: 19 Apr 2007 Posts: 1 Location: India
|
ps/2 keyboard driver |
Posted: Thu Apr 19, 2007 7:30 am |
|
|
I have tried your code & its working best for keyboard to PIC transfer. But not for PIC to keyboard transfer. I have modified your void sendByte(byte b) code(given below) for PIC to keyboard transfer & its working ok. Try it in your project & reply me.
Also I need another code for PIC to PC communication through ps/2 port. Please help me for this.
Thanks,
Sardar Patil.
Code: |
void sendByte(byte b)
{
byte a=0;
byte p = 0;
boolean t = 0;
// return; // THIS IS NOT FULLY WORKING ON ALL KEYBOARDS
// SO IT IS COMMENTED OUT
// Some kind of timing issue or something. Whatever, they're just LEDs
disable_interrupts(GLOBAL);
output_low(KEYCLK);
delay_us(80);
// input(KEYCLK);
output_low(KEYDATA);
output_high(KEYCLK);
input(KEYCLK);
for(a=0; a<8; a++)
{
while(input(KEYCLK) == 1); //wait for 0
t = bit_test(b,a);
output_bit(KEYDATA, t);
if(t)
p++;
while(input(KEYCLK) == 0); //wait for 1
}
while(input(KEYCLK) == 1); //wait for 0
t = bit_test(p,0);
t = ~t;
while(input(KEYCLK) == 0); //wait for 1
output_bit(KEYDATA, t); // input(KEYDATA);
while(input(KEYCLK) == 1); //wait for 0
/// while(input(KEYCLK) == 0); //wait for 1
output_float(KEYDATA);
enable_interrupts(GLOBAL);
}
| [/quote] _________________ sardar |
|
|
3dfx
Joined: 24 Mar 2007 Posts: 6
|
|
Posted: Sat May 12, 2007 5:04 am |
|
|
i have tested this code but i couldnt get any response from keyboard.is there any thing wrong? |
|
|
Celso Missias
Joined: 24 Oct 2007 Posts: 1
|
|
Posted: Wed Oct 24, 2007 6:40 am |
|
|
Hi Steve
Thanks for the code,
After each key pressed a '?' is sended via serial too after the letter pressed.
So, when I press 'a', I receive 'a?',
'b', 'b?' and so on...
Why it is happening?
Thanks |
|
|
Dimlow
Joined: 24 Nov 2007 Posts: 9
|
Parity bit |
Posted: Tue Sep 30, 2008 10:44 am |
|
|
I think the parity bit in the send byte is wrong. Your Sending and even parity, not and odd parity!!! Probably why it don't work on all keyboards
Code: | output_bit(DATA, p&0x01); |
should read
Code: | output_bit(DATA, p&0x10); |
|
|
|
abo_shreek11
Joined: 27 Sep 2008 Posts: 10
|
Re: Keyboard program |
Posted: Thu Nov 27, 2008 8:48 am |
|
|
foodwatch wrote: | Steve,I tried your program on an 18f4550 and it works fine. In my project I need to read a stand alone numeric keypad. I am a C novice and am having trouble figuring out how to modify/add the scan table to allow numeric keypad scan codes. I dont need any of the codes for a full keyboard. Thanks |
May you tell me how much resistance is the pull-up resistor you used ? I have 18f4550 too, and when I press a button on key board it shows with some "?" character on the lcd. I have a doubt in the pull-up resistor I am using. |
|
|
ThePraiodanish
Joined: 06 Mar 2010 Posts: 3
|
|
Posted: Sat Mar 06, 2010 7:36 am |
|
|
Hi all,
you can get rid of the "?" after each key pressed by replacing the line
with
in the function unsigned char translate(unsigned char scancode).
Although the code works great for me I have one problem:
For debugging purposes I print the received scancode to the rs232 port within the interrupt routine, the reading and printing of the circular buffer is disabled.
However if I write
Code: |
while(1)
{
//printKey();
//for(i=0 ; i < 10000 ; i++);
delay_ms(1);
}
|
in the main() - function the scancodes returned are garbage!
It seems as if the delay-routine wasn't interrupted by the interrupt properly.
At first I thought it's due to the time the delay needs to finish the statement which is in progress before jumping to the interrupt handler but I saw that the author runs this code at 4 MHz clock which means there are about 40 cycyles between each interrupt. I'm running the code at 11,0592 MHz (=110 cycles between each interrupt) so there should be plenty time for jumping to the interrupt handler. Any Ideas?
Thanks a lot,
Thomas |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Mar 07, 2010 1:53 am |
|
|
Ask your question in the General Discussion forum. You'll get far
better exposure there, and your problem is likely related to general
programming issues, and not specifically to this PS/2 driver. |
|
|
guntor
Joined: 10 Aug 2010 Posts: 1
|
PS2 Keyboard emulator v.1.0.0 alpha |
Posted: Tue Aug 10, 2010 3:27 pm |
|
|
Maybe someone need a PS2 Keyboard emulator
Code: |
#include <12F675.h>
#fuses INTRC_IO,NOWDT,NOMCLR,NOPROTECT
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_A0,rcv=PIN_A1,bits=8,STREAM=DEBUG)
#use rs232(baud=9600,parity=N,xmit=PIN_A3,rcv=PIN_A2,bits=8,STREAM=RFID)
//#define DEBUGLONG
//#define DEBUGSHORT
#define KEYCLK PIN_A5
#define KEYDATA PIN_A4
typedef unsigned char uchar;
typedef boolean bit;
/*
-----
[+5V] VDD -|1 8|- VSS [GND]
[KEYCLK] (with Pullup) GP5/T1CKI/OSC1/CLKIN -|2 7|- GP0/AN0/CIN+/ICSPDAT [XMIT DEBUG]
[KEYDATA] (with Pullup) GP4/AN3/T1G/OSC2/CLKOUT -|3 6|- GP1/AN1/CIN-/VREF/ICSPCLK [RCV DEBUG]
GP3/MCLR/VPP -|4 5|- GP2/AN2/T0CKI/INT/COU
-----
*/
// A-Z, völlig willkürliche anordnung...
// http://www.computer-engineering.org/ps2keyboard/scancodes2.html
// Für break Code: vorher 0xF0 senden, dann wieder Code
const uchar t_a_z[26]={0x1C,0x32,0x21,0x23,0x24,0x2B,0x34,0x33,0x43,0x3B,0x42,0x4B,0x3A,0x31,0x44,0x4D,0x15,0x2D,0x1B,0x2C,0x3C,0x2A,0x1D,0x22,0x35,0x1A};
// 0-9, völlig willkürliche anordnung...
const uchar t_0_9[26]={0x45,0x16,0x1E,0x26,0x25,0x2E,0x36,0x3D,0x3E,0x46};
// ASCII translatedtoScantable
uchar atrsc[2];
uchar lastbyte;
void sendNibble(boolean t);
bit getNibble();
void sendByte(byte sendbyte);
uchar receiveByte();
void senduchar(uchar sendb) ;
void translateASCIItoScanTable(uchar ASCII,uchar extended);
void sendString(uchar* str);
// SetBit: Einzelnes Bit senden...
//
// .... ......... ........
// | |...,....| |........| |........
// 10 w 30 40
//
void sendBit(boolean t){
delay_us(10);//15
output_bit(KEYDATA,t);
delay_us(30); //20
output_low(KEYCLK);
delay_us(40); //40
output_high(KEYCLK);
}
// getBit: Einzelnes Bit empfangen...
//
// .... ......... ........
// | |........| , |........| |........
// 40 15 r 20
bit getBit(){
bit t;
output_low(KEYCLK);
delay_us(40);
output_high(KEYCLK);
delay_us(15);
t=input(KEYDATA);
delay_us(20);
return t;
}
void sendByte(byte sendbyte){
uchar i;
byte parity = 0;
bit t = 0;
// ausgangslage
output_high(KEYCLK);
output_low(KEYDATA);
// Delay, falks mehrere Bytes hintereinander gesendet werden...
delay_us(250);
// startbit
output_high(KEYCLK);
sendBit(0);
for(i=0;i<8;i++){
t=bit_test(sendbyte,i);
if(t)parity++;
sendBit(t);
}
// Parity Bit
t=~bit_test(parity,0);
sendBit(t);
// Stop bit
sendBit(0);
lastbyte=sendbyte;
input(KEYCLK);
input(KEYDATA);
}
uchar receiveByte(){
uchar empf;
uchar parity;
uchar i;
bit t;
bit stopbit;
// ignore startbit???
// Generate Clock and receive bits.. LSB first...
for(i=7;i!=0;i--){
t=getBit();
if(t){
parity++;
empf|=t<<i;
}
}
// parity bit...
t=getBit();
// stop bit...
stopbit=getBit();
if(stopbit!=1){
#ifdef DEBUGLONG
fprintf(DEBUG,"Falsches Stopbit");
#endif
#ifdef DEBUGSHORT
fprintf(DEBUG,"fsb");
#endif
}
// ACK senden...
delay_us(10);
output_low(KEYDATA);
delay_us(25);
output_low(KEYCLK);
delay_us(40);
output_high(KEYCLK);
if(t!=~bit_test(parity,0)){
#ifdef DEBUGLONG
fprintf(DEBUG,"Haha, partity falsch");
#endif
#ifdef DEBUGSHORT
fprintf(DEBUG,"fp");
#endif
}
#ifdef DEBUGLONG
fprintf(DEBUG,"empfanges byte %x",empf);
#endif
#ifdef DEBUGSHORT
fprintf(DEBUG,"eb %x",empf);
#endif
return empf;
}
void senduchar(uchar sendb) {
uchar empf;
unsigned int16 breaker;
disable_interrupts(GLOBAL);
//Summary: Bus States
//Data = high, Clock = high: Idle state.
//Data = high, Clock = low: Communication Inhibited.
//Data = low, Clock = high: Host Request-to-Send
while(true){
// Host will was...
if(input(KEYCLK)==0 && input(KEYDATA)==1){
#ifdef DEBUGLONG
fprintf(DEBUG,"dammed, not free");
#endif
#ifdef DEBUGSHORT
fprintf(DEBUG,"nf");
#endif
// 50ms zeit, um Data low zu ziehen und Clock auf high
// Dann dürfen wir Clock spielen und nibbles empfangen...
breaker=0;while(input(KEYDATA)==1&&input(KEYCLK)==0&&breaker<0xFFFFF)breaker++; // Wait for 0
breaker=0;while(input(KEYCLK)==0&&breaker<0xFFFFF)breaker++; // Wait for 0
#ifdef DEBUGLONG
fprintf(DEBUG,"ready to receive");
#endif
#ifdef DEBUGSHORT
fprintf(DEBUG,"rr");
#endif
// receive Byte
empf=receiveByte();
#ifdef DEBUGLONG
fprintf(DEBUG,"empfanges byte %x",empf);
#endif
#ifdef DEBUGSHORT
fprintf(DEBUG,"eb %x",empf);
#endif
// Reset Keyboard (Too fast, false parity etc...)
if(empf==0xFF){
// Acknowledge
sendbyte(0xFA);
// BAT erfolgreich...
sendbyte(0xAA);
#ifdef DEBUGLONG
fprintf(DEBUG,"Bytes sent.");
#endif
#ifdef DEBUGSHORT
fprintf(DEBUG,"bs");
#endif
// Resend last byte...
}else if(empf==0xFE){
sendbyte(lastbyte);
}
// Wenn Frei (CLK = HIGH),
// Schauen, ob nach 50us immer noch frei, dann frei zur verwendung...
}else{
delay_us(50);
if(input(KEYCLK)==1){
break;
}
}
}
#ifdef DEBUGLONG
fprintf(DEBUG,"yeah, free");
#endif
#ifdef DEBUGSHORT
fprintf(DEBUG,"f");
#endif
// Todo: special caracters
translateASCIItoScanTable(sendb,0x00);
// Todo: uppercase
if(atrsc[1]!=0x00){
sendbyte(atrsc[1]);
}
// Send Make Key...
sendbyte(atrsc[0]);
// Ssend Break Key...
sendbyte(0xF0);
sendbyte(atrsc[0]);
if(atrsc[1]!=0x00){
sendbyte(0xF0);
sendbyte(atrsc[1]);
}
// Not too many keys per second
delay_ms(20);
enable_interrupts(GLOBAL);
}
void translateASCIItoScanTable(uchar ASCII,uchar extended){
if(ASCII>='A' && ASCII<='Z'){
atrsc[0]=t_a_z[ASCII-'A'];
atrsc[1]=0x12;
}else if(ASCII>='a' && ASCII<='z'){
atrsc[0]=t_a_z[ASCII-'a'];
atrsc[1]=0x00;
}else if(ASCII>='0' && ASCII<='9'){
atrsc[0]=t_0_9[ASCII-'0'];
atrsc[1]=0x00;
// Rest of Translation Table
// layout spefific!!
// layout: http://upload.wikimedia.org/wikipedia/commons/2/22/KB_US-International.svg
// http://www.computer-engineering.org/ps2keyboard/scancodes2.html
}else if(ASCII>=' ' && ASCII<=' '){
//atrsc[0]=t_a_z[ASCII-'A'];
atrsc[0]=0x29;
atrsc[1]=0x00;
}
}
void sendString(uchar* str){
while(*str!=0x00){
senduchar(*str);
str++;
}
}
void main() {
while(TRUE){
strcpy(RFID_rec.data,"ABCDE532d");
sendString(RFID_rec.data);
delay_ms(2500);
}
} |
|
|
|
Tufican
Joined: 23 Feb 2011 Posts: 10 Location: Turkey- izmir
|
doesn't work :((( |
Posted: Mon Sep 19, 2011 12:54 pm |
|
|
hi everybody i have a problem
i m using ccs c canbus kit pic18f4580
i wrote and add this lines to ps2 code
Code: |
#include <18f4580.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,NOBROWNOUT,NOPUT
#use delay(clock=20000000) // my clock frequency
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
//my baud rate and rs 232 pins. serial is working fine..
#define Clock pin_d0
#define Data pin_d1
main();
.
.
.
set_tris_d(0b00000011); // i am using my free pins d0 and d1 for input? |
Where is my wrong please help me :( i m going crazy :((
i have a pc oscilloscope and when i push the button i can see clock and data
keyboard is working.
have a good day to everybody
the total code is here.
Code: |
#include <18f4580.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP,NOBROWNOUT,NOPUT
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define Clock pin_d0
#define Data pin_d1
//D0 - Clock
//D1 - Data
// Clock must be the interrupt pin
unsigned char bData[16];
unsigned char idx=0;
unsigned char tmp=0;
unsigned char readByte();
unsigned char processByte();
unsigned char waitKey();
byte keyhit();
unsigned char translate(unsigned char scancode);
volatile byte shiftSet = 0;
byte kbBuffer[16];
byte kbPos = 0;
byte kbSize = 0;
byte capsSet = 0;
volatile byte extFlag = 0;
volatile byte relFlag = 0;
volatile byte key=0;
void sendByte(byte b)
{
byte a=0;
byte p = 1;
byte t = 0;
return; // THIS IS NOT FULLY WORKING ON ALL KEYBOARDS
// SO IT IS COMMENTED OUT
// Some kind of timing issue or something. Whatever, they're just LEDs
disable_interrupts(GLOBAL);
output_low(CLOCK);
delay_us(300);
output_low(DATA);
input(CLOCK);
for(a=0; a<8; a++)
{
t = b&(1<<a);
while(input(CLOCK) == 1); //wait for 0
output_bit(DATA, t);
if(t)
p++;
while(input(CLOCK) == 0); //wait for 1
}
while(input(CLOCK) == 1); //wait for 0
output_bit(DATA, p&0x01);
while(input(CLOCK) == 0); //wait for 1
input(DATA);
while(input(DATA) == 1); //wait for 0
while(input(CLOCK) == 1); //wait for 0
delay_ms(10);
clear_interrupt(INT_EXT);
enable_interrupts(GLOBAL);
}
main()
{
int i=0;
unsigned char k=0;
printf("READY >");
output_b(0x00);
input(CLOCK);
delay_ms(100);
ext_int_edge(H_to_L);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
set_tris_d(0b00000011); // RA0 ucu giriş olarak ayarlandı.
while(1)
{
k = waitKey();
printf("%c", k);
while(keyhit())
printf("%c", waitKey());
}
}
byte keyhit()
{
return kbSize != 0;
}
unsigned char waitKey()
{
unsigned char k = 0;
while(kbSize == 0);
k = kbBuffer[(kbPos - kbSize)&0x0F];
kbSize--;
return k;
}
#int_ext
void kbInterrupt()
{
volatile byte k=0;
k = processByte();
if(k != 0)
{
kbBuffer[kbPos] = k;
kbPos = ++kbPos & 0x0F;
kbSize++;
}
return;
}
unsigned char readByte()
{
int i=0, t=0;
idx=0;
tmp=0;
i=0;
goto dataread;
// while(INPUT(CLOCK) != 0); // Wait for a keypress
t=0;
while(INPUT(CLOCK) != 0 && t<255) // Wait for clock, time out if needed
{
delay_us(1);
t++;
}
for(i=0; i<11; i++)
{
t=0;
while(INPUT(CLOCK) != 0 && t<255) // Wait for clock, time out if needed
{
delay_us(1);
t++;
}
dataread:
bData[idx]=INPUT(DATA);
idx++;
if(idx==9)
{
for(idx=1; idx<9; idx++)
if(bData[idx]!=0)
tmp|=(1<<(idx-1));
return tmp;
idx=0;
tmp=0;
}
// while(INPUT(CLOCK) == 0);
t=0;
while(INPUT(CLOCK) == 0 && t<255) // Wait for clock, time out if needed
{
delay_us(1);
t++;
}
}
}
static const unsigned char scantableAZ[]={
0x1C, 0x32, 0x21, 0x23, 0x24, 0x2B, 0x34, 0x33, 0x43, 0x3B, 0x42, 0x4B, 0x3A, // A-Z
0x31, 0x44, 0x4D, 0x15, 0x2D, 0x1B, 0x2C, 0x3C, 0x2A, 0x1D, 0x22, 0x35, 0x1A};
// Normal numeric scancodes, starting with ',' .
static const unsigned char scantable09n[]=
{
0x41, 0x4E, 0x49, 0x4A, // , - . /
0x45, 0x16, 0x1E, 0x26, 0x25, 0x2E, 0x36, 0x3D, 0x3E, 0x46, //Digits 0-9
0x00, 0x4C, 0x00, 0x55 // 0 ; 0 =
};
// Shift scancodes, starting at '!'
static const unsigned char scantable09s[]=
{
0x16, 0x52, 0x26, 0x25, 0x2E, 0x3D, 0x00, 0x46, 0x45, 0x3E, 0x55
};
// Normal misc. scancode map. Scancode, ASCII value
static const unsigned char scanmapn[]=
{0x54, '[', 0x5B, ']', 0x0E, '`', 0x5D, '\\', 0x52, '\''};
// Shifted misc. scancode map. Scancode, ASCII value
static const unsigned char scanmaps[]=
{0x1E, '@', 0x36, '^', 0x4E, '_', 0x54, '{', 0x5B, '}', 0x5D, '|',
0x4C, ':', 0x41, '<', 0x49, '>', 0x4A, '?', 0x0E, '~'};
// Scancode map independent of Shift
static const unsigned char scanmapx[]=
{0x29, ' ', 0x5A, '\r', 0x0D, '\t', 0x76, 27, 0x66, 0x08};
// Extended scancode map
static const unsigned char scanmape[]=
{
0x71, 0x7F
};
unsigned char translate(unsigned char scancode)
{
int i=0;
if(extFlag == 0)
{
for(i=0; i<10; i+=2)
if(scanmapx[i] == scancode)
return scanmapx[i+1];
for(i=0; i<26; i++)
if(scantableAZ[i] == scancode)
if(shiftSet ^ capsSet)
return i+65;
else
return i+65 + 32;
if(shiftSet)
{
for(i=0; i<11; i++)
if(scantable09s[i] == scancode)
return i+'!';
for(i=0; i<22; i+=2)
if(scanmaps[i] == scancode)
return scanmaps[i+1];
} else
{
for(i=0; i<18; i++)
if(scantable09n[i] == scancode)
return i+',';
for(i=0; i<10; i+=2)
if(scanmapn[i] == scancode)
return scanmapn[i+1];
}
} else // Extended keys
{
for(i=0; i<2; i+=2)
if(scanmape[i] == scancode)
return scanmape[i+1];
}
return '?';
}
unsigned char processByte()
{
unsigned char i, j;
i = readByte();
if(i == 0xF0) //A key is being released
{
relFlag = 1;
return 0;
}
if(i == 0xE0) // Extended key operation
{
extFlag = 1;
relFlag = 0; //0xE0 always first in sequence, OK to clear this
return 0;
}
if(relFlag == 0) // Pressing a key
{
if(extFlag == 0) // Non-extended key pressed
{
if(i == 0x12 || i == 0x59)
{
shiftSet = 1;
return 0;
}
if(i == 0x58)
{
sendByte(0xED);
if(capsSet == 0)
{
capsSet = 1;
sendByte(0x04);
} else
{
capsSet = 0;
sendByte(0x00);
}
return 0;
}
}
j = translate(i);
extFlag = 0;
return j;
}
if(relFlag == 1) //Releasing a key
{
relFlag = 0; //If a flag was set but not handled, we wouldn't have gotten here
extFlag = 0; //OK to clear this here
if(extFlag == 0) // Releasing a nonextended key
{
if(i == 0x12 || i == 0x59)
{
shiftSet = 0;
return 0;
}
}
// } else // Releasing an extended key
// {
// return 0;
// }
// return 0;
}
return 0;
} |
|
|
|
pocanada
Joined: 04 Feb 2013 Posts: 1
|
Reading keyboard PS/2 bytes |
Posted: Mon Feb 04, 2013 6:32 pm |
|
|
Here is example of code I used to decode the PS/2 bytes. I used a PIC18F4550 with CLOCK = PIN_B1(Int1) and DATA = PIN_D4. It seemed to work better when I read all the bytes first rather than one at a time before decoding.
Code: |
//------------------------------------------------------------------
//----------------------- PS2_Keyboard -----------------------------
//------------------------------------------------------------------
#include "18F4550.h"
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
#use rs232(baud=19200,xmit=PIN_C6,rcv=PIN_C7,stream=prime)
//---------- PIC 18F4550 board stuff ------------------------------
#use fast_IO(B)
#use fast_IO(D)
#define led_on output_high(PIN_D3)
#define led_off output_high(PIN_D3)
#define y_led_on; output_low(PIN_D7)
#define y_led_off; output_high(PIN_D7)
#define g_led_on; output_low(PIN_D5)
#define g_led_off; output_high(PIN_D5)
#define but PIN_B4
#define but PIN_B4
//-------- Rotary Switch Stuff A is the interrupt2 pin ------------
#define A PIN_B2
#define B PIN_D6
#define PB PIN_D4
//------ PS2 Keyboard stuff---- Clock must be the interrupt1 pin ---
#define CLOCK PIN_B1
#define DATA PIN_D1
//------------------
#define hi_clk_delay; t=0;while(input(CLOCK)==1 && t<255){delay_us(1);t++;}
#define lo_clk_delay; t=0;while(input(CLOCK)==0 && t<255){delay_us(1);t++;}
//------------------
int8 readabyte(void);
int8 processByte(void;
int8 translate(int1 shft,int8 scancode);
//------------------
int8 t;
int8 bData[16];
//------------------ scan codes --------------------------------------------
const int8 scan_byte[]={
0x1C, 0x32, 0x21, 0x23, 0x24, 0x2B, 0x34, 0x33, 0x43, 0x3B, 0x42, 0x4B, 0x3A,
0x31, 0x44, 0x4D, 0x15, 0x2D, 0x1B, 0x2C, 0x3C, 0x2A, 0x1D, 0x22, 0x35, 0x1A,
0x45, 0x16, 0x1E, 0x26, 0x25, 0x2E, 0x36, 0x3D, 0x3E, 0x46, 0x0E, 0x4E ,0x55,
0x5D, 0x29, 0x54, 0x5B, 0x4C, 0x52, 0x41, 0x49, 0x4A};
//------------------ upper case literals -----------------------------------
const int8 upper_char[]={
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
')', '!', '@', '#', '$', '%', '^', '&', '*', '(', '~', '_', '+',
'|', ' ', '{', '}', ':', '"', '<', '>', '?' };
//------------------ lower case literals ----------------------------------
const int8 lower_char[]={
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '`', '-', '=',
'\\', ' ', '[', ']', ';', '\'', ',', '.', '/' };
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
#int_ext1
void kbInterrupt() {
int8 c=0;
disable_interrupts(INT_EXT1_H2L);
c = processByte();
if(c !='?')
fprintf(prime,"%c",c);
enable_interrupts(INT_EXT1_H2L);
} //kbInterrupt()
//-------------------------------------------------------------------------
main(){
set_tris_b(0xFF);
set_tris_d(0x5F);
port_b_pullups(0xFF);
fprintf(prime,"PS2_Keyboard - January 31, 2013\r\n");
enable_interrupts(INT_EXT1_H2L);
enable_interrupts(GLOBAL);
while(1){
} //while(1)
} //main
//---------------------------------------------------
//-------------------- my readabyte() -----------------
//---------------------------------------------------
int1 readabyte(void){
int8 i=0;
int8 n=0;
int8 bPar=0;
int8 tmp=0;
int1 enough=0;
for(i=0;i<16;i++)
bData[i]=0;
while(input(CLOCK)==0); //start pulse
do{
for(i=0;i<8;i++){ // following 8 pulses
hi_clk_delay;
shift_right(&bData[n],1,input(DATA));
while(input(CLOCK)==0);
lo_clk_delay;
} //for i<8
for(i=0;i<2;i++){ // parity and stop pulse
hi_clk_delay;
shift_right(&bPar,1,input(DATA));
while(input(CLOCK)==0);
lo_clk_delay;
} //for i<2
tmp++;
hi_clk_delay; // Inner pulses delay
if(input(CLOCK)== 1) // if after this clock still high == end
enough = 1;
else{
n++;
lo_clk_delay; //start pulse delay
} //else
}while((n < 16) && !enough); //do
return(tmp);
} //readabyte()
//------------------------------------------------
//----------------------- my process byte ----------
//------------------------------------------------
int8 processByte(void){
int8 k=0;
int8 j=0;
static int1 shift,caplock;
k = readabyte(); //k = # bytes in bData array;
#ifdef PRINT_DATA
int8 i;
fprintf(prime,"%U: ",k);
for(i=0;i<k;i++)
fprintf(prime,"%X ",bData[i]);
fprintf(prime,"\r\n");
#endif
//Look for cap locks first
if((bData[0]==0x58)&&(!caplock)){
shift=1;
caplock=1;
} //if...
else if((bData[0]==0x58)&&(caplock)){
shift=0;
caplock=0;
} //else if...
//Then Look for L Shift or R Shift keys
if((bData[0]==0x12)||(bData[0]==0x59))
shift = 1;
else{
if(((bData[0]==0xF0)&&(bData[1]==0x12)||
(bData[0]==0xF0)&&(bData[1]==0x59))&& !caplock)
shift = 0;
} //else...
j = translate(shift,bData[0]); //"j" = int8 of the character returned
return(j);
} //processByte()
//--------------------------------------------------------------
//------------------ my translate -----------------------------
//------------------------------------------------------------
int8 translate(int1 shft,int8 scancode){
int8 i;
if(shft){
for(i=0; i<52; i++){
if(scan_byte[i] == scancode)
return(upper_char[i]);
} //for(i=...
} //shft
else{
for(i=0; i<52; i++){
if(scan_byte[i] == scancode)
return(lower_char[i]);
} //for(i=...
} //!shft
return('?');
} //translate()
|
|
|
|
mariano
Joined: 06 Oct 2013 Posts: 1
|
Re: PS/2 keyboard driver/decoder, interrupt driven, 16F and |
Posted: Sun Oct 06, 2013 9:50 am |
|
|
stevenm86 Hello.
Hey proven soft and the problem I had is that when you press the number buttons works well then pressing the shift key changes to the symbols even hi all well but when they press the shift key does not return to the numbers remaining in the Symbols could help me, thanks my name is Mariano and my email marianoarias1967@yahoo.com.ar |
|
|
kalyan
Joined: 16 May 2014 Posts: 7
|
Re: PS/2 keyboard driver/decoder, interrupt driven, 16F and |
Posted: Sat Jun 07, 2014 9:23 am |
|
|
mariano wrote: | stevenm86 Hello.
Hey proven soft and the problem I had is that when you press the number buttons works well then pressing the shift key changes to the symbols even hi all well but when they press the shift key does not return to the numbers remaining in the Symbols could help me, thanks my name is Mariano and my email marianoarias1967@yahoo.com.ar |
even i am facing the same problem kindly help |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|