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 /** \} */