/* * main.c * * MSP-EXP430G2-LaunchPad User Experience Application * * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Heavily modified: Nov, 2013 Carl Michal * Even more so, February, 2014 * This version modified to use the Hardware UART on MSP430G2553 * see code at https://bennthomsen.wordpress.com/engineering-toolbox/ti-msp430-launchpad/msp430g2553-hardware-uart/ * jumpers for TX/RX on Launchpad board must be rotated 90 degrees * for hardware UART used here!! * This may not work on all revisions of the board? */ /****************************************************************************** * MSP-EXP430G2-LaunchPad User Experience Application * * 1. Device starts up in LPM3 + blinking LED to indicate device is alive * + Upon first button press, device transitions to application mode * 2. Application Mode * + Continuously sample ADC Temp Sensor channel * * + Transmit temperature value via TimerA UART to PC * * * Texas Instruments, Inc. ******************************************************************************/ #include "msp430.h" #define LED1 BIT0 #define LED2 BIT6 #define BUTTON BIT3 #define TXD BIT2 // TXD on P1.2 #define RXD BIT1 // RXD on P1.1 #define PreAppMode 0 #define RunningMode 1 unsigned int TXByte; volatile unsigned int Mode; void InitializeButton(void); void PreApplicationMode(void); void main(void) { long tempMeasured; WDTCTL = WDTPW + WDTHOLD; // Stop WDT /* next three lines to use internal calibrated 1MHz clock: */ BCSCTL1 = CALBC1_1MHZ; // Set range DCOCTL = CALDCO_1MHZ; BCSCTL2 &= ~(DIVS_3); // SMCLK = DCO = 1MHz InitializeButton(); // setup port for leds: P1DIR |= LED1 + LED2; P1OUT &= ~(LED1 + LED2); P1DIR |= TXD; P1OUT |= TXD; Mode = PreAppMode; PreApplicationMode(); // Blinks LEDs, waits for button press /* Configure ADC Temp Sensor Channel */ ADC10CTL1 = INCH_10 + ADC10DIV_3; // Temp Sensor ADC10CLK/4 ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE; __delay_cycles(1000); // Wait for ADC Ref to settle __enable_interrupt(); // Enable interrupts. /* Configure hardware UART */ P1SEL = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD P1SEL2 = BIT1 + BIT2 ; // P1.1 = RXD, P1.2=TXD UCA0CTL1 |= UCSSEL_2; // Use SMCLK UCA0BR0 = 104; // Set baud rate to 9600 with 1MHz clock (Data Sheet 15.3.13) UCA0BR1 = 0; // Set baud rate to 9600 with 1MHz clock UCA0MCTL = UCBRS0; // Modulation UCBRSx = 1 UCA0CTL1 &= ~UCSWRST; // Initialize USCI state machine /* if we were going to receive, we would also: IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt */ /* Main Application Loop */ while(1) { ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled turns cpu off. // an interrupt is triggered when the ADC result is ready. // The interrupt handler restarts the cpu. // store result tempMeasured = ADC10MEM; // convert to farenheit and send to host computer TXByte = (unsigned char)( ((tempMeasured - 630) * 761) / 1024 ); while (! (IFG2 & UCA0TXIFG)); // wait for TX buffer to be ready for new data UCA0TXBUF = TXByte; P1OUT ^= LED1; // toggle the light every time we make a measurement. // set up timer to wake us in a while: TACCR0 = 2400; // period TACTL = TASSEL_1 | MC_1; // TACLK = ACLK, Up mode. TACCR1 = 2400; // interrupt at end TACCTL1 = CCIE; // TACCTL0 // go to sleep, wait till timer expires to do another measurement. __bis_SR_register(LPM3_bits + GIE); // LPM0 with interrupts enabled turns cpu off. // could have just done this - but low power mode is nicer. // __delay_cycles(500000); } } void PreApplicationMode(void) { P1DIR |= LED1 + LED2; P1OUT |= LED1; // To enable the LED toggling effect P1OUT &= ~LED2; /* these next two lines configure the ACLK signal to come from a secondary oscillator source, called VLO */ BCSCTL1 |= DIVA_1; // ACLK is half the speed of the source (VLO) BCSCTL3 |= LFXT1S_2; // ACLK = VLO /* here we're setting up a timer to fire an interrupt periodically. When the timer 1 hits its limit, the interrupt will toggle the lights We're using ACLK as the timer source, since it lets us go into LPM3 (where SMCLK and MCLK are turned off). */ TACCR0 = 1200; // period TACTL = TASSEL_1 | MC_1; // TACLK = ACLK, Up mode. TACCTL1 = CCIE + OUTMOD_3; // TACCTL1 Capture Compare TACCR1 = 600; // duty cycle __bis_SR_register(LPM3_bits + GIE); // LPM3 with interrupts enabled // in LPM3, MCLCK and SMCLK are off, but ACLK is on. } // this gets used in pre-application mode only to toggle the lights: #if defined(__TI_COMPILER_VERSION__) #pragma vector=TIMER0_A1_VECTOR __interrupt void ta1_isr (void) #else void __attribute__ ((interrupt(TIMER0_A1_VECTOR))) ta1_isr (void) #endif { TACCTL1 &= ~CCIFG; // reset the interrupt flag if (Mode == PreAppMode){ P1OUT ^= (LED1 + LED2); // toggle the two lights. } else{ TACCTL1 = 0; // no more interrupts. __bic_SR_register_on_exit(LPM3_bits); // Restart the cpu } } void InitializeButton(void) // Configure Push Button { P1DIR &= ~BUTTON; P1OUT |= BUTTON; P1REN |= BUTTON; P1IES |= BUTTON; P1IFG &= ~BUTTON; P1IE |= BUTTON; } /* ************************************************************* * Port Interrupt for Button Press * 1. During standby mode: to enter application mode * * *********************************************************** */ #if defined(__TI_COMPILER_VERSION__) #pragma vector=PORT1_VECTOR __interrupt void port1_isr(void) #else void __attribute__ ((interrupt(PORT1_VECTOR))) port1_isr (void) #endif { /* this disables port1 interrupts for a little while so that we don't try to respond to two consecutive button pushes right together. The watchdog timer interrupt will re-enable port1 interrupts This whole watchdog thing is completely unnecessary here, but its useful to see how it is done. */ P1IFG = 0; // clear out interrupt flag P1IE &= ~BUTTON; // Disable port 1 interrupts WDTCTL = WDT_ADLY_250; // set up watchdog timer duration IFG1 &= ~WDTIFG; // clear interrupt flag IE1 |= WDTIE; // enable watchdog interrupts TACCTL1 = 0; // turn off timer 1 interrupts P1OUT &= ~(LED1+LED2); // turn off the leds Mode = RunningMode; __bic_SR_register_on_exit(LPM3_bits); // take us out of low power mode } // WDT Interrupt Service Routine used to de-bounce button press #if defined(__TI_COMPILER_VERSION__) #pragma vector=WDT_VECTOR __interrupt void wdt_isr(void) #else void __attribute__ ((interrupt(WDT_VECTOR))) wdt_isr (void) #endif { IE1 &= ~WDTIE; /* disable watchdog interrupt */ IFG1 &= ~WDTIFG; /* clear interrupt flag */ WDTCTL = WDTPW + WDTHOLD; /* put WDT back in hold state */ P1IE |= BUTTON; /* Debouncing complete - reenable port 1 interrupts*/ } // ADC10 interrupt service routine #if defined(__TI_COMPILER_VERSION__) #pragma vector=ADC10_VECTOR __interrupt void adc10_isr(void) #else void __attribute__ ((interrupt(ADC10_VECTOR))) adc10_isr (void) #endif { __bic_SR_register_on_exit(CPUOFF); // Restart the cpu }