/*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
|
|
/******************************************************************************
|
|
* 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, compare result against
|
|
* initial value
|
|
* + Set PWM based on measured ADC offset: Red LED for positive offset, Green
|
|
* LED for negative offset
|
|
* + Transmit temperature value via TimerA UART to PC
|
|
* + Button Press --> Calibrate using current temperature
|
|
* Send character '°' via UART, notifying PC
|
|
*
|
|
* Changes:
|
|
*
|
|
* 1.2 + Updated register naming conventions to reflect latest standard by TI
|
|
* e.g.: CCR0 --> TACCR0, CCTL0 --> TACCTL0
|
|
* + Changed method to capture TAR value into TACCR0 by using capture a
|
|
* SW-triggered event. [Changing TACCR input from GND to VCC]
|
|
* 1.1 + LED1 & LED2 labels changed so that Green LED(LED2) indicates sampled
|
|
* temperature colder than calibrated temperature and vice versa
|
|
* with Red LED (LED1).
|
|
* + Turn off peripheral function of TXD after transmitting byte to
|
|
* eliminate the extra glitch at the end of UART transmission
|
|
* 1.0 Initial Release Version
|
|
*
|
|
* Texas Instruments, Inc.
|
|
******************************************************************************/
|
|
|
|
//#include "msp430g2553.h"
|
|
//No longer needed, as the header file is specified by msp430-gcc build parameter
|
|
#include "signal.h"
|
|
|
|
|
|
#define LED1 BIT0
|
|
#define LED2 BIT6
|
|
#define LED_DIR P1DIR
|
|
#define LED_OUT P1OUT
|
|
|
|
|
|
|
|
#define BUTTON BIT3
|
|
#define BUTTON_OUT P1OUT
|
|
#define BUTTON_DIR P1DIR
|
|
#define BUTTON_IN P1IN
|
|
#define BUTTON_IE P1IE
|
|
#define BUTTON_IES P1IES
|
|
#define BUTTON_IFG P1IFG
|
|
#define BUTTON_REN P1REN
|
|
|
|
#define TXD BIT1 // TXD on P1.1
|
|
#define RXD BIT2 // RXD on P1.2
|
|
|
|
#define APP_STANDBY_MODE 0
|
|
#define APP_APPLICATION_MODE 1
|
|
|
|
#define TIMER_PWM_MODE 0
|
|
#define TIMER_UART_MODE 1
|
|
#define TIMER_PWM_PERIOD 2000
|
|
#define TIMER_PWM_OFFSET 20
|
|
|
|
#define TEMP_SAME 0
|
|
#define TEMP_HOT 1
|
|
#define TEMP_COLD 2
|
|
|
|
#define TEMP_THRESHOLD 5
|
|
|
|
// Conditions for 9600/4=2400 Baud SW UART, SMCLK = 1MHz
|
|
#define Bitime_5 0x05*4 // ~ 0.5 bit length + small adjustment
|
|
#define Bitime 13*4//0x0D
|
|
|
|
#define UART_UPDATE_INTERVAL 1000
|
|
|
|
|
|
unsigned char BitCnt;
|
|
|
|
|
|
unsigned char applicationMode = APP_STANDBY_MODE;
|
|
unsigned char timerMode = TIMER_PWM_MODE;
|
|
|
|
unsigned char tempMode;
|
|
unsigned char calibrateUpdate = 0;
|
|
unsigned char tempPolarity = TEMP_SAME;
|
|
unsigned int TXByte;
|
|
|
|
/* Using an 8-value moving average filter on sampled ADC values */
|
|
long tempMeasured[8];
|
|
unsigned char tempMeasuredPosition=0;
|
|
long tempAverage;
|
|
|
|
long tempCalibrated, tempDifference;
|
|
|
|
|
|
|
|
void InitializeLeds(void);
|
|
void InitializeButton(void);
|
|
void PreApplicationMode(void); // Blinks LED, waits for button press
|
|
void ConfigureAdcTempSensor(void);
|
|
void ConfigureTimerPwm(void);
|
|
void ConfigureTimerUart(void);
|
|
void Transmit(void);
|
|
void InitializeClocks(void);
|
|
|
|
|
|
void main(void)
|
|
{
|
|
unsigned int uartUpdateTimer = UART_UPDATE_INTERVAL;
|
|
unsigned char i;
|
|
|
|
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
|
|
|
|
InitializeClocks();
|
|
InitializeButton();
|
|
InitializeLeds();
|
|
PreApplicationMode(); // Blinks LEDs, waits for button press
|
|
|
|
/* Application Mode begins */
|
|
applicationMode = APP_APPLICATION_MODE;
|
|
|
|
|
|
|
|
ConfigureAdcTempSensor();
|
|
ConfigureTimerPwm();
|
|
|
|
__enable_interrupt(); // Enable interrupts.
|
|
|
|
/* Main Application Loop */
|
|
while(1)
|
|
{
|
|
ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
|
|
__bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
|
|
|
|
/* Moving average filter out of 8 values to somewhat stabilize sampled ADC */
|
|
tempMeasured[tempMeasuredPosition++] = ADC10MEM;
|
|
if (tempMeasuredPosition == 8)
|
|
tempMeasuredPosition = 0;
|
|
tempAverage = 0;
|
|
for (i = 0; i < 8; i++)
|
|
tempAverage += tempMeasured[i];
|
|
tempAverage >>= 3; // Divide by 8 to get average
|
|
|
|
if ((--uartUpdateTimer == 0) || calibrateUpdate )
|
|
{
|
|
ConfigureTimerUart();
|
|
if (calibrateUpdate)
|
|
{
|
|
TXByte = 248; // A character with high value, outside of temp range
|
|
|
|
Transmit();
|
|
calibrateUpdate = 0;
|
|
}
|
|
TXByte = (unsigned char)( ((tempAverage - 630) * 761) / 1024 );
|
|
|
|
Transmit();
|
|
|
|
|
|
uartUpdateTimer = UART_UPDATE_INTERVAL;
|
|
ConfigureTimerPwm();
|
|
}
|
|
|
|
tempDifference = tempAverage - tempCalibrated;
|
|
if (tempDifference < -TEMP_THRESHOLD)
|
|
{
|
|
tempDifference = -tempDifference;
|
|
tempPolarity = TEMP_COLD;
|
|
LED_OUT &= ~ LED1;
|
|
}
|
|
else
|
|
if (tempDifference > TEMP_THRESHOLD)
|
|
{
|
|
tempPolarity = TEMP_HOT;
|
|
LED_OUT &= ~ LED2;
|
|
}
|
|
else
|
|
{
|
|
tempPolarity = TEMP_SAME;
|
|
TACCTL0 &= ~CCIE;
|
|
TACCTL1 &= ~CCIE;
|
|
LED_OUT &= ~(LED1 + LED2);
|
|
}
|
|
|
|
if (tempPolarity != TEMP_SAME)
|
|
{
|
|
tempDifference <<= 3;
|
|
tempDifference += TIMER_PWM_OFFSET;
|
|
TACCR1 = ( (tempDifference) < (TIMER_PWM_PERIOD-1) ? (tempDifference) : (TIMER_PWM_PERIOD-1) );
|
|
TACCTL0 |= CCIE;
|
|
TACCTL1 |= CCIE;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void PreApplicationMode(void)
|
|
{
|
|
LED_DIR |= LED1 + LED2;
|
|
LED_OUT |= LED1; // To enable the LED toggling effect
|
|
LED_OUT &= ~LED2;
|
|
|
|
BCSCTL1 |= DIVA_1; // ACLK/2
|
|
BCSCTL3 |= LFXT1S_2; // ACLK = VLO
|
|
|
|
TACCR0 = 1200; //
|
|
TACTL = TASSEL_1 | MC_1; // TACLK = SMCLK, Up mode.
|
|
TACCTL1 = CCIE + OUTMOD_3; // TACCTL1 Capture Compare
|
|
TACCR1 = 600;
|
|
__bis_SR_register(LPM3_bits + GIE); // LPM0 with interrupts enabled
|
|
}
|
|
|
|
void ConfigureAdcTempSensor(void)
|
|
{
|
|
unsigned char i;
|
|
/* 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
|
|
ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
|
|
__bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
|
|
tempCalibrated = ADC10MEM;
|
|
for (i=0; i < 8; i++)
|
|
tempMeasured[i] = tempCalibrated;
|
|
tempAverage = tempCalibrated;
|
|
}
|
|
|
|
|
|
void ConfigureTimerPwm(void)
|
|
{
|
|
timerMode = TIMER_PWM_MODE;
|
|
|
|
TACCR0 = TIMER_PWM_PERIOD; //
|
|
TACTL = TASSEL_2 | MC_1; // TACLK = SMCLK, Up mode.
|
|
TACCTL0 = CCIE;
|
|
TACCTL1 = CCIE + OUTMOD_3; // TACCTL1 Capture Compare
|
|
TACCR1 = 1;
|
|
}
|
|
|
|
void ConfigureTimerUart(void)
|
|
{
|
|
timerMode = TIMER_UART_MODE; // Configure TimerA0 UART TX
|
|
|
|
TACCTL0 = OUT; // TXD Idle as Mark
|
|
TACTL = TASSEL_2 + MC_2 + ID_3; // SMCLK/8, continuous mode
|
|
P1SEL |= TXD + RXD; //
|
|
P1DIR |= TXD; //
|
|
}
|
|
|
|
// Function Transmits Character from TXByte
|
|
void Transmit()
|
|
{
|
|
BitCnt = 0xA; // Load Bit counter, 8data + ST/SP
|
|
|
|
/* Simulate a timer capture event to obtain the value of TAR into the TACCR0 register */
|
|
TACCTL0 = CM_1 + CCIS_2 + SCS + CAP + OUTMOD0; //capture on rising edge, initially set to GND as input // clear CCIFG flag
|
|
TACCTL0 |= CCIS_3; //change input to Vcc, effectively rising the edge, triggering the capture action
|
|
|
|
while (!(TACCTL0 & CCIFG)); //allowing for the capturing//updating TACCR0.
|
|
|
|
TACCR0 += Bitime ; // Some time till first bit
|
|
TXByte |= 0x100; // Add mark stop bit to TXByte
|
|
TXByte = TXByte << 1; // Add space start bit
|
|
TACCTL0 = CCIS0 + OUTMOD0 + CCIE; // TXD = mark = idle
|
|
|
|
while ( TACCTL0 & CCIE ); // Wait for TX completion
|
|
}
|
|
|
|
|
|
|
|
// Timer A0 interrupt service routine
|
|
//-------- IAR & CCS Convention
|
|
//#pragma vector=TIMER0_A0_VECTOR
|
|
//__interrupt void Timer_A (void)
|
|
|
|
//-------- GCC Convention
|
|
interrupt (TIMER0_A0_VECTOR) Timer_A(void)
|
|
{
|
|
if (timerMode == TIMER_UART_MODE)
|
|
{
|
|
TACCR0 += Bitime; // Add Offset to TACCR0
|
|
if (TACCTL0 & CCIS0) // TX on CCI0B?
|
|
{
|
|
if ( BitCnt == 0)
|
|
{
|
|
P1SEL &= ~(TXD+RXD);
|
|
TACCTL0 &= ~ CCIE ; // All bits TXed, disable interrupt
|
|
}
|
|
|
|
else
|
|
{
|
|
TACCTL0 |= OUTMOD2; // TX Space
|
|
if (TXByte & 0x01)
|
|
TACCTL0 &= ~ OUTMOD2; // TX Mark
|
|
TXByte = TXByte >> 1;
|
|
BitCnt --;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (tempPolarity == TEMP_HOT)
|
|
LED_OUT |= LED1;
|
|
if (tempPolarity == TEMP_COLD)
|
|
LED_OUT |= LED2;
|
|
TACCTL0 &= ~CCIFG;
|
|
}
|
|
}
|
|
// ----------- CCS & IAR convention
|
|
//#pragma vector=TIMER0_A1_VECTOR
|
|
//__interrupt void ta1_isr(void)
|
|
interrupt (TIMER0_A1_VECTOR) ta1_isr(void)
|
|
{
|
|
TACCTL1 &= ~CCIFG;
|
|
if (applicationMode == APP_APPLICATION_MODE)
|
|
LED_OUT &= ~(LED1 + LED2);
|
|
else
|
|
LED_OUT ^= (LED1 + LED2);
|
|
|
|
}
|
|
|
|
void InitializeClocks(void)
|
|
{
|
|
|
|
BCSCTL1 = CALBC1_1MHZ; // Set range
|
|
DCOCTL = CALDCO_1MHZ;
|
|
BCSCTL2 &= ~(DIVS_3); // SMCLK = DCO = 1MHz
|
|
}
|
|
|
|
void InitializeButton(void) // Configure Push Button
|
|
{
|
|
BUTTON_DIR &= ~BUTTON;
|
|
BUTTON_OUT |= BUTTON;
|
|
BUTTON_REN |= BUTTON;
|
|
BUTTON_IES |= BUTTON;
|
|
BUTTON_IFG &= ~BUTTON;
|
|
BUTTON_IE |= BUTTON;
|
|
}
|
|
|
|
|
|
void InitializeLeds(void)
|
|
{
|
|
LED_DIR |= LED1 + LED2;
|
|
LED_OUT &= ~(LED1 + LED2);
|
|
}
|
|
|
|
/* *************************************************************
|
|
* Port Interrupt for Button Press
|
|
* 1. During standby mode: to exit and enter application mode
|
|
* 2. During application mode: to recalibrate temp sensor
|
|
* *********************************************************** */
|
|
interrupt (PORT1_VECTOR) PORT1_ISR(void)
|
|
{
|
|
BUTTON_IFG = 0;
|
|
BUTTON_IE &= ~BUTTON; /* Debounce */
|
|
WDTCTL = WDT_ADLY_250;
|
|
IFG1 &= ~WDTIFG; /* clear interrupt flag */
|
|
IE1 |= WDTIE;
|
|
|
|
if (applicationMode == APP_APPLICATION_MODE)
|
|
{
|
|
tempCalibrated = tempAverage;
|
|
calibrateUpdate = 1;
|
|
}
|
|
else
|
|
{
|
|
applicationMode = APP_APPLICATION_MODE; // Switch from STANDBY to APPLICATION MODE
|
|
|
|
TACCTL1 &= ~CCIE;
|
|
|
|
__bic_SR_register_on_exit(LPM3_bits );
|
|
|
|
}
|
|
}
|
|
|
|
// WDT Interrupt Service Routine used to debounce button press
|
|
interrupt (WDT_VECTOR) WDT_SIR(void)
|
|
{
|
|
IE1 &= ~WDTIE; /* disable interrupt */
|
|
IFG1 &= ~WDTIFG; /* clear interrupt flag */
|
|
WDTCTL = WDTPW + WDTHOLD; /* put WDT back in hold state */
|
|
BUTTON_IE |= BUTTON; /* Debouncing complete */
|
|
}
|
|
|
|
|
|
// ADC10 interrupt service routine
|
|
// -------- CCS & IAR convention
|
|
//#pragma vector=ADC10_VECTOR
|
|
//__interrupt void ADC10_ISR (void)
|
|
interrupt (ADC10_VECTOR) ADC10_ISR(void)
|
|
{
|
|
|
|
__bic_SR_register_on_exit(CPUOFF); // Return to active mode
|
|
|
|
}
|
|
|
|
|
|
|