Contiki 2.6

temp.c

Go to the documentation of this file.
00001 /*
00002  *  Copyright (c) 2008  Swedish Institute of Computer Science
00003  *  All rights reserved.
00004  *
00005  *  Redistribution and use in source and binary forms, with or without
00006  *  modification, are permitted provided that the following conditions are met:
00007  *
00008  *  * Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  *  * Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in
00012  *    the documentation and/or other materials provided with the
00013  *    distribution.
00014  *  * Neither the name of the copyright holders nor the names of
00015  *    contributors may be used to endorse or promote products derived
00016  *    from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028  * POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 /**
00031  * \file
00032  *
00033  * \brief
00034  *      Driver for the on board temperature sensor.
00035  *
00036  * \author
00037  *      Mike Vidales mavida404@gmail.com
00038  *
00039  */
00040 
00041 #include "key.h"
00042 #include "temp.h"
00043 #include "lcd.h"
00044 
00045 /**
00046  *  \addtogroup lcd
00047  *  \{
00048 */
00049 
00050 /** Type used together with find_temp() to find temperature */
00051 typedef enum {
00052     TEMP_ZERO_OFFSET_CELCIUS    = -15,
00053     TEMP_ZERO_OFFSET_FAHRENHEIT =   0
00054 } temp_zero_offset_t;
00055 
00056 #if defined( DOXYGEN )
00057 static uint16_t temp_table_celcius[];
00058 static uint16_t temp_table_fahrenheit[];
00059 #else  /* !DOXYGEN */
00060 /** Celcius temperatures (ADC-value) from -15 to 60 degrees */
00061 static uint16_t temp_table_celcius[] PROGMEM = {
00062     923,917,911,904,898,891,883,876,868,860,851,843,834,825,815,
00063     806,796,786,775,765,754,743,732,720,709,697,685,673,661,649,
00064     636,624,611,599,586,574,562,549,537,524,512,500,488,476,464,
00065     452,440,429,418,406,396,385,374,364,354,344,334,324,315,306,
00066     297,288,279,271,263,255,247,240,233,225,219,212,205,199,193,
00067     187,
00068 };
00069 
00070 /** Fahrenheit temperatures (ADC-value) from 0 to 140 degrees */
00071 static uint16_t temp_table_fahrenheit[] PROGMEM = {
00072     938, 935, 932, 929, 926, 923, 920, 916, 913, 909, 906, 902, 898,
00073     894, 891, 887, 882, 878, 874, 870, 865, 861, 856, 851, 847, 842,
00074     837, 832, 827, 822, 816, 811, 806, 800, 795, 789, 783, 778, 772,
00075     766, 760, 754, 748, 742, 735, 729, 723, 716, 710, 703, 697, 690,
00076     684, 677, 670, 663, 657, 650, 643, 636, 629, 622, 616, 609, 602,
00077     595, 588, 581, 574, 567, 560, 553, 546, 539, 533, 526, 519, 512,
00078     505, 498, 492, 485, 478, 472, 465, 459, 452, 446, 439, 433, 426,
00079     420, 414, 408, 402, 396, 390, 384, 378, 372, 366, 360, 355, 349,
00080     344, 338, 333, 327, 322, 317, 312, 307, 302, 297, 292, 287, 282,
00081     277, 273, 268, 264, 259, 255, 251, 246, 242, 238, 234, 230, 226,
00082     222, 219, 215, 211, 207, 204, 200, 197, 194, 190, 187,
00083 };
00084 #endif /* !DOXYGEN */
00085 
00086 /** Flag indicating initialized or not */
00087 bool temp_initialized = false;
00088 
00089 /** \brief          Find array index corresponding to input ADC value
00090  *
00091  *                  Returned array index is actual temperature + zero offset. To
00092  *                  get actual temperature, the zero offset (\ref temp_zero_offset_t)
00093  *                  has to be subtracted.
00094  *
00095  * \param[in]           value                   Value to seracah for in table
00096  * \param[in]           array                   Pointer to array in which to look for ADC value
00097  * \param[in]           count                   Size of array
00098  *
00099  *
00100  * \return                              EOF on error
00101  */
00102 static int find_temp(int16_t value, uint16_t* array, int count);
00103 
00104 /*---------------------------------------------------------------------------*/
00105 
00106 /**
00107  *   \brief This will initialize the digital IO and adc channel for temperture readings.
00108  *   Optionally enable adc channel 2 for measurement of EXT_SUPL_SIG.
00109  *
00110  *   \retval 0 Place holder for returning status.
00111 */
00112 int
00113 temp_init(void)
00114 {
00115     /* Disable the Digital IO for the analog readings. */
00116     DIDR0 |= (1 << ADC4D);
00117 
00118     /* Temp sens power pin as output */
00119     TEMP_DDR |= (1 << TEMP_BIT_PWR);
00120 
00121     /* Power off temp sensor */
00122     TEMP_PORT &= ~(1 << TEMP_BIT_PWR);
00123 
00124     /* Temp sens input, no pullup */
00125     TEMP_DDR &= ~(1 << TEMP_BIT_IN);
00126     TEMP_PORT &= ~(1 << TEMP_BIT_IN);
00127 
00128 #if MEASURE_ADC2
00129     DIDR0 |= (1 << ADC2D);
00130     TEMP_DDR &= ~(1 << 2);
00131     TEMP_PORT &= ~(1 << 2);
00132 #endif   
00133 
00134     temp_initialized = true;
00135 
00136     return 0;
00137 }
00138 
00139 /*---------------------------------------------------------------------------*/
00140 
00141 /**
00142  *   \brief This will disable temperature readings by reseting the initialed flag.
00143 */
00144 void
00145 temp_deinit(void)
00146 {
00147     temp_initialized = false;
00148 }
00149 
00150 /*---------------------------------------------------------------------------*/
00151 
00152 /**
00153  *   \brief This will turn on the adc channel for reading the temp sensor.
00154  *
00155  *   After the raw adc value is stored, it will be used to lookup a degree conversion
00156  *   based on the tables for F or C.
00157  *   Optionally, EXT_SUPL_SIG is also read on channel 2 and stored in the global
00158  *   ADC2_reading for subsequent transfer to the 1284p web server.
00159  *
00160  *   \param unit Used to determine what unit needs to be appended with the value.
00161  *
00162  *   \return EOF This is an uninitialized adc error.
00163  *   \retval temp The newly converted value in degrees F or C.
00164 */
00165 #if MEASURE_ADC2
00166 uint16_t ADC2_reading;
00167 #endif
00168 
00169 int16_t
00170 temp_get(temp_unit_t unit)
00171 {
00172     int16_t res;
00173     int16_t temp;
00174 
00175     /* Return if temp sensor driver not initialized */
00176     if (temp_initialized == false) {
00177         return EOF;
00178     }
00179 
00180     /* Power up sensor */
00181     TEMP_PORT |= (1 << TEMP_BIT_PWR);
00182 
00183     /* Init ADC and measure */
00184     adc_init(ADC_CHAN_ADC4, ADC_TRIG_FREE_RUN, ADC_REF_AVCC, ADC_PS_128);
00185     adc_conversion_start();
00186     while ((res = adc_result_get(ADC_ADJ_RIGHT)) == EOF ){
00187         ;
00188     }
00189     
00190 #if MEASURE_ADC2
00191     /* Measure external voltage supply, routed to ADC2 through a 470K/100K divider*/
00192     /* AVCC is 3.3 volts if using external supply, else Vbat which will be lower */
00193     /* Convert result to millivolts assuming AVCC is 3.3 volts, on battery it will be lower! */
00194     adc_init(ADC_CHAN_ADC2, ADC_TRIG_FREE_RUN, ADC_REF_AVCC, ADC_PS_128);
00195     adc_conversion_start();
00196     while ((ADC2_reading = adc_result_get(ADC_ADJ_RIGHT)) == EOF ){
00197         ;
00198     }
00199     ADC2_reading = (ADC2_reading*((470+100)*3300UL))/(100*1024UL);
00200 #endif
00201  
00202    adc_deinit();
00203     /* Re-init the adc for buttons. */
00204     key_init();
00205 
00206     /* Power down sensor */
00207     TEMP_PORT &= ~(1 << TEMP_BIT_PWR);
00208 
00209     /* Get corresponding temperature from table */
00210     if (unit == TEMP_UNIT_CELCIUS) {
00211         temp = find_temp(res, temp_table_celcius, sizeof(temp_table_celcius)/sizeof(int)) + TEMP_ZERO_OFFSET_CELCIUS;
00212     } else /*unit == TEMP_UNIT_FAHRENHEIT*/{
00213         temp = find_temp(res, temp_table_fahrenheit, sizeof(temp_table_fahrenheit)/sizeof(int)) + TEMP_ZERO_OFFSET_FAHRENHEIT;
00214     }
00215 
00216     return temp;
00217 }
00218 
00219 /*---------------------------------------------------------------------------*/
00220 
00221 /**
00222  *   \brief Find array index corresponding to input ADC value
00223  *
00224  *   Returned array index is actual temperature + zero offset. To
00225  *   get actual temperature, the zero offset (\ref temp_zero_offset_t)
00226  *   has to be subtracted.
00227  *
00228  *   \param[in] value Value to search for in table
00229  *   \param[in] array Pointer to array in which to look for ADC value
00230  *   \param[in] count Size of array
00231  *
00232  *   \return         EOF on error
00233 */
00234 static int
00235 find_temp(int16_t value, uint16_t* array, int count)
00236 {
00237     int i = 0;
00238     int table_val = 0;
00239     do{
00240         table_val = pgm_read_word(&array[i]);
00241         if (table_val < value) {
00242             return i;
00243         }
00244     } while(++i<count);
00245     return EOF;
00246 }
00247 
00248 /** \} */