Skip to content

Instantly share code, notes, and snippets.

@shabaz123
Last active March 9, 2024 04:20
Show Gist options
  • Save shabaz123/ca3e76b55e292d316417e87d4ae74719 to your computer and use it in GitHub Desktop.
Save shabaz123/ca3e76b55e292d316417e87d4ae74719 to your computer and use it in GitHub Desktop.
MSP430 code (MSP430G2452) to implement a push-button power on/off system
/***********************************************
* Button Power Control
*
* rev 1 - shabaz - December 2023
* This code expects a push-button wired to GPIO pin P1.2 and VCC.
* The output is on pin P2.3
* The delays for turn-on and turn-off are separately configurable
* (see the definitions below)
* *********************************************/
// includes
#include <msp430.h>
// ******** defines ********
// change to suit requirements
// times are in multiples of 10msec, so 100 means 1000 msec.
#define PUSH_ON_INTERVAL 100
#define PUSH_OFF_INTERVAL 100
#define DEBOUNCE_INTERVAL 10
#define PWR_ENABLE P2OUT |= (0x01 << 3)
#define PWR_DISABLE P2OUT &= ~(0x01 << 3)
// PUSH_BTN_B input is normally low
#define PUSH_BTN_B_PRESSED ((P1IN & 0x04)!=0)
#define PUSH_BTN_B_UNPRESSED ((P1IN & 0x04)==0)
#define BTN_B_EVENT 1
#define BTN_B_NOEVENT 0
#define TOGGLE_NONE 0
#define TOGGLE_WAIT_ON_DEBOUNCE 1
#define TOGGLE_ON_REL_DEBOUNCE 2
#define TOGGLE_ON 3
#define TOGGLE_WAIT_OFF_DEBOUNCE 4
#define TOGGLE_OFF_REL_DEBOUNCE 5
// global vars
unsigned int mtick;
unsigned char timer_status;
// other
unsigned char pwrstate;
// push-button B
unsigned char btn_b_event;
unsigned char toggle_state;
// function prototypes
// ********* interrupt service routines *********
// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
if (mtick < 65535) {
mtick++;
}
__bic_SR_register_on_exit(LPM3_bits);
}
// Port 1 interrupt service routine
#pragma vector=PORT1_VECTOR
__interrupt void port1_isr(void)
{
if ((P1IFG & 0x04) != 0) {
// P1.2 interrupt occurred
btn_b_event = BTN_B_EVENT;
}
P1IFG = 0; // reset interrupt
__bic_SR_register_on_exit(LPM3_bits);
}
// functions
void enable_timer(void)
{
timer_status = 1;
mtick=0;
CCR0 = 120; // 120 = 10msec (approx)
TACTL = TASSEL_1 | MC_1 | TACLR; // ACLK, upmode, and clear the counter
CCTL0 |= CCIE; // enable CCRO interrupt
}
void disable_timer(void)
{
CCTL0 &= ~CCIE; // disable CCRO interrupt
timer_status = 0;
}
// function to handle push-on and push-off functionality
void process_btn_b(void)
{
switch(toggle_state) {
case TOGGLE_NONE:
if (btn_b_event==BTN_B_EVENT) {
toggle_state = TOGGLE_WAIT_ON_DEBOUNCE;
enable_timer();
}
break;
case TOGGLE_WAIT_ON_DEBOUNCE:
if(PUSH_BTN_B_PRESSED) {
if (mtick>=PUSH_ON_INTERVAL) {
// button was held down long enough, so we can power up!
PWR_ENABLE;
mtick=0;
toggle_state = TOGGLE_ON_REL_DEBOUNCE;
} else {
// continue to wait to see if the button is pressed long enough
}
} else {
// button was prematurely released! abort.
toggle_state = TOGGLE_NONE;
disable_timer();
}
break;
case TOGGLE_ON_REL_DEBOUNCE:
if (PUSH_BTN_B_PRESSED) {
// keep waiting for the user to release the button
} else {
if (mtick>=DEBOUNCE_INTERVAL) {
toggle_state = TOGGLE_ON;
} else {
// keep waiting
}
}
break;
case TOGGLE_ON:
// do nothing unless the button is pressed
disable_timer();
//if (btn_b_event==BTN_B_EVENT) {
if (PUSH_BTN_B_PRESSED) {
toggle_state = TOGGLE_WAIT_OFF_DEBOUNCE;
enable_timer();
} else {
// do nothing, we are powered up, and no button event to power off.
}
break;
case TOGGLE_WAIT_OFF_DEBOUNCE:
if (PUSH_BTN_B_PRESSED) {
if (mtick>=PUSH_OFF_INTERVAL) {
// button was held down long enough, so we can power off!
PWR_DISABLE;
mtick=0;
toggle_state = TOGGLE_OFF_REL_DEBOUNCE;
} else {
// continue to wait to see if button is pressed long enough
}
} else {
// button was prematurely released! abort back to the ON state.
toggle_state = TOGGLE_ON;
disable_timer();
}
break;
case TOGGLE_OFF_REL_DEBOUNCE:
if (PUSH_BTN_B_PRESSED) {
// keep waiting for the user to release the button
} else {
if (mtick>=DEBOUNCE_INTERVAL) {
toggle_state = TOGGLE_NONE;
disable_timer();
} else {
// keep waiting
}
}
default:
break;
}
btn_b_event=BTN_B_NOEVENT;
}
// ************* main function ******************
void main (void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
BCSCTL3 = LFXT1S_2; // use VLO for ACLK
// global var initialization
mtick=0;
timer_status = 0;
btn_b_event = BTN_B_NOEVENT;
toggle_state = TOGGLE_NONE;
// input/output initialization
P1OUT = 0;
P2OUT = 0;
P1DIR = 0xF8; // Set P1.3, 1.4, 1.5, 1.6, 1.7 as outputs
P2DIR = 0x2f; // Set P2.0, 2.1, 2.2, 2.3, 2.5 as outputs
P1REN |= 0x07; // resistor enabled for P1.0, 1.1, 1.2 (to act as pull-down)
P2REN |= 0x10; // resistor enabled for P2.4 (to act as pull-down)
P1IES &= ~0x04; // interrupt on low-to-high transition of P1.2
P1IE |= 0x04; // interrupt enable for P1.2
PWR_DISABLE; // start with the power disabled
__bis_SR_register(GIE); // enable interrupts
while(1) {
// enter a power mode depending on if button detection or clock interrupt is needed
if (timer_status) {
__bis_SR_register(LPM3_bits); // enter LPM3, clock will be updated
} else {
__bis_SR_register(LPM3_bits); // don't know why LPM4_bits here doesn't work
}
process_btn_b();
_NOP(); // set breakpoint here if desired to see operation
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment