Nested switch statements

The simple state machine shown in the state machine introduction can be implemented for the AVR microcontrollers using the following nested switch statement


switch (state)
{
case DEFAULT:
{
if (ShiftPress())
{
state=SHIFTED; //Update state
ShiftAction(); //Transition Action
}
DefaultActivity();
}
break;
case SHIFTED:
{
if (ShiftPress())
{
state=DEFAULT; //Update state
DefaultAction(); //Transition Action
}
ShiftActivity();
}
break;
}

The switch statement is used to select the current case. The if statement within each case then tests for the possible events. In this case there is only one event ShiftPress() which returns true if the shift key has been pressed. If the event occurs then the Action function associated with the transition is called and then the current state is updated. Finally the Activity function is called.

Each the Action and Activity functions are then implemented as individual functions as shown below.

void ShiftAction(void)
{
 LCDPutStr("Shifted state", 110, 15, LARGE, WHITE, BLUE);
}

void DefaultAction(void)
{
 LCDPutStr("Default state", 110, 15, LARGE, WHITE, BLUE);
}

void ShiftActivity(void)
{
 char ind=0;
 if (StrRxFlag)
 {
 while ( buffer[ind] != 0x00)
 {
 buffer[ind]=buffer[ind]-0x20;
 ind++;
 }
 LCDPutStr(buffer,80,5,SMALL,WHITE,BLUE); //Write to LCD Display
 StrRxFlag=0; // Reset String received flag
 }
}

void DefaultActivity(void)
{
 if (StrRxFlag)
 {
 LCDPutStr(buffer,80,5,SMALL,WHITE,BLUE); //Write to LCD Display
 StrRxFlag=0; // Reset String received flag
 }
}

Figure 1 FSM for implementing the button press and released functionality

In this example the event that the state machine responds to is a button that is pressed and released. The code for polling this condition is given below. It makes use of a two state FSM shown in Figure 1. This code uses software debouncing to ensure that the button press and release is correctly captured.

char ShiftPress(void)
{ //Returns true when a button is pressed and then released. Includes software debounce
 static char press=RELEASED; // State variable (PRESSED | RELEASED)

switch (press)
 {
 case RELEASED:
 {
 if (debounce((PINS1 & (1< return 0;
 }
 break;
 case PRESSED:
 {
 if (debounce(!(PINS1 & (1<The software debounce is implemented as follows
 char debounce(char pressed) {  static char count=0; // Incremented each time the button is in the desired state  if (pressed) count=0; //Reset count if switch is released  else count++; //Increment count if switch is pressed  _delay_us(100);  if (count > 10)
 {
 count=0;
 return 1;
 }
 else return 0;
}

The complete code is here. Note that this code assumes that the Color_LCD_driver and the USART modules are in a folder named Utilities which is in the same folder as the StickyShift project. You will also need to link the .c and .h file to the project.


/*
* StickyShift.c
* Implements Caps lock style behavior
* Button S1 on the Sparkfun Color LCD shield acts as the caps lock key
* Lower case strings sent over the USB link from a terminal are then
* displayed on the LCD screen in the selected case. Note the string must
* be terminated with a carriage return (Select +CR in the terminal program)
* Created: 16/12/2011 07:48:59
* Author: Benn Thomsen
*/

#define F_CPU 16000000UL /* 16 MHz Crystal Oscillator */
#define BAUDRATE 9600
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "....UtilitiesColor_LCD_driver.h"
#include "....UtilitiesUSART.h"

// Function Prototypes
char ShiftPress(void);
void DefaultActivity(void);
void ShiftActivity(void);
void DefaultAction(void);
void ShiftAction(void);
char debounce(char pressed);

#define DEFAULT 0
#define SHIFTED 1
#define RELEASED 0
#define PRESSED 1

// Note the use of the volatile keyword to ensure that the memory for these variables is reserved
volatile int i=0;
volatile char buffer[20];
volatile char StrRxFlag=0;
int main(void)
{
LCDInit(); //Initialize the LCD
LCDClear(BLUE);
USART_interrupt_init();

char state = DEFAULT;
while(1)
{
switch (state)
{
case DEFAULT:
{
if (ShiftPress())
{
state=SHIFTED; //Update state
ShiftAction(); //Transition Action
}
DefaultActivity();
}
break;
case SHIFTED:
{
if (ShiftPress())
{
state=DEFAULT; //Update state
DefaultAction(); //Transition Action
}
ShiftActivity();
}
break;
}
}
}

void ShiftAction(void)
{
LCDPutStr("Shifted state", 110, 15, LARGE, WHITE, BLUE);
}

void DefaultAction(void)
{
LCDPutStr("Default state", 110, 15, LARGE, WHITE, BLUE);
}

void ShiftActivity(void)
{
char ind=0;
if (StrRxFlag)
{
while ( buffer[ind] != 0x00)
{
buffer[ind]=buffer[ind]-0x20;
ind++;
}
LCDPutStr(buffer,80,5,SMALL,WHITE,BLUE); //Write to LCD Display
StrRxFlag=0; // Reset String received flag
}
}

void DefaultActivity(void)
{
if (StrRxFlag)
{
LCDPutStr(buffer,80,5,SMALL,WHITE,BLUE); //Write to LCD Display
StrRxFlag=0; // Reset String received flag
}
}

char ShiftPress(void)
{ //Returns true when a button is pressed and then released. Includes software debounce
static char press=RELEASED; // State variable (PRESSED | RELEASED)

switch (press)
{
case RELEASED:
{
if (debounce((PINS1 & (1<<S1)))) press=PRESSED; //Update state
return 0;
}
break;
case PRESSED:
{
if (debounce(!(PINS1 & (1<<S1))))
{
press=RELEASED; //Update state
return 1; // Return true (Button pressed and released)
}
else return 0;
}
break;
}
}

char debounce(char pressed)
{
static char count=0; // Incremented each time the button is in the desired state

if (pressed) count=0; //Reset count if switch is released
else count++; //Increment count if switch is pressed
_delay_us(100);
if (count > 10)
{
count=0;
return 1;
}
else return 0;
}

ISR(USART0_RX_vect)
{
buffer[i]=UDR0; //Read USART data register
if(buffer[i++]=='r') //check for carriage return terminator and increment buffer index
{
// if terminator detected
StrRxFlag=1; //Set String received flag
buffer[i-1]=0x00; //Set string terminator to 0x00
i=0; //Reset buffer index
}
}

Next: State transition table implementation

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s