Advertisement
Guest User

Temperature Recorder - Source Code

a guest
Apr 1st, 2010
1,003
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.45 KB | None | 0 0
  1. //******************************************************************************
  2. /******************************************************************************/
  3. //
  4. // temp_recorder
  5. //
  6. // Interrupt driven, after power-on initialization, the software checks
  7. // the first free FLASH word to see if run-length encoded data is present.
  8. // If not, the watchdog timer is configured as a watch crystal controlled
  9. // interval timer and each 8-second interrupt measures the temperature.
  10. // But if FLASH has run-length encoded temperature data, it dumps the
  11. // temperature time and values to the USB debugger terminal window and
  12. // log file.
  13. //
  14. // The 16-bit ADC measures the temperature using a built-in thermistor
  15. // device. The built-in 'short' interface is used to provide a relative
  16. // zero. By happy accident, the low-power, 32 oversampling values are a
  17. // simple offset and shift from 1/10th degree Fahrenheit values. However,
  18. // the low order three bits suffer from thermal noise and are shifted out.
  19. //
  20. // To smooth the data, a five-element, Gaussian filter is used on each
  21. // data point. This minimizes noise, yet preserves most local peak events.
  22. //
  23. // The data from the Gaussian filter is stored in a three level,
  24. // run-length encoded array. The three levels are the high, middle and
  25. // low temperatures saved as a byte value and a byte counter. When a new
  26. // high or new low temperature reading occurs, the last array element is
  27. // saved as a run-length word and the temperature arrays shift. The
  28. // run-length word is written to FLASH and the part goes to sleep again.
  29. //
  30. // IAR Project -> Options
  31. // General Options
  32. // Target -> MSP430F2013
  33. // Library Configuration -> CLIB
  34. // Library Options -> printf -> Small
  35. // C/C++ compiler
  36. // Optimization -> size -> High (smallest)
  37. // FET Debugger
  38. // Erase main and information memory -> to initialize part
  39. // Retain unchanged memory -> to dump temperature record
  40. //
  41. // NOTE: The include files are standard, unmodified, with the IAR system.
  42. //
  43. // Bob Wilson, September 19, 2006, bwilson4use@hotmail.com
  44. //
  45. /******************************************************************************/
  46.  
  47. #include "msp430x20x3.h"
  48. #include "intrinsics.h"
  49. #include "stdio.h"
  50. #include "string.h"
  51. #include "limits.h"
  52.  
  53. //
  54. // The maximum temperature in 1/10th degrees should be set by
  55. // the battery chemistry. As for the FLASH itself, the limit is just
  56. // above 100C.
  57. //
  58. #define MAX_TEMP 2200
  59.  
  60. union rlen {
  61. unsigned int temp; // The run length encoded word
  62. unsigned char rb[2]; // The byte values
  63. };
  64.  
  65. unsigned int * temp_begin; // Lowest data address
  66. static unsigned int temp_cnt = 0; // Highest code address
  67. static unsigned int temp_cur = 0; // Current index
  68.  
  69. static unsigned char lcnt = 0; // Count of low values
  70. static unsigned char mcnt = 0; // Count of medium value
  71. static unsigned char hcnt = 0; // Count of high values
  72. static unsigned int ltemp = 0; // Low temperature value
  73. static unsigned int mtemp = 0; // Medium temperature value
  74. static unsigned int htemp = 0; // High temperature value
  75.  
  76.  
  77. static unsigned int wdt_cnt=0; // Interrupt counters
  78. static unsigned int sd16_cnt=0;
  79.  
  80. #define tcnt 6
  81. static unsigned int temp[tcnt]; // Temp measurements
  82.  
  83. //
  84. // FLASH operation code runs out of RAM memory in part because
  85. // it is so slow to write. This following 'flash' module is
  86. // copied over into RAM, fcode[] and then called with the data to be written
  87. // and location.
  88. //
  89. void flash(unsigned int stemp)
  90. {
  91. union rlen rle; // Local data
  92. //
  93. // Range testing
  94. //
  95. if ( stemp > 32687 ) // Did we measure a negative temp?
  96. {
  97. stemp = 0; // Lowest temp is 0
  98. }
  99. //
  100. // Shutoff if TOO HOT!
  101. //
  102. if ( stemp > MAX_TEMP ) // Have we reached limit?
  103. {
  104. _BIC_SR(GIE); // Stop interrupts
  105. _BIS_SR(LPM4_bits); // Save yourself, try to shutoff
  106. }
  107. //
  108. // Run-length encoding code
  109. //
  110. rle.temp = 0; // Nothing for now
  111. if ( (lcnt == 0) & (hcnt == 0) & (mcnt == 0) ) // First entry?
  112. {
  113. htemp = stemp; // Use first temp for both
  114. mtemp = stemp; // Medium temperature
  115. ltemp = stemp; // so we have a start
  116. lcnt = 1; // Count this one
  117. return; // Done for now
  118. }
  119. //
  120. // See if we have an ltemp match
  121. //
  122. if ( stemp == ltemp )
  123. {
  124. if (lcnt < UCHAR_MAX) // Still within count range?
  125. {
  126. lcnt++; // Count this low temp
  127. return;
  128. }
  129. rle.temp = ltemp >> 3; // Shift into a byte
  130. rle.rb[1] = lcnt; // take the count
  131. lcnt = 1; // Keep temp, restart counter
  132. }
  133. //
  134. // See if we have an mtemp match
  135. //
  136. if ( stemp == mtemp )
  137. {
  138. if (mcnt < UCHAR_MAX) // Still within count range?
  139. {
  140. mcnt++; // Count this low temp
  141. return;
  142. }
  143. rle.temp = mtemp >> 3; // Shift into a byte
  144. rle.rb[1] = mcnt; // take the count
  145. mcnt = 1; // Keep temp, restart counter
  146. }
  147. //
  148. // See if we have an htemp match
  149. //
  150. if ( stemp == htemp )
  151. {
  152. if ( hcnt < UCHAR_MAX ) // Still within count range?
  153. {
  154. hcnt++; // Count this high temp
  155. return;
  156. }
  157. rle.temp = htemp >> 3; // Shift into a byte
  158. rle.rb[1] = hcnt; // take the count
  159. hcnt = 1; // Keep temp, restart counter
  160. }
  161. //
  162. // See if a new low has arrived
  163. //
  164. if (stemp < ltemp) // New cold temperature?
  165. { // YES - dump the last high
  166. rle.temp = htemp >> 3; // Bring temp to a byte value
  167. rle.rb[1] = hcnt; // New RTL is ready
  168. htemp = mtemp; // Shift up ltemp
  169. mtemp = ltemp; // save the new mtemp
  170. hcnt = mcnt; // and counter
  171. mcnt = lcnt; // save in new mtemp
  172. ltemp = stemp; // Save the current
  173. lcnt = 1; // Start counting
  174. }
  175. //
  176. // See if a new high has arrived
  177. //
  178. if (stemp > htemp) // New hot temp?
  179. { // YES - dump the last low
  180. rle.temp = ltemp >> 3; // Bring temp to a byte value
  181. rle.rb[1] = lcnt; // New RTL is ready
  182. ltemp = mtemp; // Shift down htemp
  183. mtemp = htemp; // into the medium
  184. lcnt = mcnt; // and counter
  185. mcnt = hcnt; // including medium counter
  186. htemp = stemp; // Save the current temp
  187. hcnt = 1; // Start counting
  188. }
  189. //
  190. // Halt the watchdog, write flash, restart watchdog
  191. //
  192. WDTCTL = WDTPW + WDTHOLD; // Turn off the watchdog timer, for now, no recursion
  193. temp_begin[temp_cur] = rle.temp; // Save the run length encode value
  194. temp_cur += 1; // Point to next
  195.  
  196. if ( temp_cur <= temp_cnt )
  197. {
  198. WDTCTL = WDTPW + // Makes the watchdog work as a timer
  199. WDTSSEL + // use 32,768 kHz clock, / 32768, ~9.5 sec
  200. WDTTMSEL ; // Puts in interval time mode
  201. }
  202. else
  203. {
  204. P1OUT = 0x01; // Enable the LED, done.
  205. }
  206. }
  207.  
  208. void gausian(void)
  209. {
  210. unsigned long sum; // Start the conversion
  211. sum = (6 * temp[3]) + (4 * (temp[2]+temp[4])) + (temp[1]+temp[5]);
  212. sum /= 16; // Normalize
  213. sum += 4; // Add half of shift
  214. sum = sum >> 3; // Shift out lower bits
  215. sum = sum << 3; // Shift back to normal, *8
  216. flash( sum ); // Write the flash value
  217. }
  218.  
  219. void start_adc(int sd16inctl0)
  220. {
  221. //
  222. // Configure the SD16_A to read the thermistor voltage
  223. //
  224. SD16AE = 0; // No external interfaces
  225. SD16INCTL0 = sd16inctl0; // Input control register
  226. SD16CTL = // Control register
  227. 0 + // clock divider
  228. SD16LP + // low power mode
  229. 0 + // clock divider
  230. SD16SSEL1 + // use ACLK
  231. 0 + // V(MID) buffer off (not in 2013?)
  232. SD16REFON + // reference on
  233. SD16OVIE ; // enable overflow interrupt
  234. SD16CCTL0 = // Channel 0 control register
  235. SD16UNI + // unipolar mod
  236. //SD16XOSR + // extended mode, 1024 sampling
  237. SD16SNGL + // single conversion
  238. SD16OSR1 + SD16OSR0 + // 32 oversampling
  239. 0 + // don't toggle on SD16MEM0 reads
  240. SD16LSBACC + // read the low order 16-bits
  241. 0 + // offset binary, not 2s complement
  242. SD16IE + // interrupt enable
  243. SD16SC ; // start conversion
  244. }
  245.  
  246. //
  247. // This is entered via a Power On Reset and the 'glue' logic includes
  248. // an invisible routine to clear the RAM. By default, the watchdog
  249. // timer re-enters this way, thus wiping out all flags and counters.
  250. //
  251. void main(void)
  252. {
  253. WDTCTL = WDTPW + WDTHOLD; // Turn off the watchdog timer, for now, no recursion
  254. //
  255. // Setup the clocks for all functions
  256. //
  257. BCSCTL3 = 0; // Use Xtal, lowest 1 pf stablity
  258. BCSCTL2 = SELM1+SELM0 + DIVM1+DIVM0 + DIVS1; // Xtal drives MCLK, /8, DCO -> SCLK
  259. //
  260. // We use DCO at 1 mHz, divided by 4, for FLASH writes.
  261. //
  262. BCSCTL1 = CALBC1_1MHZ; // Set the calibrated clock value
  263. BCSCTL1 |= DIVA1+DIVA0; // 1 mHz, Divide Xtal / 8 for ACLK
  264. DCOCTL = CALDCO_1MHZ; // Set DCO step and modulation
  265. //
  266. // Find the available FLASH memory for data storage.
  267. //
  268. #pragma segment="DATA16_C"
  269. #pragma segment="INTVEC"
  270. temp_cnt = (unsigned int) __segment_end("DATA16_C"); // Grab the last byte
  271. temp_cnt += 1; // Move up one
  272. temp_cnt &= 0xfffe; // Round to word boundry
  273. temp_begin = (unsigned int *) temp_cnt; // Point to first FLASH word
  274. temp_cnt = (unsigned int) __segment_begin("INTVEC") - temp_cnt; // Remember the end
  275. temp_cnt /= 2; // Make it a word count
  276.  
  277. if ( temp_begin[0] == 0xffff ) // Is first flash still unused?
  278. {
  279. FCTL1 = FWKEY + WRT; // Make flash writable
  280. FCTL2 = FWKEY + FSSEL_3 + FN2; // Use SCLK, / 4
  281. FCTL3 = FWKEY ; // Turn off the locks,
  282. //
  283. // Setup the watchdog timer as an interval timer
  284. //
  285. WDTCTL = WDTPW + // Makes the watchdog work as a timer
  286. WDTSSEL + // use 32,768 kHz clock, / 32768, ~9.5 sec
  287. WDTTMSEL ; // Puts in interval time mode
  288. IE1 |= WDTIE; // Enable timer interrupts when GIE enabled
  289. //
  290. // Initialize the output LED port and go to sleep
  291. //
  292. _BIS_SR(GIE); // Enable the interrupts
  293. //
  294. // Enter the lowest possible, wait state pending interrupt(s).
  295. //
  296. P1DIR |= 0xFF; // Avoid floating pins drain, set unused to output
  297. P1OUT = 0x01; // Enable LED
  298. _BIS_SR(LPM3_bits); // Turn off CPU in idle loop
  299. // MCLK, SMCLK, DCO osc disabled
  300. // DC gen. disabled
  301. // ACLK remains active
  302. // LED still flashes
  303. //
  304. }
  305. else // No - report the values
  306. {
  307. int i = 0; // Counter for flash memory
  308. unsigned long sec = 0; // Counter for elapsed time
  309. union rlen rle; // Local decoder for run length
  310. unsigned int ltemp=0; // Local time
  311.  
  312. while ( temp_begin[i] != 0xffff ) // Pass through data
  313. {
  314. rle.temp = temp_begin[i]; // Pickup compressed into two bytes
  315. if ( rle.rb[1] > 0 ) // Is this a counted temperature?
  316. {
  317. printf("%ld,", sec); // Lets see the last second start
  318. sec += rle.rb[1]; // Add the seconds byte to new end time
  319. rle.rb[1] = 0; // Clear out the temp bits
  320. ltemp = rle.temp << 3; // Restore temperature
  321. printf("%d\n%ld,%d\n",
  322. ltemp, sec, ltemp); // Lets see the temperature
  323. }
  324. i += 1; // Point to next
  325. }
  326. }
  327. }
  328.  
  329. // 0xFFF4 Watchdog Timer - start temperature measurement
  330. #pragma vector=WDT_VECTOR
  331. __interrupt void wdt_vector(void)
  332. {
  333. wdt_cnt +=1; // Count ISR
  334. if ( wdt_cnt >= tcnt ) // Have we reached limit of temp array?
  335. {
  336. gausian(); // Convert the gausian array
  337. }
  338. start_adc(SD16INCH2 + SD16INCH1); // Begin temperature recording
  339. if ( temp_begin[0] == 0xffff ) // Are we still getting started?
  340. {
  341. P1OUT ^= 0x01; // Flash LED to other state
  342. }
  343. else
  344. {
  345. P1OUT = 0; // Everything off
  346. }
  347. }
  348.  
  349. // 0xFFEA Sigma Delta ADC
  350. #pragma vector=SD16_VECTOR
  351. __interrupt void sd16_vector(void)
  352. {
  353. sd16_cnt +=1; // Count ISR
  354. int i; // Counter for data shifts
  355.  
  356. SD16IV = 0; // Suppress recursive interrupt
  357. i = SD16INCTL0 & (SD16INCH2+SD16INCH1+SD16INCH0) ; // Get the source bits
  358.  
  359. if ( i == (SD16INCH2+SD16INCH1+SD16INCH0) ) // Was this a zero request?
  360. {
  361. temp[0] = temp[0] - SD16MEM0; // Adjust for zero
  362. temp[0] /= 4; // Scale to 0.1F
  363. temp[0] -= 4516; // Offset to base for 32 F.
  364. temp[0] += 4; // Add half of shift
  365. temp[0] = temp[0] >> 3; // Shift out lower bits
  366. temp[0] = temp[0] << 3; // Shift back to normal, *8
  367.  
  368. for (i=tcnt-1; i > 0; i--) // Pass through existing array
  369. {
  370. temp[i] = temp[i-1]; // Shift all values up
  371. }
  372.  
  373. temp[0] = 0; // Clear the low
  374. }
  375. else // No, assume a data request
  376. {
  377. temp[0] = SD16MEM0; // Get the value
  378. start_adc(SD16INCH2 + SD16INCH1 + SD16INCH0); // Get the zero to adjust
  379. }
  380. }
  381.  
  382. // End of code segment?
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement