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 Companys 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 ********************************************************/ |