You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

415 lines
13 KiB

5 years ago
  1. /*
  2. * main.c
  3. *
  4. * MSP-EXP430G2-LaunchPad User Experience Application
  5. *
  6. * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
  7. *
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. *
  13. * Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. *
  16. * Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the
  19. * distribution.
  20. *
  21. * Neither the name of Texas Instruments Incorporated nor the names of
  22. * its contributors may be used to endorse or promote products derived
  23. * from this software without specific prior written permission.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  26. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  27. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  28. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  29. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  30. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  31. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  32. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  33. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  34. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  35. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. *
  37. */
  38. /******************************************************************************
  39. * MSP-EXP430G2-LaunchPad User Experience Application
  40. *
  41. * 1. Device starts up in LPM3 + blinking LED to indicate device is alive
  42. * + Upon first button press, device transitions to application mode
  43. * 2. Application Mode
  44. * + Continuously sample ADC Temp Sensor channel, compare result against
  45. * initial value
  46. * + Set PWM based on measured ADC offset: Red LED for positive offset, Green
  47. * LED for negative offset
  48. * + Transmit temperature value via TimerA UART to PC
  49. * + Button Press --> Calibrate using current temperature
  50. * Send character '' via UART, notifying PC
  51. *
  52. * Changes:
  53. *
  54. * 1.2 + Updated register naming conventions to reflect latest standard by TI
  55. * e.g.: CCR0 --> TACCR0, CCTL0 --> TACCTL0
  56. * + Changed method to capture TAR value into TACCR0 by using capture a
  57. * SW-triggered event. [Changing TACCR input from GND to VCC]
  58. * 1.1 + LED1 & LED2 labels changed so that Green LED(LED2) indicates sampled
  59. * temperature colder than calibrated temperature and vice versa
  60. * with Red LED (LED1).
  61. * + Turn off peripheral function of TXD after transmitting byte to
  62. * eliminate the extra glitch at the end of UART transmission
  63. * 1.0 Initial Release Version
  64. *
  65. * Texas Instruments, Inc.
  66. ******************************************************************************/
  67. #include "msp430g2553.h"
  68. #define LED1 BIT0
  69. #define LED2 BIT6
  70. #define LED_DIR P1DIR
  71. #define LED_OUT P1OUT
  72. #define BUTTON BIT3
  73. #define BUTTON_OUT P1OUT
  74. #define BUTTON_DIR P1DIR
  75. #define BUTTON_IN P1IN
  76. #define BUTTON_IE P1IE
  77. #define BUTTON_IES P1IES
  78. #define BUTTON_IFG P1IFG
  79. #define BUTTON_REN P1REN
  80. #define TXD BIT1 // TXD on P1.1
  81. #define RXD BIT2 // RXD on P1.2
  82. #define APP_STANDBY_MODE 0
  83. #define APP_APPLICATION_MODE 1
  84. #define TIMER_PWM_MODE 0
  85. #define TIMER_UART_MODE 1
  86. #define TIMER_PWM_PERIOD 2000
  87. #define TIMER_PWM_OFFSET 20
  88. #define TEMP_SAME 0
  89. #define TEMP_HOT 1
  90. #define TEMP_COLD 2
  91. #define TEMP_THRESHOLD 5
  92. // Conditions for 9600/4=2400 Baud SW UART, SMCLK = 1MHz
  93. #define Bitime_5 0x05*4 // ~ 0.5 bit length + small adjustment
  94. #define Bitime 13*4//0x0D
  95. #define UART_UPDATE_INTERVAL 1000
  96. unsigned char BitCnt;
  97. unsigned char applicationMode = APP_STANDBY_MODE;
  98. unsigned char timerMode = TIMER_PWM_MODE;
  99. unsigned char tempMode;
  100. unsigned char calibrateUpdate = 0;
  101. unsigned char tempPolarity = TEMP_SAME;
  102. unsigned int TXByte;
  103. /* Using an 8-value moving average filter on sampled ADC values */
  104. long tempMeasured[8];
  105. unsigned char tempMeasuredPosition=0;
  106. long tempAverage;
  107. long tempCalibrated, tempDifference;
  108. void InitializeLeds(void);
  109. void InitializeButton(void);
  110. void PreApplicationMode(void); // Blinks LED, waits for button press
  111. void ConfigureAdcTempSensor(void);
  112. void ConfigureTimerPwm(void);
  113. void ConfigureTimerUart(void);
  114. void Transmit(void);
  115. void InitializeClocks(void);
  116. void main(void)
  117. {
  118. unsigned int uartUpdateTimer = UART_UPDATE_INTERVAL;
  119. unsigned char i;
  120. WDTCTL = WDTPW + WDTHOLD; // Stop WDT
  121. InitializeClocks();
  122. InitializeButton();
  123. InitializeLeds();
  124. PreApplicationMode(); // Blinks LEDs, waits for button press
  125. /* Application Mode begins */
  126. applicationMode = APP_APPLICATION_MODE;
  127. ConfigureAdcTempSensor();
  128. ConfigureTimerPwm();
  129. __enable_interrupt(); // Enable interrupts.
  130. /* Main Application Loop */
  131. while(1)
  132. {
  133. ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
  134. __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
  135. /* Moving average filter out of 8 values to somewhat stabilize sampled ADC */
  136. tempMeasured[tempMeasuredPosition++] = ADC10MEM;
  137. if (tempMeasuredPosition == 8)
  138. tempMeasuredPosition = 0;
  139. tempAverage = 0;
  140. for (i = 0; i < 8; i++)
  141. tempAverage += tempMeasured[i];
  142. tempAverage >>= 3; // Divide by 8 to get average
  143. if ((--uartUpdateTimer == 0) || calibrateUpdate )
  144. {
  145. ConfigureTimerUart();
  146. if (calibrateUpdate)
  147. {
  148. TXByte = 248; // A character with high value, outside of temp range
  149. Transmit();
  150. calibrateUpdate = 0;
  151. }
  152. TXByte = (unsigned char)( ((tempAverage - 630) * 761) / 1024 );
  153. Transmit();
  154. uartUpdateTimer = UART_UPDATE_INTERVAL;
  155. ConfigureTimerPwm();
  156. }
  157. tempDifference = tempAverage - tempCalibrated;
  158. if (tempDifference < -TEMP_THRESHOLD)
  159. {
  160. tempDifference = -tempDifference;
  161. tempPolarity = TEMP_COLD;
  162. LED_OUT &= ~ LED1;
  163. }
  164. else
  165. if (tempDifference > TEMP_THRESHOLD)
  166. {
  167. tempPolarity = TEMP_HOT;
  168. LED_OUT &= ~ LED2;
  169. }
  170. else
  171. {
  172. tempPolarity = TEMP_SAME;
  173. TACCTL0 &= ~CCIE;
  174. TACCTL1 &= ~CCIE;
  175. LED_OUT &= ~(LED1 + LED2);
  176. }
  177. if (tempPolarity != TEMP_SAME)
  178. {
  179. tempDifference <<= 3;
  180. tempDifference += TIMER_PWM_OFFSET;
  181. TACCR1 = ( (tempDifference) < (TIMER_PWM_PERIOD-1) ? (tempDifference) : (TIMER_PWM_PERIOD-1) );
  182. TACCTL0 |= CCIE;
  183. TACCTL1 |= CCIE;
  184. }
  185. }
  186. }
  187. void PreApplicationMode(void)
  188. {
  189. LED_DIR |= LED1 + LED2;
  190. LED_OUT |= LED1; // To enable the LED toggling effect
  191. LED_OUT &= ~LED2;
  192. BCSCTL1 |= DIVA_1; // ACLK/2
  193. BCSCTL3 |= LFXT1S_2; // ACLK = VLO
  194. TACCR0 = 1200; //
  195. TACTL = TASSEL_1 | MC_1; // TACLK = SMCLK, Up mode.
  196. TACCTL1 = CCIE + OUTMOD_3; // TACCTL1 Capture Compare
  197. TACCR1 = 600;
  198. __bis_SR_register(LPM3_bits + GIE); // LPM0 with interrupts enabled
  199. }
  200. void ConfigureAdcTempSensor(void)
  201. {
  202. unsigned char i;
  203. /* Configure ADC Temp Sensor Channel */
  204. ADC10CTL1 = INCH_10 + ADC10DIV_3; // Temp Sensor ADC10CLK/4
  205. ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE;
  206. __delay_cycles(1000); // Wait for ADC Ref to settle
  207. ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
  208. __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
  209. tempCalibrated = ADC10MEM;
  210. for (i=0; i < 8; i++)
  211. tempMeasured[i] = tempCalibrated;
  212. tempAverage = tempCalibrated;
  213. }
  214. void ConfigureTimerPwm(void)
  215. {
  216. timerMode = TIMER_PWM_MODE;
  217. TACCR0 = TIMER_PWM_PERIOD; //
  218. TACTL = TASSEL_2 | MC_1; // TACLK = SMCLK, Up mode.
  219. TACCTL0 = CCIE;
  220. TACCTL1 = CCIE + OUTMOD_3; // TACCTL1 Capture Compare
  221. TACCR1 = 1;
  222. }
  223. void ConfigureTimerUart(void)
  224. {
  225. timerMode = TIMER_UART_MODE; // Configure TimerA0 UART TX
  226. TACCTL0 = OUT; // TXD Idle as Mark
  227. TACTL = TASSEL_2 + MC_2 + ID_3; // SMCLK/8, continuous mode
  228. P1SEL |= TXD + RXD; //
  229. P1DIR |= TXD; //
  230. }
  231. // Function Transmits Character from TXByte
  232. void Transmit()
  233. {
  234. BitCnt = 0xA; // Load Bit counter, 8data + ST/SP
  235. /* Simulate a timer capture event to obtain the value of TAR into the TACCR0 register */
  236. TACCTL0 = CM_1 + CCIS_2 + SCS + CAP + OUTMOD0; //capture on rising edge, initially set to GND as input // clear CCIFG flag
  237. TACCTL0 |= CCIS_3; //change input to Vcc, effectively rising the edge, triggering the capture action
  238. while (!(TACCTL0 & CCIFG)); //allowing for the capturing//updating TACCR0.
  239. TACCR0 += Bitime ; // Some time till first bit
  240. TXByte |= 0x100; // Add mark stop bit to TXByte
  241. TXByte = TXByte << 1; // Add space start bit
  242. TACCTL0 = CCIS0 + OUTMOD0 + CCIE; // TXD = mark = idle
  243. while ( TACCTL0 & CCIE ); // Wait for TX completion
  244. }
  245. // Timer A0 interrupt service routine
  246. #pragma vector=TIMER0_A0_VECTOR
  247. __interrupt void Timer_A (void)
  248. {
  249. if (timerMode == TIMER_UART_MODE)
  250. {
  251. TACCR0 += Bitime; // Add Offset to TACCR0
  252. if (TACCTL0 & CCIS0) // TX on CCI0B?
  253. {
  254. if ( BitCnt == 0)
  255. {
  256. P1SEL &= ~(TXD+RXD);
  257. TACCTL0 &= ~ CCIE ; // All bits TXed, disable interrupt
  258. }
  259. else
  260. {
  261. TACCTL0 |= OUTMOD2; // TX Space
  262. if (TXByte & 0x01)
  263. TACCTL0 &= ~ OUTMOD2; // TX Mark
  264. TXByte = TXByte >> 1;
  265. BitCnt --;
  266. }
  267. }
  268. }
  269. else
  270. {
  271. if (tempPolarity == TEMP_HOT)
  272. LED_OUT |= LED1;
  273. if (tempPolarity == TEMP_COLD)
  274. LED_OUT |= LED2;
  275. TACCTL0 &= ~CCIFG;
  276. }
  277. }
  278. #pragma vector=TIMER0_A1_VECTOR
  279. __interrupt void ta1_isr(void)
  280. {
  281. TACCTL1 &= ~CCIFG;
  282. if (applicationMode == APP_APPLICATION_MODE)
  283. LED_OUT &= ~(LED1 + LED2);
  284. else
  285. LED_OUT ^= (LED1 + LED2);
  286. }
  287. void InitializeClocks(void)
  288. {
  289. BCSCTL1 = CALBC1_1MHZ; // Set range
  290. DCOCTL = CALDCO_1MHZ;
  291. BCSCTL2 &= ~(DIVS_3); // SMCLK = DCO = 1MHz
  292. }
  293. void InitializeButton(void) // Configure Push Button
  294. {
  295. BUTTON_DIR &= ~BUTTON;
  296. BUTTON_OUT |= BUTTON;
  297. BUTTON_REN |= BUTTON;
  298. BUTTON_IES |= BUTTON;
  299. BUTTON_IFG &= ~BUTTON;
  300. BUTTON_IE |= BUTTON;
  301. }
  302. void InitializeLeds(void)
  303. {
  304. LED_DIR |= LED1 + LED2;
  305. LED_OUT &= ~(LED1 + LED2);
  306. }
  307. /* *************************************************************
  308. * Port Interrupt for Button Press
  309. * 1. During standby mode: to exit and enter application mode
  310. * 2. During application mode: to recalibrate temp sensor
  311. * *********************************************************** */
  312. #pragma vector=PORT1_VECTOR
  313. __interrupt void PORT1_ISR(void)
  314. {
  315. BUTTON_IFG = 0;
  316. BUTTON_IE &= ~BUTTON; /* Debounce */
  317. WDTCTL = WDT_ADLY_250;
  318. IFG1 &= ~WDTIFG; /* clear interrupt flag */
  319. IE1 |= WDTIE;
  320. if (applicationMode == APP_APPLICATION_MODE)
  321. {
  322. tempCalibrated = tempAverage;
  323. calibrateUpdate = 1;
  324. }
  325. else
  326. {
  327. applicationMode = APP_APPLICATION_MODE; // Switch from STANDBY to APPLICATION MODE
  328. __bic_SR_register_on_exit(LPM3_bits);
  329. }
  330. }
  331. // WDT Interrupt Service Routine used to de-bounce button press
  332. #pragma vector=WDT_VECTOR
  333. __interrupt void WDT_ISR(void)
  334. {
  335. IE1 &= ~WDTIE; /* disable interrupt */
  336. IFG1 &= ~WDTIFG; /* clear interrupt flag */
  337. WDTCTL = WDTPW + WDTHOLD; /* put WDT back in hold state */
  338. BUTTON_IE |= BUTTON; /* Debouncing complete */
  339. }
  340. // ADC10 interrupt service routine
  341. #pragma vector=ADC10_VECTOR
  342. __interrupt void ADC10_ISR (void)
  343. {
  344. __bic_SR_register_on_exit(CPUOFF); // Return to active mode
  345. }