AVR External Interrupts - INT0 Example
AVR External Interrupts - INT0 Example
AVR External Interrupts - INT0 Example
1 of 5
http://www.electronics-base.com/projects/complete-projects/108-avr-p...
Adding PC keyboard to your hardware design and connecting microcontroller to it is both useful and COOL!
In this project we will explain how this is done and provide complete source code and step by step tutorial how to do this with AVR
microcontroller.
This project uses interrupts to interface a PS/2 keyboard with AVR ATmega8535, but code can be very easily adjusted for any microcontroller. The simplicity of the
protocol and the asynchronous nature of the clock generated by the keyboard make this a great simple start for getting familiar with interrupts and interrupt handlers. If
you have no experience with external interrupts, see AVR external interrupts - INT0 example.
First to say few words on how PS/2 port communicates.
All signals are generated by keyboard, AVR only reads pin state at pins defined as inputs.
Here is PS/2 connector pinout :
Pin 1 Data
Pin 2 Not Connected
Pin 3 GND
Pin 4 Vcc (+5V)
Pin 5 Clock
Pin 6 Not Connected
The easiest way to connect it is to find PS/2 female connector or take one from old broken PC motherboard.
You need to use four pins and we connected four wires to these pins: Vcc (red), GND (black), Data (white), Clock (yellow).
These signals are very fast so simple pooling pin state would be too slow and we could lose some data. Because of this, we use external interrupt INT0 for clock falling
edge detection and readout of key data.
28/05/2015 18:02
2 of 5
http://www.electronics-base.com/projects/complete-projects/108-avr-p...
On picture above we can see clock frequency is around 10 kHz. Yellow line is clock and blue one is data.
Each data packet consists of 11 bits. These are 1 start bit, 8 data bits, parity and stop bit. This is illustrated on picture below.
When we capture byte from keyboard, we have Keyboard Scan Code. These are codes that give us information which key is pressed or released. Table of all Keyboard
Scan Codes is given below :
KEY
MAKE
BREAK
KEY
MAKE
BREAK
1C
F0,1C
46
32
F0,32
21
F0,21
23
-----
KEY
MAKE
BREAK
F0,46
54
FO,54
0E
F0,0E
INSERT
E0,70
E0,F0,70
4E
F0,4E
HOME
E0,6C
E0,F0,6C
F0,23
55
FO,55
PG UP
E0,7D
E0,F0,7D
24
F0,24
5D
F0,5D
DELETE
E0,71
E0,F0,71
2B
F0,2B
BKSP
66
F0,66
END
E0,69
E0,F0,69
34
F0,34
SPACE
29
F0,29
PG DN
E0,7A
E0,F0,7A
33
F0,33
TAB
0D
F0,0D
U ARROW
E0,75
E0,F0,75
43
F0,43
CAPS
58
F0,58
L ARROW
E0,6B
E0,F0,6B
3B
F0,3B
L SHFT
12
FO,12
D ARROW
E0,72
E0,F0,72
42
F0,42
L CTRL
14
FO,14
R ARROW
E0,74
E0,F0,74
4B
F0,4B
L GUI
E0,1F
E0,F0,1F
NUM
77
F0,77
3A
F0,3A
L ALT
11
F0,11
KP /
E0,4A
E0,F0,4A
31
F0,31
R SHFT
59
F0,59
KP *
7C
F0,7C
44
F0,44
R CTRL
E0,14
E0,F0,14
KP -
7B
F0,7B
4D
F0,4D
R GUI
E0,27
E0,F0,27
KP +
79
F0,79
15
F0,15
R ALT
E0,11
E0,F0,11
KP EN
E0,5A
E0,F0,5A
2D
F0,2D
APPS
E0,2F
E0,F0,2F
KP .
71
F0,71
1B
F0,1B
ENTER
5A
F0,5A
KP 0
70
F0,70
2C
F0,2C
ESC
76
F0,76
KP 1
69
F0,69
3C
F0,3C
F1
05
F0,05
KP 2
72
F0,72
2A
F0,2A
F2
06
F0,06
KP 3
7A
F0,7A
1D
F0,1D
F3
04
F0,04
KP 4
6B
F0,6B
22
F0,22
F4
0C
F0,0C
KP 5
73
F0,73
35
F0,35
F5
03
F0,03
KP 6
74
F0,74
1A
F0,1A
F6
0B
F0,0B
KP 7
6C
F0,6C
45
F0,45
F7
83
F0,83
KP 8
75
F0,75
16
F0,16
F8
0A
F0,0A
KP 9
7D
28/05/2015
F0,7D
-----
18:02
3 of 5
http://www.electronics-base.com/projects/complete-projects/108-avr-p...
45
F0,45
F7
83
F0,83
KP 8
75
F0,75
16
F0,16
F8
0A
F0,0A
KP 9
7D
F0,7D
1E
F0,1E
F9
01
F0,01
5B
F0,5B
26
F0,26
F10
09
F0,09
4C
F0,4C
25
F0,25
F11
78
F0,78
'
52
F0,52
2E
F0,2E
F12
07
F0,07
41
F0,41
36
F0,36
PRNT
SCRN
E0,12,
E0,7C
E0,F0,
7C,E0,
F0,12
49
F0,49
3D
F0,3D
SCROLL
7E
F0,7E
4A
F0,4A
PAUSE
E1,14,77,
E1,F0,14,
F0,77
-NONE8
3E
F0,3E
And you can download this table along with some extra codes for special function buttons at this link.
In this example we implemented conversion of Keyboard Scan Codes to their ASCII codes. As you can see, any key sends its code when it is pressed or byte 0xf0
followed by taster code when it is released.We will use this to detect whether shift taster is pressed or not. Since scan codes for a and A are the same we have to
detect when shift is pressed.
External interrupt on falling edge of clock signal is used. Usage of external interrupts on AVR is explained more at AVR external interrupts - INT0 example.Reception of
data from keyboard is done in INT0 ISR.
Here is code that does this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
It is very simple code that receives bit by bit and adds it to appropriate place in previously declared data variable. Also, start, parity and stop bits are ignored so only scan
code will be placed in data variable.When received, scan code needs to be converted into ASCII value.To be able to do this we defined constant strings that contains all
ASCII codes and its keyboard scan codes. Here are those strings:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
?
// keyboard scan codes (without & with shift key pressed)
flash unsigned char unshifted[67][2] = {
//0x0d,9,
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,'=',0x5a,13,
0x5b,']',0x5d,'/',0x61,'<',0x66,8, 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 };
flash unsigned char shifted[67][2] = {
//0x0d,9,
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,'+',0x5a,13,
0x5b,'}',0x5d,'|',0x61,'>',0x66,8, 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 };
Conversion of keyboard scan code to ASCII code is done with function decode(data).
Here is its source code:
1
2
3
4
5
6
7
8
//***********************************************
// decode scan code
void decode(unsigned char sc) {
static unsigned char is_up=0, shift = 0, mode = 0;
unsigned char i;
if (!is_up) {
switch (sc) {
28/05/2015 18:02
4 of 5
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
http://www.electronics-base.com/projects/complete-projects/108-avr-p...
unsigned char i;
if (!is_up) {
switch (sc) {
case 0xF0 :// The up-key identifier
is_up = 1;
break;
case 0x12 :// Left SHIFT
shift = 1;
break;
case 0x59 :// Right SHIFT
shift = 1;
break;
case 0x05 :// F1
if(mode == 0)
mode = 1;// Enter scan code mode
if(mode == 2)
mode = 3;// Leave scan code mode
break;
default:
if(mode == 0 || mode == 3) {// If ASCII mode
if(!shift) {// If shift not pressed, do a table look-up
for(i = 0; unshifted[i][0]!=sc && unshifted[i][0]; i++);
if (unshifted[i][0] == sc) {
putchar(unshifted[i][1]);
}
}
else {// If shift pressed
for(i = 0; shifted[i][0]!=sc && shifted[i][0]; i++);
if (shifted[i][0] == sc) {
putchar(shifted[i][1]);
}
}
}
else putchar(sc);
// scan code mode (debugging mode)
break;
}
}
else {
is_up = 0;// Two 0xF0 in a row not allowed
switch (sc) {
case 0x12 :// Left SHIFT
shift = 0;
break;
case 0x59 :// Right SHIFT
shift = 0;
break;
case 0x05 :// F1 -- F1 puts you in debugging mode
// pressing F1 again gets you out of debugging mode
// in debugging mode hex code of the scan codes
// are stored in the buffer instead of their ascii codes
if(mode == 1)
mode = 2;
if(mode == 3)
mode = 0;
break;
}
}
}
//***********************************************
It is simple state machine that keeps track if shift key is pressed or not and finds appropriate ASCII code for every received keyboard scan code received from PS/2 port.
By pressing F1 key you can choose to send scan codes directly to UART without conversion. This is done for you to understand better how this conversion is done.
Because of its simplicity whole code is done in interrupt, so while(1) loop is empty and can execute other tasks. Implementation in interrupt guarantees that no data will be
lost.
Here is video showing how this example works in practice:
28/05/2015 18:02
5 of 5
http://www.electronics-base.com/projects/complete-projects/108-avr-p...
You can download complete project for connection of AVR with PS/2 tastature and source code from this link.
Below is provided source code with key lines for this example highlighted:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
?
/*****************************************************
This program was produced by the
CodeWizardAVR V2.04.4a Advanced
Automatic Program Generator
Copyright 1998-2009 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date
: 12/26/2011
Author :
Company :
Comments:
Chip type
: ATmega8535
Program type
: Application
AVR Core Clock frequency: 8.000000 MHz
Memory model
: Small
External RAM size
: 0
Data Stack size
: 128
*****************************************************/
#include <mega8535.h>
#include <delay.h>
// Standard Input/Output functions
#include <stdio.h>
#define KBD_DATA PIND.3
// External Interrupt 0 service routine
unsigned char data,bitcount=11;
// holds the received scan code
// keyboard scan codes (without & with shift key pressed)
flash unsigned char unshifted[67][2] = {
//0x0d,9,
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,'=',0x5a,13,
0x5b,']',0x5d,'/',0x61,'<',0x66,8, 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 };
flash unsigned char shifted[67][2] = {
//0x0d,9,
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,'+',0x5a,13,
0x5b,'}',0x5d,'|',0x61,'>',0x66,8, 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 };
//***********************************************
// decode scan code
void decode(unsigned char sc) {
static unsigned char is_up=0, shift = 0, mode = 0;
unsigned char i;
if (!is_up) {
switch (sc) {
case 0xF0 :// The up-key identifier
is_up = 1;
break;
case 0x12 :// Left SHIFT
shift = 1;
break;
case 0x59 :// Right SHIFT
shift = 1;
break;
case 0x05 :// F1
if(mode == 0)
mode = 1;// Enter scan code mode
if(mode == 2)
mode = 3;// Leave scan code mode
break;
default:
if(mode == 0 || mode == 3) {// If ASCII mode
if(!shift) {// If shift not pressed, do a table look-up
for(i = 0; unshifted[i][0]!=sc && unshifted[i][0]; i++);
if (unshifted[i][0] == sc) {
putchar(unshifted[i][1]);
}
}
else {// If shift pressed
for(i = 0; shifted[i][0]!=sc && shifted[i][0]; i++);
if (shifted[i][0] == sc) {
putchar(shifted[i][1]);
}
28/05/2015 18:02