You are on page 1of 5

IAR Application Note #8611-003

IAR Application Note #6811-003

Implementing a State Machine


by Stefan Nyman [mailto:Stefan.Nyman@micronym.se]

SUMMARY

By describing a problem in terms of states, tests and tasks you can easily solve it in a straightforward switch statement.

KEYWORDS

State machine, switch

State Machine for Keyboard Scanning


This example shows how to use a state machine in the program. In most programs, important parts can be regarded as state machines. As an illustration, a 2-key rollover keyboard scanner is implemented. The benefit of using a state machine is that the behavior of the program can easily be described in a graph. The graph is then implemented in a table.

No Yes

State 0
AnyKey? No

ScanKey

State 1
SameKey? Yes

ClearKey No

FindKey

SameKey? Yes

State 3

No

SameKey?

State 2

Yes

The graph above shows one way to accomplish a very secure detection of keys on a cheap keyboard matrix - or anything that needs filtering. By describing the filtering in the state graph, we can create a good method of reading the keys. The machine starts in State 0.
1

IAR Application Note #8611-003

State 0: When a key is detected, the corresponding code (read from a port) is remembered, and the machine switches to state 1. State 1: If the same code is detected, it is approved, a flag is set and the key value is passed to other programs (via a mailbox). State 2: As long as the same code is detected, nothing is done. If the code changes, the state shifts to see if the change is occasional. State 3: If the change was occasional, the machine returns to state 2; otherwise it restarts to look for another keycode. The graph can easily be converted to a switch statement:
void Scan_Keyboard(void) { switch (KeyState) { case 0: { if (AnyKey()) { ScanKey(); KeyState = 1; } } case 1: { if (SameKey()) { FindKey(); KeyState = 2; } else KeyState = 0; } case 2: { if (SameKey()) { } else KeyState = 3; } case 3: { if (SameKey()) { KeyState = 2; } else { ClearKey(); KeyState = 0; } } } }

The keyboard is connected as shown below. By setting one bit to 1 in PORTB, you can detect the key pressed.

IAR Application Note #8611-003

PORTA
2 1 0 6

PORTB
5 4 3

10 k 10 k 10 k

With this state machine and the task routines, we are going to build a versatile program component which will behave like a 74HC922. Variables:
// State: char KeyState; // Bit pattern after each scan: char KeyCode; // Output value from the virtual 74HC922: char KeyValue; // KeyDown is set if key is down: char KeyDown; // KeyNew is set every time a new key is down: char KeyNew;

Test Functions:
// AnyKey is true if any key is down char AnyKey(void) { PORTB |= 0x78; return (PORTA & 0x07); } // SameKey is true if same key is still down char SameKey(void) { PORTB = ((PORTB & 0x87) | ( KeyCode & 0x78)); return ((KeyCode & PORTA) & 0x07); }

IAR Application Note #8611-003

Tasks:
// ScanKey generates a bit pattern in KeyCode void ScanKey(void) { PORTB = (PORTB & 0x87) | 0x08; while (PORTB & 0X78) { if (PORTA & 0x07) { KeyCode = ((PORTA & 0x07) | (PORTB & 0x78)); } PORTB = (PORTB & 0x87) | (((PORTB & 0x78)<<1) & 0x78); } } const char KeyTable[][2] = { { { { { { { { { { { { { 0x09, 0x0A, 0x0C, 0x11, 0x12, 0x14, 0x21, 0x22, 0x24, 0x41, 0x42, 0x44, '6'}, '4'}, '5'}, '9'}, '7'}, '8'}, '#'}, '*'}, '0'}, '3'}, '1'}, '2'}} ;

// FindKey compares KeyCode to values in KeyTable. // If match, KeyValue, KeyDown and KeyNew are updated. void FindKey(void) { char index; for (index = 0; index < 12; index++) { if (KeyTable [index][0] == KeyCode) { KeyValue = (KeyTable [index][1]); KeyDown = 1; KeyNew = 1; break; } } } void ClearKey(void) { KeyDown = 0; }

The state machine is called about every 4 ms. That is an appropriate time between keyscans.
interrupt void RTI_interrupt(void) { TFLG2 = 0x40; Scan_Keyboard(); // State machine }

A small main loop for testing:


main(void) { TMSK2 = 0x40;

// Start RTI-interrupt every 4 ms

IAR Application Note #8611-003

enable_interrupt(); while(1) { if (KeyNew)KeyNew = 0; } }

Conclusions
Every application that acts different depending of what has happened previously, can be implemented as a state machine. This method can be used in a general way to solve more complex problems. It is of course possible to have several independent state variables.

CONTACT INFORMATION
USA IAR Systems Inc. One Maritime Plaza San Francisco, CA 94111 Tel: +1 415-765-5500 Fax: +1 415-765-5503 Email: info@iar.com SWEDEN IAR Systems AB P.O. Box 23051 S-750 23 Uppsala Tel: +46 18 16 78 00 Fax: +46 18 16 78 38 Email: info@iar.se GERMANY IAR Systems AG Posthalterring 5 D-855 99 Parsdorf Tel: +49 89 90 06 90 80 Fax: +49 89 90 06 90 81 Email: info@iar.de UK IAR Systems Ltd. 9 Spice Court, Ivory Square London SW11 3UE Tel: +44 171 924 3334 Fax: +44 171 924 5341 Email: info@iarsys.co.uk DENMARK IAR Systems A/S Elkjervej 30-32 DK-8230 Aabyhoj Tel: +45 86 25 11 11 Fax: +45 86 25 11 91 Email: info@iar.dk

www.iar.com
Copyright 2000 IAR Systems
IAR and C-SPY are registered trademarks of IAR Systems. IAR Embedded Workbench is a trademark of IAR Systems. Windows is a trademark of Microsoft Corporation. All other products are registered trademarks or trademarks of their respective owners. Product features, availability, pricing and other terms and conditions are subject to change by IAR Systems without prior notice.

You might also like