Hi,
I am having a few teething issues with my first state machine implementation, and suspect it's due to me not being 100% aufait with C programming so after some advice.
I will give a brief description of the code and problem I am seeing, and suspect the issue lies within int CheckButtons() function.
Basically I have 2 buttons assigned so far, one button I have made some analogue circuitry with suitable debouce, and the other button is just using the S2 on the launchpad. My button is active high and the S2 is active low, which I admit could have been better implemented to be the same, but my code takes this into account.
#define OnOff_B BIT3 // S2 button which when depressed gives a 0 on the port
#define Select_B BIT2 // My button which when depressed gives a 1 on the port
When I press the OnOff_B button the LCD changes and toggles between displaying "SYSTEM OFF" and "SYSTEM ON PRESS SELECT" all good as what I wanted and expected.
However, when in the "SYSTEM OFF" state and pressing the Select_B button several times, the states and LCD display the following sequence "SYSTEM ON PRESS SELECT" then "BRIGHTNESS" ADJ" then "PRESET MODES" and then it toggles between "BRIGHTNESS" ADJ" and "PRESET MODES" as it should.
So the problem is the Select_B button should not allow the jump from "SYSTEM OFF" ?
The Select_B button also jumps from "SYSTEM ON PRESS SELECT" to the "SYSTEM OFF" state and then begins the sequence above, the same issue but thought it best to describe all the symptoms.
The code is below and have tried to break this down into as smaller block as possible, as well as adding manual indents (is there a way to copy and paste adding the indents?). I have highlighted the function int CheckButtons() as believe this is the issue, but it could also be related to my IF statement in the while loop in main. I am exploring a way to check the buttons using switch case, having the switch as variable and assign the value of P1IN to that variable, but it's not working either.
#include "ExtFunc/itoa.h" // "" means local include <> external
#include "ExtFunc/lcd.h" // "" means local include <> external
#include "msp430g2231.h"
#define OnOff_B BIT3 // Button defined to input pin
#define Select_B BIT2 // Button defined to input pin
//#define Increase_B BIT2 // Button defined to input pin
//#define Decrease_B BIT4 // Button defined to input pin
volatile int sysTick = 0;
// State definitions
enum states { OFFSTATE, ONSTATE, BRIGHTNESS, PRESETS, TRANSITION, MAXSTATES };
// Event definitions
enum events { OFF, ON, LIGHTLEVEL, MODE, MAXEVENTS };
int Current_State = OFFSTATE; // Default state the system starts in
//void OnEnter( int State);
//void OnExit( int State);
// Interrupt and timer to achieve desired sysTick speed
int counter()
{
TA0CCR0 = 60000; // Count limit 125kHz / 62500 = 2, therefore interrupt triggers every 500mS
TA0CCTL0 = CCIE; // Enable counter interrupts
TA0CTL = TASSEL_2 + MC_1 + ID_3; // Timer A 0 with SMCLK at 1MHZ / 8 = 125kHz, count UP
_BIS_SR( GIE ); // interrupts enabled
}
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer0_A0 (void) // Timer0 A0 interrupt service routine
{
sysTick = 1;
}
// end code for sysTick setup
void StateM(int event); // Contains states OFFSTATE, ONSTATE, BRIGHTNESS, PRESETS, MAXSTATES
int CheckButtons(); // Monitors the buttons connected to the LaunchPad
/* ********** Start Main ********** */
int main()
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
BCSCTL1 = CALBC1_1MHZ; // Set range
DCOCTL = CALDCO_1MHZ; // Set DCO step and modulation
InitializeLcm();
ClearLcmScreen();
// These function calls simulate events passed to the SM
while ( Current_State != MAXSTATES ) // continue while TS_state is (NOT =) to MAXSTATES
{
counter(); // Timer_A determines the time for the sysTick
if (sysTick == 1)
{
if (~P1IN & OnOff_B || P1IN & Select_B)
{
StateM( CheckButtons() ); // Contains button event assignment, waits for button press to coincide with sysTick
sysTick = 0;
}
}
}
return 0;
}
/* ********** End Main ********** */
int CheckButtons() // Buttons trigger the following events OFF, ON, LIGHTLEVEL, MODE, MAXEVENTS
{
if(~P1IN & OnOff_B) // Changes the state value when the ON/OFF button is pressed **S2 LOW to make
{
if (Current_State == (ONSTATE || BRIGHTNESS || PRESETS)) // If the Current_State equals ONSTATE execute IF, otherwise execute ELSE
{
return OFF; // Pass OFF to the StateM Function
}
else
{
return ON; // Pass ON to the StateM Function
}
}
if(P1IN & Select_B) // Changes the state value when the SELECT button is pressed
{
if (Current_State == ONSTATE) // If the Current_State is equal to ONSTATE execute IF
{
return LIGHTLEVEL; // Pass LIGHTLEVEL to the StateM Function
}
if (Current_State == BRIGHTNESS) // If the Current_State is equal to BRIGHTNESS execute IF
{
return MODE; // Pass MODE to the StateM Function
}
else // If the Current_State is equal to PRESETS execute ELSE
{
return LIGHTLEVEL; // Pass LIGHTLEVEL to the StateM Function
}
}
else
{
return MAXSTATES;
}
}
// State Machine code starts here
void StateM(int event)
{
int NextState = Current_State;
switch ( Current_State )
{
case OFFSTATE:
// LCD off
ClearLcmScreen();
LcmSetCursorPosition(0,3); //function to set text position then use LCD command
PrintStr("SYSTEM OFF");
switch (event)
{
case ON:
NextState = ONSTATE;
break;
case LIGHTLEVEL:
NextState = BRIGHTNESS;
break;
case MODE:
NextState = PRESETS;
break;
case OFF:
NextState = OFFSTATE;
break;
}
break;
case ONSTATE:
// short delay "Please press select button"
ClearLcmScreen();
LcmSetCursorPosition(0,3); //function to set text position then use LCD command
PrintStr("SYSTEM ON");
LcmSetCursorPosition(1,2); //text position via command to LCD
PrintStr("PRESS SELECT");
switch (event)
{
case ON:
NextState = ONSTATE;
break;
case LIGHTLEVEL:
NextState = BRIGHTNESS;
break;
case MODE:
NextState = PRESETS;
break;
case OFF:
NextState = OFFSTATE;
break;
}
break;
case BRIGHTNESS:
// SEPERATE FUNCTION TO CONTROL BRIGHTNESS
ClearLcmScreen();
LcmSetCursorPosition(0,1); //function to set text position then use LCD command
PrintStr("BRIGHTNESS ADJ");
switch (event)
{
case ON:
NextState = ONSTATE;
break;
case LIGHTLEVEL:
NextState = BRIGHTNESS;
break;
case MODE:
NextState = PRESETS;
break;
case OFF:
NextState = OFFSTATE;
break;
}
break;
case PRESETS:
// SEPERATE FUNCTION TO SWITCH PRESETS
ClearLcmScreen();
LcmSetCursorPosition(0,2); //function to set text position then use LCD command
PrintStr("PRESET MODES");
switch (event)
{
case ON:
NextState = ONSTATE;
break;
case LIGHTLEVEL:
NextState = BRIGHTNESS;
break;
case MODE:
NextState = PRESETS;
break;
case OFF:
NextState = OFFSTATE;
break;
}
break;
default:
break;
// The program should never get here !
}
if (NextState != Current_State)
{
//OnExit(Current_State);
//OnEnter(NextState);
Current_State = NextState;
}
Thanks for looking at this in advance and hope my explanation makes sense.
Regards,
Ant