Temperature Logger

I’ve experienced some interesting temperature changes in my lifetime including one just a few years ago where we set a record high one day and then set a record low the next day.  The most interesting one I experienced was a long time ago while I was in Sondrestrom, Greenland.  The temperatures would typically get down to -40F during the winter so every building had hitching posts with electrical cords for plugging in the engine heaters of our vehicles.  There is also a phenomenon in that part of the world known as Foehn winds that can raise the temperature almost 60 degrees in less than an hour.  The location I was at saw the temperature go from -40F to +40F in less than 24 hours.  That’s all just a long introduction to this episode where we build on two previous posts by adding a sensor to our PIC to create a simple temperature data logger.

Temperature Sensors

There are a variety of temperature sensors out there that can be used to interface to a microcontroller.  The simplest one is a thermistor which basically changes resistance in a consistent fashion based on changes in temperature.  They are relatively inexpensive and can even be scrounged from some old computer fans.  The down side is that the resistance change is not linear so it requires a bit of software finagling.  At the other end of the spectrum are ready-made sensor modules that calculate the temperature and then send the data out as a serial bit stream.  They also take a bit of software wrangling to perform the serial setup and decoding.  What we will use in this project is kind of in between those two extremes.  These devices calculate the temperature for us and the output is linear.  The most common ones put out 10mv per degree and they come in a small, transistor sized package with three leads.

There are basically three categories of these temperature sensors: Kelvin, Celsius, and Fahrenheit.  Within each category you can usually find a couple of different temperature ranges.  Mostly we would be interested in the Celsius and Fahrenheit models with the choice of temperature range based on our needs.  The two models you will likely find are the LM34 (Fahrenheit) and the LM35 (Celsius).  The letters appended to those model numbers dictate the temperature range.  Generally speaking, if the first letter is “D” (e.g.: LM34DZ) then the range goes from freezing to boiling (+32F to +212F, or 0C to +100C).  If the first letter starts with “C” then the range extends below the freezing point.  When I was shopping for sensors I found that the LM35DZ (Celsius, 0 to +100) was the cheapest and easiest to find while the LM34CZ (Fahrenheit, -40 to +230) was the most expensive.  It is also important to note that the practical lower end for the LM34CZ with a single positive power supply is +5F.  That should be good enough for most simple hobby applications.



This diagram uses the same long time delay circuit that we talked about in the post on the PIC Wake-up Feature.  Again, the capacitor value depends on your application.  The timeout is approximately 30ms per nano-farad at 5 volts so our calculated timeout here is about 23.5 minutes.  That value would allow us to record a maximum of 255 data points in EEPROM over a time period of almost 100 hours (4+ days).  Again, make sure you use a tantalum capacitor for values above 1uf to avoid reduced timeouts due to leakage current.

The LM3x device connects to power and ground with the analog output fed to an analog input of the PIC.  We will see in the software section that the PIC has that input configured to perform an A/D (analog to digital) conversion each time the PIC wakes up from sleep mode.  The potentiometer value is not critical (10k should work) or it can be replaced by a simple resistor voltage divider.  The idea is to set the input on pin 5 (11) to about 2.5 volts without exceeding 2.55 volts.  That will allow the A/D conversion to output one bit per 10mv of input to match our temperature sensor output of 10mv per degree.  In keeping with our low power goal, one side of the potentiometer is powered by the PIC only when taking a temperature measurement.  The power for the sensor is also controlled by the PIC.  The sensor output voltage settles within 20us so that’s less than 1 instruction cycle when we use the PIC internal 31-kHz clock.

Because we are using a PIC I/O pin to power the potentiometer for the voltage reference, we will need to first set it using the PIC power supply.  Just take the side of the potentiometer that will later be connected to PIC pin 5 (11) and connect it to the V+ that will be applied to PIC pin 1 instead.  Set the 2.5 volts and then you can connect the potentiometer to PIC pin 5 (11).  The output on that pin should be pretty close to the supply voltage.

The ground connection to pin 2 is used as an enable in the software.  That was required because the PIC actually runs while it is sitting in a powered up programmer like the Pickit3.  That can cause a problem when we read the stored temperature values because the PIC will start overwriting EEPROM if we don’t prevent it in software.

You will also note in the diagram that the PIC can be either one of the two versions we have been using in these episodes.  The top half of the 16F688 exactly matches the eight pins of the 12F683 so you can use either one in applications that only require six or fewer I/O ports.  You might even want to build your circuit with a 14-pin socket even if you plan to use the 12F683.  That way you won’t have to rewire those eight pins if you later decide to drop in a 16F688.


The software links are listed below.  I have included ones for both the 12F683 and the 16F688.  The differences are mostly in a few register names along with the expected differences in the PIC version (LIST=) and the INCLUDE file line and the __CONFIG line.

As noted earlier, the software baseline is the one we used in Episode 7 for the long sleep periods.  In addition, the EEPROM write code from Episode 6 was added.  In the 12F683 version the line “BCF EECON1,  EEPGD” is commented out because it only applies to the 16F688.  That line is not used in the 12F683 code because the EEPGD bit is not present in the EECON1 register.  The 12F683 only allows writes to EEPROM and not to program memory.  Most of the rest of the new code deals with the A/D converter setup and usage.  Once the proper registers are set up in the Init code, the conversion only requires a pair of flags to be set.  That is all done inside of the interrupt handler when the PIC wakes up.  You can also see the points where the power is turned on and off for the temperature sensor and the Vref potentiometer.  There is also an endless loop in the last part of the Init routine if the Enable pin described in the Hardware step is not grounded.  That prevents the EEPROM from being overwritten when it is sitting in the Pickit3 programmer.

One new twist in the code is the use of an expanded lookup table at a specified address to translate the A/D values into temperature values.  When using lookup tables like this you need to make sure that the table boundary doesn’t cross a page boundary.  Pages are defined as starting every 256 bytes (100 hex).  In this example we purposely start the lookup table code at a high page boundary (700 hex).  In order to calculate the CALL address for this code we copy the upper bits of the table address into register PCLATH.  Those address bits then get used by the PIC when calculating the location of the lookup table code.  That’s something you don’t need to worry about when using a high-level language like C because the compiler automatically adds the needed instructions for you.  It is also something you don’t normally need to worry about when using microcontrollers or microprocessors that have a full 16-bit address capability.

There are two other things to note about the lookup table.  Since we are restricting our temperature readouts to two digits for convenience, the digits from 100 to 109 degrees use an ASCII “A” for the decimal equivalent of “10”.  The other thing to keep in mind is that each entry in the table takes two bytes of memory.  One byte is for the RETLW instruction and one byte is for the returned value.  To keep within our page limit of 255 bytes we can’t exceed 127 entries.


Reading Data

Ok, so we get everything built and running but how do we get the logged data out of the PIC?  With the 16F688 we could add a serial interface or even the Bluetooth interface described in an earlier episode.  For this project we will keep in simple and just use the capabilities of our Pickit3 programmer and the MPLAB X IDE.  We are already familiar with the button to download (program) the software into the PIC, but right next to that button is one for uploading from the PIC.  If you click on the arrow alongside of that button you can see the options for which parts of memory you want to retrieve.  The bottom option is for the EEPROM.  When you click on that, it will pop up a window that allows you to determine the name and destination of the hex file.  The file that is created can be read using Windows Notepad and is formatted like this:


The actual data values logged start on line 2.  There are a total of 32 lines of data with 8 values on each line.  The first value on each line starts at position 8.  The data entries are logged as 16-bit values but the leading two zeros are not applicable because the EEPROM is only 8-bits wide.  The last four numbers on each data line are a checksum and can be ignored.  The lookup table in the software specifically sets the values with the knowledge that the hex file will convert them to ASCII.  In the sample above the temperatures recorded on the first line are 73, 73, 72, 72, etc.  That’s it for this post.  Check out my other electronics projects.