This note focuses on using the PICAXE-18X as very inexpensive general purpose data logger. It is very simple, consisting only of the PICAXE-18X, a battery of nominally 3 - 5 VDC when logging and a sensor, most probably less than $20.00.
This example uses the onboard EEPROM (256 bytes). In the future, I plan to extend this to an external 24LC256 which will accommodate 32K bytes. However, even 256 bytes is more than adequate for many applications. Assuming one sample per hour, this is nominally ten days.
One might argue that a byte is not adequate to store a sample. However, the beauty of designing something for yourself, or for a specific application is that you can very easily tailor the design for your specific application. For example, a temperature may well range from 0.0 to 150.0 in an attic and if one desires 0.25 degree resolution, the quantities will range from 0 to 600, which exceeds the capability of a byte. But, over the course of a week, in most situations, it is not reasonable to believe the temperature will span the entire range. Most probably, 0.0 to 50.0 or 80.0 to 150.0 degrees F are more reasonable. Thus, in logging data, one might operate on the measurement such that it can be accommodated in a byte, and when displaying the data, convert back to the original measurement.
Another example is atmospheric pressure, which I feel requires a 12-bit A/D. However, it doesn't require 12-bits to store this as atmospheric pressure changes very little, perhaps 20 millibars of 1000 millibars. Thus, one might measure the pressure and then subtract 900 and save this to EEPROM. When displaying, the 900 can be added to the stored value.
In the following, only EEPROM memory locations 0 - 249 are used to store data. Locations 254 and 255 are used to determine if this is the first time the logger has been used since the firmware has been downloaded. Location 253 is used to store the current memory location where data is to be stored.
When the processor is booted, FirstTime locations, (254 and 255) are read and if they are not $55 and $aa, the values $55 and $aa are written to these locations and $00 is written to AddressPtr (253). This indicates that the next memory location to write to is $00.
Switches on Input1 and Input0 are read and the program forks to either reset the EEPROM, display the logged data or to log data.
If logging the data, the memory address to be written to is read and if this is not $00, this indicates there was a reboot during the logging mission. This may have been due to a power interruption of unknown duration. I opted to log the value $ff (255) to indicate a special event occurred. This assumes that 255 is not a valid data value. But, it is important to note that the logging mission is not reset. That is, the data prior to the loss of power remains, followed by the logging the special event, followed by the new measurements.
A measurement is performed, the value of the AddressPtr is fetched, and the measurement is written to the specified EEPROM location. The address is then incremented and written to the AddressPtr location. After 250 samples, the program discontinues logging and simply loops at LOCK.
Note that the measurement data is written first, followed by the writing of new value of the next address. Thus, if power is lost during this sequence, the only sacrifice is the current sample. There is a possibility that power may be lost while writing the next memory location to the AddressPtr and indeed, this value might be corrupted. A possible solution, which I did not implement, is to use two EEPROM locations to redundantly store the AddressPtr, and prior to logging each measurement, ascertain if they are the same, and if not, try to determine which is the more realistic. Note that if the measurement and logging is performed hourly, the 20 ms to write to the EEPROM is a very narrow window and one must weigh the probability of losing power in the narrow window against the importance of the logging mission.
In this routine, my measurement was to simply an eight bit ADC reading of a potentiometer. But, this might virtually any kind of measurement.
In this routine, I used a delay of simply 1000 ms between measurements as I did not want to wait for hours to debug my routine. One might facilitate longer delays;
' hour delay For Mi = 0 to 59 For Se = 0 to 59 Pause 1000 Next ' toggle an LED Peek $06, Z Pins = Z ^ $01 Next
I am well aware that this probably is non too accurate, but by observing the toggling of the LED each 60 seconds, the 1000 ms pause may adjusted such that it is pretty close. In the future I plan to develop an application note which illustrates how to interface with a DS1602 elapsed time counter, but here again, one must weigh the simplicity of performing the timing using software against the importance of the accuracy of measurement timing.
Note that each time a measurement is performed, an LED is blipped a single time. No one likes a device that just sits there, appearing to do nothing. Certainly, one will be very disappointed to field a logger for ten days only to find it never logged a thing. Thus, one might periodically blip an LED to be certain the design is working and then, if power is a concern, disconnect it for the bulk of the logging mission.
To dump the data, the switches on Inputs 1 and 0 are set to either 0 1 or 1 0 and the PICAXE is booted. In this program, the data is output to the terminal at 4800 baud, with 16 values per line. One can modify this, perhaps using the SerOut command at 2400 baud to meet their needs. One might use the PICAXE software or HyperTerm to read the logger.
Prior to fielding for another mission, the user should reset the memory by setting the switches to 0 0 and booting the processor. This causes the program to simply write $00 to the AddressPtr. When performing the actual mission, the switches should be set to 1 1 followed by booting the processor.
' LOG_1.Bas (PICAXE-18X) ' ' Illustrates logging data to the onboard EEPROM (256 bytes) ' ' copyright, Peter H Anderson, Baltimore, MD, May, '04 Symbol N = B0 Symbol X = B2 ' general purpose variable X and Y Symbol Y = B3 Symbol Index = B1 Symbol ADVal = B4 Symbol FirstTime0 = 254 Symbol FirstTime1 = 255 Symbol AddressPtr = 253 Main: Pause 7000 Read FirstTime0, X ' read location 254 and 255 to Read FirstTime1, Y ' determine if this is first time If X <> $55 And Y <> $AA Then FirstTime ' first time Main_1: X = Pins & $03 Branch X, (ResetEEPROM, DumpData, DumpData, Log) ' 00 Init, 01 or 10 Dump Data, 11 Log Log: Read AddressPtr, X If X = 0 Then Log_1 ' else Write X, $ff ' to indicate there was a power interruption X = X + 1 Write AddressPtr, X Log_1: GoSub Blip GoSub Measure Read AddressPtr, X Write X, ADval X = X + 1 Write AddressPtr, X If X >= 250 Then Lock ' else Pause 1000 Goto Log_1 Lock: Goto Lock: FirstTime: Write FirstTime0, $55 Write FirstTime1, $aa Write AddressPtr, $00 ' location of where data is to be stored Goto Main_1 ResetEEPROM: Write AddressPtr, 00 Goto Lock DumpData: Read AddressPtr, X If X = 0 Then NoLoggedData ' else X = X-1 Index = 0 ' used to provide newline after each 16 bytes For N = 0 to X Read N, Y ' read and display SerTxD (#Y, " ") Index = Index + 1 If Index <= 15 Then DumpData_1 ' no new line ' else SerTxD (13, 10) ' newline Index = 0 DumpData_1: Next Goto Lock NoLoggedData: SerTxD ("No Data", 13, 10) Goto Lock Measure: ReadADC 2, ADVal Return Blip: Pin0 = 1 Pause 250 Pin0 = 0 SerTxD ("Blip", 13, 10) Return