Title: Chapter 12 Capturing Input
1Chapter 12 Capturing Input
2Button Inputs
3Inputs Packing
int readK( void) // returns 0..F if keys
pressed, 0 none int c 0 if (
!_RD6) // leftmost button c 8 if
( !_RD7) c 4 if ( !_RA7)
c 2 if ( !_RD13) // rightmost button
c 1 return c // readK
4De-Bouncing
int getK( void) // wait for a key pressed and
debounce int i0, r0, j0 int c
// 1. wait for a key pressed for at least .1sec
do Delayms( 10) if ( (c
readKEY())) if ( cgtr)
// if more than one button r c
// take the new code i
else i0 while
( ilt10)
// 2. wait for key released for at least .1 sec
i 0 do Delayms( 10)
if ( (c readKEY())) if
(cgtr) // if more then one button r
c // take the new code i0
j // keep
counting else
i while ( ilt10) // 3.
check if a button was pushed longer than 500ms
if ( jgt50) r0x80
// add a flag in bit 7 // 4. return
code return r // getK
5Rotary Encoders
6Polling Example
/ Rotary.c / // configuration bit settings,
Fcy72MHz, Fpb36MHz pragma config POSCMODXT,
FNOSCPRIPLL pragma config FPLLIDIVDIV_2,
FPLLMULMUL_18, FPLLODIVDIV_1 pragma config
FPBDIVDIV_2, FWDTENOFF, CPOFF,
BWPOFF include ltp32xxxx.hgt include
ltexplore.hgt include ltLCD.hgt define ENCHA
_RA9 // channel A define ENCHB _RA10
// channel B main( void) int i 0
char s16 initLCD() // main
loop while( 1) while( ENCHA)
// detect CHA falling edge Delayms( 5)
// debounce i ENCHB ? 1 -1
while( !ENCHA) // wait for CHA rising
edge Delayms( 5) // debounce
// display relative counter value
clrLCD() sprintf( s, "d", i)
putsLCD( s) // main loop
// main
7Interrupt Driven
Rotary Encoder State Machine Diagram
Rotary Encoder State Machine Transitions Table
8Interrupt Driven Example
/ Rotary2.c / // configuration bit settings,
Fcy72MHz, Fpb36MHz pragma config POSCMODXT,
FNOSCPRIPLL pragma config FPLLIDIVDIV_2,
FPLLMULMUL_18, FPLLODIVDIV_1 pragma config
FPBDIVDIV_2, FWDTENOFF, CPOFF,
BWPOFF include ltp32xxxx.hgt include
ltplib.hgt include ltexplore.hgt include
ltLCD.hgt define ENCHA _RA9 // encoder
channel A define ENCHB _RA10 // encoder
channel B define TPMS (FPB/1000) // PB clock
ticks per ms // state machine
definitions define R_IDLE 0 define
R_DETECT 1 volatile int RCount char
RState void initR( void) // init state
machine RCount 0 // init
counter RState 0 // init
state machine // init Timer2 T2CON
0x8020 // enable Timer2, Fpb/4 PR2
5TPMS/4 // 5ms period
mT2SetIntPriority( 1)
mT2ClearIntFlag() mT2IntEnable( 1)
// init R
9Interrupt Service Routine
void __ISR( _TIMER_2_VECTOR, ipl1) T2Interrupt(
void) static char d switch (
RState) default case R_IDLE
// waiting for CHA rise if ( !
ENCHA) RState
R_DETECT if ( ! ENCHB)
d -1 else
d 1 break
case R_DETECT // waitin for CHA fall
if ( ENCHA)
RState R_IDLE RCount d
break // switch
mT2ClearIntFlag() // T2 Interrupt
10Example (cont.)
main( void) int i 0 char s16
initEX16() // init and enable
interrupts initLCD() // init
LCD module initR() // init
Rotary Encoder // main loop while( 1)
Delayms( 100) // place holder
for a complex app. clrLCD()
sprintf( s, "RCount d", RCount)
putsLCD( s) // main loop
// main
11Keyboards
Physical Interface (5-pin DIN)
Physical Interface (6-pin mini-DIN)
12PS2 Communication Protocol
Host Communication Waveform
13Input Capture Modules
Figure 15-1 (DS61143)
14PS/2 Bit Timing
15IC State Machine
16IC ISR
void __ISR( _INPUT_CAPTURE_1_VECTOR, ipl1)
IC1Interrupt( void) // input capture interrupt
service routine int d // 1. reset
timer on every edge TMR2 0 switch(
PS2State) default case PS2START
if ( ! PS2DAT) // verify start bit
KCount 8 // init
bit counter KParity 0 //
init parity check PR2 TMAX
// init timer period T2CON 0x8000
// enable TMR2, 11 PS2State
PS2BIT break case
PS2BIT KBDBuf gtgt1 // shift
in data bit if ( PS2DAT)
KBDBuf 0x80 KParity KBDBuf
// update parity if ( --KCount 0)
// if all bit read, move on PS2State
PS2PARITY break case
PS2PARITY if ( PS2DAT) //
verify parity bit KParity 0x80
if ( KParity 0x80) // if parity odd,
continue PS2State PS2STOP
else PS2State PS2START
break
case PS2STOP if ( PS2DAT)
// verify stop bit KBDCode
KBDBuf // save code in mail box
KBDReady 1 // set flag, code available
T2CON 0 // stop the timer
PS2State PS2START
break // switch state machine //
clear interrupt flag d IC1BUF
// discard capture mIC1ClearIntFlag()
// IC1 Interrupt
17Using Stimulus Files
18Test Program
/ PS2ICTest.c / // configuration bit
settings, Fcy72MHz, Fpb36MHz pragma config
POSCMODXT, FNOSCPRIPLL pragma config
FPLLIDIVDIV_2, FPLLMULMUL_18,
FPLLODIVDIV_1 pragma config FPBDIVDIV_2,
FWDTENOFF, CPOFF, BWPOFF include
ltp32xxxx.hgt include ltexplore.hgt include
"PS2IC.h" main() int Key initEX16()
// init and enable interrupts
initKBD() // initialization
routine while ( 1) if (
KBDReady) // wait for the flag
Key KBDCode // fetch the
key code KBDReady 0 //
clear the flag // main loop
//main
19Simulator Profiler
20Change Notification Module
21Using CN to Capture Keyboard Inputs
22CN - ISR
void __ISR( _CHANGE_NOTICE_VECTOR, ipl1)
CNInterrupt( void) // change notification
interrupt service routine // 1. make sure
it was a falling edge if ( PS2CLK 0)
switch( PS2State) default
case PS2START // verify start
bit if ( ! PS2DAT)
KCount 8 // init bit
counter KParity 0 //
init parity check PS2State
PS2BIT break
case PS2BIT KBDBuf gtgt1
// shift in data bit if (
PS2DAT) KBDBuf 0x80
KParity KBDBuf // update parity
if ( --KCount 0) // if all bit read,
move on PS2State PS2PARITY
break case PS2PARITY
if ( PS2DAT) // verify parity
KParity 0x80 if (
KParity 0x80) // if parity odd, continue
PS2State PS2STOP else
PS2State PS2START
break
case PS2STOP if ( PS2DAT)
// verify stop bit
KBDCode KBDBuf // save code in mail
box KBDReady 1 // set
flag, code available
PS2State PS2START break
// switch state machine // if falling
edge // clear interrupt flag
mCNClearIntFlag() // CN Interrupt
23I/O Polling (Timer based)
24I/O Polling State Machine
25I/O Polling - ISR
void __ISR( _TIMER_4_VECTOR, ipl1) T4Interrupt(
void) int d, k // sample the
inputs clock and data at the same time d
PS2DAT k PS2CLK // keyboard
state machine if ( KState) //
previous time clock was high KState 1 if
( !k) // PS2CLK 0
// falling edge detected,
KState 0 // transition to
State0 ltltltlt insert data state machine here
gtgtgtgt // falling edge else
// clock still high, remain in State1
// clock still high // state 1
else // state 0 if ( k)
// PS2CLK 1 // rising
edge, transition to State1 KState
1 // rising edge else
// clocl still low, remain in State0
// clock still low // state 0 //
clear the interrupt flag mT4ClearIntFlag()
// T4 Interrupt
26I/O Polling w/Timeout
27I/O Polling w/Timeout - ISR
void __ISR( _TIMER_4_VECTOR, ipl1) T4Interrupt(
void) int d, k // sample the inputs
clock and data at the same time d PS2DAT
k PS2CLK // keyboard state machine
if ( KState) // previous time clock
was high KState 1 if ( !k)
// PS2CLK 0 // falling
edge detected, KState 0
// transition to State0 KTimer
KMAX // restart the counter
ltltltlt insert data state machine here gtgtgtgt
// falling edge else
// clock still high, remain in State1
KTimer-- if ( KTimer 0) //
Timeout PS2State PS2START
// Reset data SM // clock still high
// Kstate 1
else // Kstate 0 if ( k)
// PS2CLK 1 // rising
edge, transition to State1 KState
1 // rising edge else
// clocl still low, remain in State0
KTimer-- if ( KTimer 0)
// Timeout PS2State PS2START
// Reset data SM // clock still low
// Kstate 0 // clear the interrupt
flag mT4ClearIntFlag() // T4 Interrupt
28Switch
switch( PS2State)
default case PS2START
if ( !d) // PS2DAT 0
KCount 8
// init bit counter
KParity 0 // init parity check
PS2State PS2BIT
break case PS2BIT
KBDBuf gtgt1 //
shift in data bit if ( d)
// PS2DAT 1 KBDBuf
0x80 KParity KBDBuf
// calculate parity if ( --KCount
0) // all bit read
PS2State PS2PARITY break
case PS2PARITY
if ( d) // PS2DAT 1
KParity 0x80 if (
KParity 0x80) // parity odd, continue
PS2State PS2STOP
else PS2State PS2START
break case
PS2STOP if ( d)
// PS2DAT 1
KBDCode KBDBuf // write in the
buffer KBDReady 1
PS2State PS2START
break // switch
29InitKBD
void initKBD( void) // init I/Os
ODCGbits.ODCG13 1 // make RG13 open drain
(PS2clk) _TRISG13 1 // make RG13
an input pin (for now) _TRISG12 1
// make RG12 an input pin // clear the kbd
flag KBDReady 0 // configure Timer4
PR4 25TPS - 1 // 25 us T4CON
0x8000 // T4 on, prescaler 11
mT4SetIntPriority( 1) // lower priority
mT4ClearIntFlag() // clear interrupt flag
mT4IntEnable( 1) // enable interrupt
// init KBD
30Efficiency Evaluation
void __ISR(..) T4Interrupt( void) _RA2
1 // flag up, inside the ISR ltltlt
Interrupt service routine here gtgt _RA2
0 // flag down, back to the main
31Keyboard Buffering
A Circular Buffer
// circular buffer unsigned char KCB
KB_SIZE // head and tail or write and read
pointers volatile int KBR, KBW
32Using the Circular Buffer
Insertion case PS2STOP if (
PS2IN DATMASK) // verify stop bit
KCB KBW KBDBuf //
write in the buffer // check if
buffer full if ( (KBW1)KB_SIZE
! KBR) KBW
// else increment ptr KBW
KB_SIZE // wrap around
PS2State PS2START
break
Extraction int getKeyCode( char c) if (
KBR KBW) // buffer empty
return FALSE // else buffer contains at
least one key code c KCB KBR
// extract the first key code KBR KB_SIZE
// wrap around the pointer
return TRUE // getKeyCode
33KeyCodes Decoding
// PS2 keyboard codes (standard set 2) const
char keyCodes128 0, F9,
0, F5, F3, F1, F2, F12, //00
0, F10, F8, F6, F4, TAB, '', 0, //08
0, 0,L_SHFT, 0,L_CTRL,'q','1',
0, //10 0, 0, 'z', 's', 'a',
'w', '2', 0, //18 0, 'c',
'x', 'd', 'e', '4', '3', 0, //20
0, ' ', 'v', 'f', 't', 'r', '5', 0, //28
0, 'n', 'b', 'h', 'g', 'y', '6',
0, //30 0, 0, 'm', 'j', 'u',
'7', '8', 0, //38 0, ',',
'k', 'i', 'o', '0', '9', 0, //40
0, '.', '/', 'l', '', 'p', '-', 0, //48
0, 0,'\'', 0, '', '', 0,
0, //50 CAPS, R_SHFT,ENTER, '',
0,0x5c, 0, 0, //58 0, 0,
0, 0, 0, 0, BKSP, 0, //60
0, '1', 0, '4', '7', 0, 0, 0, //68
0, '.', '2', '5', '6', '8', ESC,
NUM, //70 F11, '', '3', '-',
'', '9', 0, 0 //78 const
char keySCodes128 0, F9,
0, F5, F3, F1, F2, F12, //00
0, F10, F8, F6, F4, TAB, '', 0, //08
0, 0,L_SHFT, 0,L_CTRL,'Q','!', 0,
//10 0, 0, 'Z', 'S', 'A',
'W', '_at_', 0, //18 0, 'C',
'X', 'D', 'E', '', '', 0, //20
0, ' ', 'V', 'F', 'T', 'R', '', 0, //28
0, 'N', 'B', 'H', 'G', 'Y', '',
0, //30 0, 0, 'M', 'J', 'U',
'', '', 0, //38 0, 'lt',
'K', 'I', 'O', ')', '(', 0, //40
0, 'gt', '?', 'L', '', 'P', '_', 0, //48
0, 0,'\"', 0, '', '', 0,
0, //50 CAPS, R_SHFT,ENTER, '', 0,
'', 0, 0, //58 0, 0,
0, 0, 0, 0, BKSP, 0, //60
0, '1', 0, '4', '7', 0, 0, 0, //68
0, '.', '2', '5', '6', '8', ESC, NUM,
//70 F11, '', '3', '-', '',
'9', 0, 0 //78
34getc()
char getC( void) unsigned char c
while( 1) while( !KBDReady)
// wait for a key pressed // check if it
is a break code while (KBDCode 0xf0)
// consume the break code
KBDReady 0 // wait for a new
key code while ( !KBDReady)
// check if the shift button is released
if ( KBDCode L_SHFT)
CapsFlag 0 // and discard it
KBDReady 0 // wait
for the next key while (
!KBDReady) // check for
special keys if ( KBDCode L_SHFT)
CapsFlag 1
KBDReady 0 else if ( KBDCode
CAPS) CapsFlag
!CapsFlag KBDReady 0
else // translate into an ASCII code
if ( CapsFlag)
c keySCodesKBDCode128
else c keyCodesKBDCode128
break // consume
the current character KBDReady 0
return ( c) // getC