IAR Application Note #8611-003
IAR Application Note #6811-003
Implementing a State Machine by Stefan Nyman [mailto:
[email protected]]
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 FindKey
ClearKey No
No
State 3
SameKey?
State 2
Yes
SameKey?
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.
2
IAR Application Note #8611-003
PORTA 2
PORTB 1
0
6
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); }
3
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)