Chapter 12 Capturing Input Change Notification Module Di Jasio - Programming 32-bit Microcontrollers in C Using CN to Capture Keyboard Inputs Di Jasio - Programming 32-bit Microcontrollers in C CN - 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 >>=1; // 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) KParity ^= if ( KParity & PS2State = else PS2State = break; // verify parity 0x80; 0x80) // if parity odd, continue PS2STOP; PS2START; Di Jasio - Programming 32-bit Microcontrollers in C case PS2STOP: if ( PS2DAT) { KBDCode = KBDBuf; KBDReady = 1; } PS2State = PS2START; break; } // switch state machine } // if falling edge // clear interrupt flag mCNClearIntFlag(); } // CN Interrupt // verify stop bit // save code in mail box // set flag, code availab I/O Polling (Timer based) Di Jasio - Programming 32-bit Microcontrollers in C I/O Polling State Machine Di Jasio - Programming 32-bit Microcontrollers in C I/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 <<<< insert data state machine here >>>> } // 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 Di Jasio - Programming 32-bit Microcontrollers in C I/O Polling w/Timeout Di Jasio - Programming 32-bit Microcontrollers in C I/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 if ( !k) { // falling edge detected, KState = 0; KTimer = KMAX; KState 1 // PS2CLK == 0 // transition to State0 // restart the counter <<<< insert data state machine here >>>> } // 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 Di Jasio - Programming 32-bit Microcontrollers in C Switch switch( PS2State){ default: case PS2START: if ( !d) { KCount = 8; KParity = 0; PS2State = PS2BIT; } break; // PS2DAT == 0 // init bit counter // init parity check case PS2BIT: KBDBuf >>=1; // if ( d) // KBDBuf += 0x80; KParity ^= KBDBuf; // if ( --KCount == 0) // PS2State = PS2PARITY; break; case PS2PARITY: if ( d) KParity ^= if ( KParity & PS2State = else PS2State = break; Di Jasio - Programming 32-bit Microcontrollers in C calculate parity all bit read // PS2DAT == 1 0x80; 0x80) // parity odd, continue PS2STOP; PS2START; case PS2STOP: if ( d) { KBDCode = KBDBuf; KBDReady = 1; } PS2State = PS2START; break; } // switch shift in data bit PS2DAT == 1 // PS2DAT == 1 // write in the buffer InitKBD void initKBD( void) { // init I/Os ODCGbits.ODCG13 = 1; _TRISG13 = 1; _TRISG12 = 1; // make RG13 open drain (PS2clk) // make RG13 an input pin (for now) // make RG12 an input pin // clear the kbd flag KBDReady = 0; // configure Timer4 PR4 = 25*TPS - 1; T4CON = 0x8000; mT4SetIntPriority( 1); mT4ClearIntFlag(); mT4IntEnable( 1); } // init KBD Di Jasio - Programming 32-bit Microcontrollers in C // // // // // 25 us T4 on, prescaler 1:1 lower priority clear interrupt flag enable interrupt Efficiency Evaluation void __ISR(..) T4Interrupt( void) { _RA2 = 1; // flag up, inside the ISR <<< Interrupt service routine here >> _RA2 = 0; } Di Jasio - Programming 32-bit Microcontrollers in C // flag down, back to the main Keyboard Buffering A Circular Buffer // circular buffer unsigned char KCB[ KB_SIZE]; // head and tail or write and read pointers volatile int KBR, KBW; Di Jasio - Programming 32-bit Microcontrollers in C Using the Circular Buffer Insertion: case PS2STOP: if ( PS2IN & DATMASK) { KCB[ KBW] = KBDBuf; // check if buffer full if ( (KBW+1)%KB_SIZE != KBW++; KBW %= KB_SIZE; } PS2State = PS2START; break; // verify stop bit // write in the buffer KBR) // else increment ptr // wrap around Extraction: int getKeyCode( char *c) { if ( KBR == KBW) return FALSE; // buffer empty // 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 Di Jasio - Programming 32-bit Microcontrollers in C KeyCodes Decoding // PS2 keyboard codes (standard set #2) const char keyCodes[128]={ 0, F9, 0, F5, F3, F1, F2, F12, 0, F10, F8, F6, F4, TAB, '`', 0, 0, 0,L_SHFT, 0,L_CTRL,'q','1', 0, 0, 0, 'z', 's', 'a', 'w', '2', 0, 0, 'c', 'x', 'd', 'e', '4', '3', 0, 0, ' ', 'v', 'f', 't', 'r', '5', 0, 0, 'n', 'b', 'h', 'g', 'y', '6', 0, 0, 0, 'm', 'j', 'u', '7', '8', 0, 0, ',', 'k', 'i', 'o', '0', '9', 0, 0, '.', '/', 'l', ';', 'p', '-', 0, 0, 0,'\'', 0, '[', '=', 0, 0, CAPS, R_SHFT,ENTER, ']', 0,0x5c, 0, 0, 0, 0, 0, 0, 0, 0, BKSP, 0, 0, '1', 0, '4', '7', 0, 0, 0, 0, '.', '2', '5', '6', '8', ESC, NUM, F11, '+', '3', '-', '*', '9', 0, 0 }; const char keySCodes[128] = { 0, F9, 0, F5, F3, F1, F2, F12, 0, F10, F8, F6, F4, TAB, '~', 0, 0, 0,L_SHFT, 0,L_CTRL,'Q','!', 0, 0, 0, 'Z', 'S', 'A', 'W', '@', 0, 0, 'C', 'X', 'D', 'E', '$', '#', 0, 0, ' ', 'V', 'F', 'T', 'R', '%', 0, 0, 'N', 'B', 'H', 'G', 'Y', '^', 0, 0, 0, 'M', 'J', 'U', '&', '*', 0, 0, '<', 'K', 'I', 'O', ')', '(', 0, 0, '>', '?', 'L', ':', 'P', '_', 0, 0, 0,'\"', 0, '{', '+', 0, 0, CAPS, R_SHFT,ENTER, '}', 0, '|', 0, 0, 0, 0, 0, 0, 0, 0, BKSP, 0, 0, '1', 0, '4', '7', 0, 0, 0, 0, '.', '2', '5', '6', '8', ESC, NUM, F11, '+', '3', '-', '*', '9', 0, 0 }; Di Jasio - Programming 32-bit Microcontrollers in C //00 //08 //10 //18 //20 //28 //30 //38 //40 //48 //50 //58 //60 //68 //70 //78 //00 //08 //10 //18 //20 //28 //30 //38 //40 //48 //50 //58 //60 //68 //70 //78 getc() 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; } Di Jasio - Programming 32-bit Microcontrollers in C else // translate into an ASCII code { if ( CapsFlag) c = keySCodes[KBDCode%128]; else c = keyCodes[KBDCode%128]; break; } } // consume the current character KBDReady = 0; return ( c); } // getC