Rev Author Line No. Line
1661 kaklik 1 /*********************************************************************
2 *
3 * Thermo Sensor
4 *
5 *********************************************************************
6 * FileName: temperature.c
7 * Dependencies: See INCLUDES section below
8 * Processor: PIC18
9 * Compiler: C18 2.30.01+
10 * Company: Microchip Technology, Inc.
11 *
12 * Software License Agreement
13 *
14 * The software supplied herewith by Microchip Technology Incorporated
15 * (the “Company”) for its PICmicro® Microcontroller is intended and
16 * supplied to you, the Company’s customer, for use solely and
17 * exclusively on Microchip PICmicro Microcontroller products. The
18 * software is owned by the Company and/or its supplier, and is
19 * protected under applicable copyright laws. All rights are reserved.
20 * Any use in violation of the foregoing restrictions may subject the
21 * user to criminal sanctions under applicable laws, as well as to
22 * civil liability for the breach of the terms and conditions of this
23 * license.
24 *
25 * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
26 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
27 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
28 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
29 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
30 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
31 *
32 ********************************************************************/
33  
34 /** I N C L U D E S **********************************************************/
35 #include "Compiler.h"
36 #include "GenericTypeDefs.h"
37 #include "HardwareProfile.h"
38 #include "temperature.h"
39  
40 #if defined(__18CXX)
41 #include <spi.h>
42 #endif
43  
44 /** V A R I A B L E S ********************************************************/
45 #pragma udata
46 unsigned int I2CStateVariable; // Used for keeping track of the I2C state
47 // machine when using the HPC Explorer board's
48 // I2C based TC74 temperature sensor.
49 signed char TempAccumulator; // Used for averaging temperature samples
50 signed char TempSave;
51 WORD_VAL temperature; // Raw data format
52 char tempString[10]; // Buffer for storing data in ASCII format
53  
54 /** P R I V A T E P R O T O T Y P E S ***************************************/
55  
56 /** D E C L A R A T I O N S **************************************************/
57 #pragma code
58 /******************************************************************************
59 * Function: void InitTempSensor(void)
60 *
61 * PreCondition: None
62 *
63 * Input: None
64 *
65 * Output: None
66 *
67 * Side Effects: None
68 *
69 * Overview: Initializes SPI interface & chip select line
70 *
71 * Note: None
72 *****************************************************************************/
73 void InitTempSensor(void)
74 {
75 #if defined(PICDEM_FS_USB)
76 cs_temp_sensor = 1;
77 tris_cs_temp_sensor = OUTPUT_PIN;
78 OpenSPI(SPI_FOSC_64, MODE_11, SMPMID);
79  
80 // Initialize readable values - default to room temperature
81 temperature.Val = 0x0C87; // 25 degree celsius
82 UpdateCelsiusASCII();
83  
84 #elif defined(PIC18F87J50_PIM)
85 temperature.Val = 0x0C87; // 25 degree celsius
86 UpdateCelsiusASCII();
87  
88 //Need to initialize I2C Module to prepare for communication with
89 //TC74 temperature sensor on the HPC Explorer board.
90 mInitI2CPins(); // See io_cfg.h
91 SSP1STAT = 0xC0; // Slew rate control disabled, SMBus
92 SSP1CON1 = 0x08; // I2C Master mode
93 SSP1CON2 = 0x00;
94 SSP1ADD = 0x7D; // Just under 100kHz at 48MHz core frequency
95 SSP1CON1bits.SSPEN = 1; // Enable MSSP module
96  
97 I2CStateVariable = 0; // Initial state for I2C state machine
98  
99 #endif
100 }//end InitTempSensor
101  
102 /******************************************************************************
103 * Function: void AcquireTemperature(void)
104 *
105 * PreCondition: None
106 *
107 * Input: None
108 *
109 * Output: None
110 *
111 * Side Effects: None
112 *
113 * Overview: None
114 *
115 * Note: None
116 *****************************************************************************/
117 BOOL AcquireTemperature(void)
118 {
119 #if defined(PICDEM_FS_USB)
120 //The PICDEM FS USB Demo Board uses a TC77 (13 bit) temperature sensor and
121 //communicates with it through the SPI interface.
122 cs_temp_sensor = 0;
123 temperature.v[1] = ReadSPI();
124 temperature.v[0] = ReadSPI();
125 cs_temp_sensor = 1;
126  
127 if(temperature.bits.b2 == 0)
128 return FALSE;
129  
130 #elif defined(__C30__) || defined(__C32__)
131  
132 //Create temp variables to store the conversion data
133 float temp;
134  
135 //get ready to sample the A/D
136  
137 #if defined(__C30__)
138 AD1CHS = 0x4; //MUXA uses AN4
139 AD1PCFGLbits.PCFG4 = 0;
140 for(temp=0;temp<1000;temp++); //Sample delay
141 // Get an ADC sample
142 AD1CON1bits.SAMP = 1; //Start sampling
143 for(temp=0;temp<1000;temp++); //Sample delay, conversion start automatically
144 AD1CON1bits.SAMP = 0; //Start sampling
145 for(temp=0;temp<1000;temp++); //Sample delay, conversion start automatically
146 while(!AD1CON1bits.DONE); //Wait for conversion to complete
147  
148 #else
149 AD1PCFGbits.PCFG4 = 0;
150  
151 AD1CON1 = 0x0000; // SAMP bit = 0 ends sampling ...
152 // and starts converting
153 AD1CHS = 0x00040000; // Connect RB4/AN4 as CH0 input ..
154 // in this example RB2/AN2 is the input
155 AD1CSSL = 0;
156 AD1CON3 = 0x0002; // Manual Sample, Tad = internal 6 TPB
157 AD1CON2 = 0;
158 AD1CON1SET = 0x8000; // turn ADC ON
159  
160 AD1CON1SET = 0x0002; // start sampling ...
161 for(temp=0;temp<1000;temp++); //Sample delay, conversion start automatically
162 AD1CON1CLR = 0x0002; // start Converting
163 while (!(AD1CON1 & 0x0001));// conversion done?
164 #endif
165  
166 //convert the results to a float
167 temp = (float)ADC1BUF0;
168  
169 // voltage = A2D_reading * 3.3v / 1024
170 temp *= 3.3;
171 temp /= 1024;
172  
173 // align to 0C (subtracting -.65v)
174 temp -= .55;
175  
176 //convert to TC77 style output and store to temperature
177 temp *= 12800;
178 temperature.Val = (WORD)temp;
179 temperature.Val |= 0x7;
180  
181 //#elif defined(__C32__)
182 //#warning "TODO"
183 #elif defined(PIC18F87J50_PIM) // Uses TC74 (8 bit)
184 //The PIC18F87J50 FS USB Plug-In Module (PIM) does not have a temperature
185 //sensor, but there is a TC74 (8 bit) I2C based temperature sensor on the
186 //HPC Explorer demo board. In order for this temperature demo code to do
187 //anything useful, the PIM should be used in conjunction with the HPC Explorer.
188 //The TC74 comes in 5V and 3.3V optimized versions. If a 5V part is run at
189 //3.3V (as with the PIM installed), it may have relatively large offsets.
190 return TRUE; // Don't need to do anything in this function, temperature
191 // polling with the PIC18F87J50 FS USB Plug-In Module is
192 // done with the PollTempOnHPCExplorer() function.
193 // This is done so the I2C communication can be done with
194 // a non-blocking approach.
195 #elif defined(LOW_PIN_COUNT_USB_DEVELOPMENT_KIT)
196 temperature.Val = 0x0000;
197 return TRUE;
198 #elif defined(PIC18F46J50_PIM)
199 //Create temp variables to store the conversion data
200 float temp;
201  
202 //get ready to sample the A/D
203 ADCON0bits.CHS = 0x07;
204 for(temp=0;temp<1000;temp++){}
205 ADCON0bits.GO = 1; // Start AD conversion
206 while(ADCON0bits.NOT_DONE); // Wait for conversion
207  
208 //convert the results to a float
209 temp = (float)ADRES;
210  
211 // voltage = A2D_reading * 3.3v / 1024
212 temp *= 3.3;
213 temp /= 1024;
214  
215 // align to 0C (subtracting -.65v)
216 temp -= .55;
217  
218 //convert to TC77 style output and store to temperature
219 temp *= 12800;
220 temperature.Val = (WORD)temp;
221 temperature.Val |= 0x7;
222  
223 return TRUE;
224 #else
225 #error "Unknown temperature acquire configuration. See AcquireTemperature function in __FILE__"
226 #endif
227 return TRUE;
228 }//end AcquireTemperature
229  
230 /******************************************************************************
231 * Function: void PollTempOnHPCExplorer(void)
232 *
233 * PreCondition: None
234 *
235 * Input: None
236 *
237 * Output: Temperature data from TC74 on HPC Explorer, but formatted
238 * like the TC77, stored in the "temperature" variable.
239 * Side Effects: None
240 *
241 * Overview: None
242 *
243 * Note: None
244 *****************************************************************************/
245 #if defined(PIC18F87J50_PIM)
246 void PollTempOnHPCExplorer(void)
247 {
248 //The PIC18F87J50 FS USB Plug-In Module (PIM) does not have a temperature
249 //sensor, but there is a TC74 (8 bit) I2C based temperature sensor on the
250 //HPC Explorer demo board. In order for this temperature demo code to do
251 //anything useful, the PIM must be used in conjunction with the HPC Explorer.
252 //The TC74 comes in 5V and 3.3V optimized versions. If a 5V part is run at
253 //3.3V (as with the PIM installed), it may have relatively large offsets.
254 #define TC74AddressWrite 0b10011010 // This is the default address for the TC74, use this for writes
255 #define TC74AddressRead 0b10011011 // This is the default address for the TC74, use this for reads
256 #define RTR 0x00 // This is the read temp command for TC74
257  
258 // Should not use blocking functions in USB code. Therefore, these I2C
259 // communications are done with a state machine as shown below.
260 switch(I2CStateVariable)
261 {
262 case 0x00:
263 PIR1bits.SSP1IF = 0;
264 SSP1CON2bits.SEN = 1; // Send Start Bit
265 I2CStateVariable = 0x01;
266 break;
267 case 0x01:
268 if(PIR1bits.SSP1IF == 0) {break;}
269 PIR1bits.SSP1IF = 0;
270 SSP1BUF = TC74AddressWrite; // Begin sending the actual address
271 I2CStateVariable = 0x02;
272 break;
273 case 0x02:
274 if(PIR1bits.SSP1IF == 0) {break;}
275 PIR1bits.SSP1IF = 0;
276 SSP1BUF = RTR; // Send command to select the TEMP register
277 I2CStateVariable = 0x03;
278 break;
279 case 0x03:
280 if(PIR1bits.SSP1IF == 0) {break;}
281 PIR1bits.SSP1IF = 0;
282 SSP1CON2bits.SEN = 1; // Send another start bit
283 I2CStateVariable = 0x04;
284 break;
285 case 0x04:
286 if(PIR1bits.SSP1IF == 0) {break;}
287 PIR1bits.SSP1IF = 0;
288 SSP1BUF = TC74AddressRead; // Send the address again, but this time "read"
289 I2CStateVariable = 0x05;
290 break;
291 case 0x05:
292 if(PIR1bits.SSP1IF == 0) {break;}
293 PIR1bits.SSP1IF = 0;
294 SSP1CON2bits.RCEN = 1; // Initiate read from device
295 I2CStateVariable = 0x06;
296 break;
297 case 0x06:
298 if(PIR1bits.SSP1IF == 0) {break;}
299 PIR1bits.SSP1IF = 0;
300 TempSave = SSP1BUF; // Finally got the result, need to save it
301 SSP1CON2bits.ACKDT = 1; // Prepare I2C NACK handshake
302 SSP1CON2bits.ACKEN = 1; // Send the acknowledge bit
303 I2CStateVariable = 0x07;
304 break;
305 case 0x07:
306 if(PIR1bits.SSP1IF == 0) {break;}
307 PIR1bits.SSP1IF = 0;
308 SSP1CON2bits.PEN = 1; // Now send a stop bit
309 I2CStateVariable = 0x08;
310 break;
311 case 0x08:
312 if(PIR1bits.SSP1IF == 0) {break;}
313 PIR1bits.SSP1IF = 0;
314 I2CStateVariable = 0x09;
315 break;
316 case 0x09:
317 TempAccumulator = ((TempAccumulator + TempSave) / 2); // Get an average
318 I2CStateVariable = 0x10;
319 break;
320 case 0x10:
321 //Now format data like that of the TC77, which is what the PC side code expects,
322 //since it was originally intended to be used with the TC77.
323 temperature.v[1] = TempAccumulator;
324 if(temperature.bits.b15 == 0) // == 0 when positive temperature
325 {
326 temperature.Val = temperature.Val >> 1;
327 temperature.bits.b15 = 0; // Positive temperature, upper MSb clear
328 }
329 else
330 {
331 temperature.Val = temperature.Val >> 1;
332 temperature.bits.b15 = 1; // Negative temperature, upper MSb set
333 }
334 temperature.bits.b0 = 1; // Lower three LSbs = 1 on TC74 format
335 temperature.bits.b1 = 1; // Lower three LSbs = 1 on TC74 format
336 temperature.bits.b2 = 1; // Lower three LSbs = 1 on TC74 format
337  
338 I2CStateVariable = 0x11; // Could go back to 0, but don't want to poll that fast
339 break;
340 case 0x5000: // This slows down the sample rate of the device.
341 I2CStateVariable = 0x00; // The temp sensor itself only updates around 8 times/sec.
342 break;
343 default:
344 I2CStateVariable++;
345 break;
346 }//end switch
347 }//end PollTempOnHPCExplorer
348 #endif
349  
350 /******************************************************************************
351 * Function: void UpdateCelsiusASCII(void)
352 *
353 * PreCondition: None
354 *
355 * Input: None
356 *
357 * Output: None
358 *
359 * Side Effects: None
360 *
361 * Overview: This routine converts data output to ASCII string
362 *
363 * Note: None
364 *****************************************************************************/
365 void UpdateCelsiusASCII(void)
366 {
367 WORD_VAL temp;
368 BYTE i;
369  
370 temp.Val = temperature.Val >> 3;
371  
372 if(temp.bits.b12 == 0)
373 {
374 temp.byte.HB &= 0x1F;
375 tempString[0] = '+';
376 }
377 else
378 {
379 temp.byte.HB |= 0xE0;
380 tempString[0] = '-';
381 temp.Val = temp.Val ^ 0xFFFF; // Negate
382 temp.Val++;
383 }//end if
384  
385 temp.Val = (temp.Val*10U) >> 4; // Turn into celsius xx.x
386  
387 /* Populate string */
388 for(i=4;i>0;i--)
389 {
390 tempString[i] = (((char)(temp.Val % 10)) & 0x0F) | 0x30;
391 temp.Val /= 10;
392 }//end for
393  
394 /* Turn leading zeros into spaces */
395 if(tempString[1] == '0')
396 {
397 tempString[1] = ' ';
398 if(tempString[2] == '0')
399 tempString[2] = ' ';
400 }//end if
401  
402 /* Adjust decimal digit */
403 tempString[5] = tempString[4];
404 tempString[4]='.';
405 tempString[6]=0xF8; // Degree symbol
406 tempString[7]='C';
407 tempString[8]='\r';
408 tempString[9]=0x00; // Null-Terminated
409  
410 }//end UpdateCelsiusASCII
411  
412 /** EOF temperature.c ********************************************************/