brid0030
- 21st September 2010, 17:08
I am working on some tiny dataloggers--these things weigh less than a raisin--and I have had great success with several PICs (12Fs and 16F688). To miniaturize things even more, I've been trying to use a PIC10F222, but I fear there just is not enough code space. I have written some code that might work (I have tested all the components of code) but I am short about 100 words or so when I put it all together. I am contemplating dealving into assembly to save some space, but I wonder if the PIC10 data logger will work even then. I am hoping that if I post my code here, some of you could give it a glance and suggest some shortcuts and/or give me some insight as to whether using assembly could make this project possible.
The device is pretty simple. It interfaces with an external EEPROM (Microchip 24AA256) and a Clock via I2C. The clock is set to emit an 'alarm' every minute which wakes the PIC from sleep. Once awake the PIC accesses the EEPROM to obtain some stored parameters (the PIC cannot retain variable in sleep mode, and sleep is absolutely necessary), does an ADC conversion from the sensor, and then stores the data in the EEPROM. Every tenth minute, an average ADC value is calculated from the sum of the 10 previous ADC operations. So every datapoint in the permanent EEPROM storage is an average over 10 minutes. More details are in comments within the code. One of the main problems is that the I2CREAD command is huge. It takes up about 150 words. Perhaps there is an assembly (or even a PBP) solution that is more efficient. I hope some of you have some suggestions. Thanks.
'This program runs the PIC10f222 on a tiny geolocator module.
'The device makes an ADC reading once a minute. Every 10 minutes, when the
'minutes value ends with a 9, it stores an average of the last 10 ADC
'values to the MICROCHIP 24AA256 EEPROM. ADC values are 7 bits
'(range 0 to 127)
'The device should not log data at certain times (middle of day and middle
'of night). Logging is controlled by IF/THEN statements dependent on
'the minute counter.
'
'PARAMETER STORAGE:
'ADC SUM (max value 1270) in EEPROM BYTES 31982 and 4 high bits of 32983
'Minute counter (max value 1440) stored in EEPROM BYTES 31984 and
'4 low bits of 32983
'MEM address (max ~32000) in EEPROM BYTES 31985-31986
'the initital start time is stored in EEPROM BYTES 31987 to 31992.
'Memory testing EEPROM BYTE 31993
'No date skipping
'
'DATA STORAGE
'first EEPROM memory address for data storage is 0. Last address is 31980
'_________________________________________________
'
DEFINE ADC_SAMPLEUS 100 'Sampling time for ADC
DEFINE I2C_SCL GPIO,2
DEFINE I2C_SDA GPIO,0
'
'Alias pins
INT VAR GPIO.3 'interupt (wake-up) pin (pin 6, input only)
SDA VAR GPIO.0 'I2C DATA PIN (pin 1),
SCL VAR GPIO.2 'I2C CLOCK PIN (pin 4)
LIGHT Var GPIO.1 'INPUT FROM LIGHT SENSOR (pin 3)
'
'Need 6 byte variables, Soft stack set to 1 byte, RR1 and RM1
'commented out in RAM file
B0 VAR Byte[6] '6 byte array
'
'Word names aliased to Bytes using EXT
ASM
W0 = _B0 + 0
W1 = _B0 + 2
W2 = _B0 + 4
ENDASM
W0 VAR WORD EXT
W1 VAR WORD EXT
W2 VAR Word EXT
'
wake: 'The action starts here
OPTION_REG = %00000000
TRISIO = 0 'all outputs
OSCCAL.0 = 0 'must be set to zero on wake-up
ADCON0 = %00000000
'
IF INT = 1 tHEN 'Detects data collector
PAUSE 100
GOTO nolog 'loops until data collector is unplugged
ENDIF
'
W2 = 32981 'Set memory address to collect stored parameters
GOSUB readmem 'RETURNS ADC SUM, COUNTER, and EEPROM Memory address
IF W2 = 31980 Then nolog 'Stops logging when memory is full
B0[0] = B0[2]//4 'Makes W0 the ADC SUM
B0[2] = B0[2]//16 ' Makes W1 the COUNTER
IF W1 < 180 THEN nolog 'no logging before counter = 180
IF W1 > 599 THEN 'no logging between 600 and 899
IF W1 < 900 THEN nolog
ENDIF
IF W1 > 1379 THEN nolog ' no logging after counter is 1380
OPTION_REG = (W1//9) 'store ones digit of counter in OPTION_REG
IF W1 = 909 THEN 'First logging after aftenoon sleep is at counter 909
FSR.0 = 1 'Use FSR to flag this situation
ELSE
FSR.0 = 0
ENDIF
'
ADCIN 1, B0[2] 'perform ADC on channel 1 (GPIO 1) and stores in B2 or W1.Byte1
B0[2] = B0[2] / 2 'divide by 2
W0 = W0 + B0[2] 'add to ADC sum
'
IF OPTION_REG <> 0 THEN nolog 'log data only every 10 minutes
'(when ones digit of counter = 9)
B0[1] = W0 / 10 'Calculates ADC average
B0.0[15] = FSR.0 'flag bit 7 of B0[1] if waking from afternoon sleep.
'_____________________________________
'at this point:
'B0[0] = 1
'B0[1] = ADC Average
'W1 = junk
'W2 still equals EEPROM memory address
'________________________________________
GOSUB writemem 'Write only B0[1]
PAUSE 5
W2 = 32981
GOSUB readmem
W0 = 0 'clear ADC sum
B0[2] = B0[2]//16 'clear four high bits from B0[2] (calculate count as W1)
'
nolog:
W1 = W1 + 1 'add 1 to minute COUNTER
IF W1 = 1440 then W1 = 0 'reset minute count if necessary
'ROUTINE TO STORE PARAMETERS
'_____________________________________
'at this point:
'W0 = ADC SUM
'W1 = current Counter
'W2 = memory address
'________________________________________
'Repackage ADC SUM and Counter to free up B0[0]
B0[0] = B0[0] << 4 'shift bits of B0[0] over to high side
B0[2] = B0[2] + B0[0] 'add shifted bits of B0[0] to B0[2]
W2 = 32981
GOSUB writemem
'
ADCON0 = %11001100 'must be in this state for some reason
OPTION_REG = %01000000 'SET OPTION REGISTER FOR WAKE ON CHANGE
TRISIO = %00001111 'wake ups on GP3 and GP0
'PAUSE 2000
'GOTO wake
B0[0] = GPIO 'read pins to establish change state.
'....and go to sleep.
@ SLEEP
'
'SUBROUTINES
'
readmem:
I2CREAD SDA,SCL,$A0,W2,[W0,W1,W2]
RETURN
'
writemem:
B0[0] = 1 'set initial B0[0] value
writeagain:
I2CWRITE SDA,SCL,$A0,W2,[B0[B0[0]]] 'write byte designated by B0[0]
IF W2 < 31981 THEN RETURN
IF B0[0] = 3 THEN RETURN
B0[0] = B0[0] + 1
W2 = W2 + 1
GOTO writeagain
end
The device is pretty simple. It interfaces with an external EEPROM (Microchip 24AA256) and a Clock via I2C. The clock is set to emit an 'alarm' every minute which wakes the PIC from sleep. Once awake the PIC accesses the EEPROM to obtain some stored parameters (the PIC cannot retain variable in sleep mode, and sleep is absolutely necessary), does an ADC conversion from the sensor, and then stores the data in the EEPROM. Every tenth minute, an average ADC value is calculated from the sum of the 10 previous ADC operations. So every datapoint in the permanent EEPROM storage is an average over 10 minutes. More details are in comments within the code. One of the main problems is that the I2CREAD command is huge. It takes up about 150 words. Perhaps there is an assembly (or even a PBP) solution that is more efficient. I hope some of you have some suggestions. Thanks.
'This program runs the PIC10f222 on a tiny geolocator module.
'The device makes an ADC reading once a minute. Every 10 minutes, when the
'minutes value ends with a 9, it stores an average of the last 10 ADC
'values to the MICROCHIP 24AA256 EEPROM. ADC values are 7 bits
'(range 0 to 127)
'The device should not log data at certain times (middle of day and middle
'of night). Logging is controlled by IF/THEN statements dependent on
'the minute counter.
'
'PARAMETER STORAGE:
'ADC SUM (max value 1270) in EEPROM BYTES 31982 and 4 high bits of 32983
'Minute counter (max value 1440) stored in EEPROM BYTES 31984 and
'4 low bits of 32983
'MEM address (max ~32000) in EEPROM BYTES 31985-31986
'the initital start time is stored in EEPROM BYTES 31987 to 31992.
'Memory testing EEPROM BYTE 31993
'No date skipping
'
'DATA STORAGE
'first EEPROM memory address for data storage is 0. Last address is 31980
'_________________________________________________
'
DEFINE ADC_SAMPLEUS 100 'Sampling time for ADC
DEFINE I2C_SCL GPIO,2
DEFINE I2C_SDA GPIO,0
'
'Alias pins
INT VAR GPIO.3 'interupt (wake-up) pin (pin 6, input only)
SDA VAR GPIO.0 'I2C DATA PIN (pin 1),
SCL VAR GPIO.2 'I2C CLOCK PIN (pin 4)
LIGHT Var GPIO.1 'INPUT FROM LIGHT SENSOR (pin 3)
'
'Need 6 byte variables, Soft stack set to 1 byte, RR1 and RM1
'commented out in RAM file
B0 VAR Byte[6] '6 byte array
'
'Word names aliased to Bytes using EXT
ASM
W0 = _B0 + 0
W1 = _B0 + 2
W2 = _B0 + 4
ENDASM
W0 VAR WORD EXT
W1 VAR WORD EXT
W2 VAR Word EXT
'
wake: 'The action starts here
OPTION_REG = %00000000
TRISIO = 0 'all outputs
OSCCAL.0 = 0 'must be set to zero on wake-up
ADCON0 = %00000000
'
IF INT = 1 tHEN 'Detects data collector
PAUSE 100
GOTO nolog 'loops until data collector is unplugged
ENDIF
'
W2 = 32981 'Set memory address to collect stored parameters
GOSUB readmem 'RETURNS ADC SUM, COUNTER, and EEPROM Memory address
IF W2 = 31980 Then nolog 'Stops logging when memory is full
B0[0] = B0[2]//4 'Makes W0 the ADC SUM
B0[2] = B0[2]//16 ' Makes W1 the COUNTER
IF W1 < 180 THEN nolog 'no logging before counter = 180
IF W1 > 599 THEN 'no logging between 600 and 899
IF W1 < 900 THEN nolog
ENDIF
IF W1 > 1379 THEN nolog ' no logging after counter is 1380
OPTION_REG = (W1//9) 'store ones digit of counter in OPTION_REG
IF W1 = 909 THEN 'First logging after aftenoon sleep is at counter 909
FSR.0 = 1 'Use FSR to flag this situation
ELSE
FSR.0 = 0
ENDIF
'
ADCIN 1, B0[2] 'perform ADC on channel 1 (GPIO 1) and stores in B2 or W1.Byte1
B0[2] = B0[2] / 2 'divide by 2
W0 = W0 + B0[2] 'add to ADC sum
'
IF OPTION_REG <> 0 THEN nolog 'log data only every 10 minutes
'(when ones digit of counter = 9)
B0[1] = W0 / 10 'Calculates ADC average
B0.0[15] = FSR.0 'flag bit 7 of B0[1] if waking from afternoon sleep.
'_____________________________________
'at this point:
'B0[0] = 1
'B0[1] = ADC Average
'W1 = junk
'W2 still equals EEPROM memory address
'________________________________________
GOSUB writemem 'Write only B0[1]
PAUSE 5
W2 = 32981
GOSUB readmem
W0 = 0 'clear ADC sum
B0[2] = B0[2]//16 'clear four high bits from B0[2] (calculate count as W1)
'
nolog:
W1 = W1 + 1 'add 1 to minute COUNTER
IF W1 = 1440 then W1 = 0 'reset minute count if necessary
'ROUTINE TO STORE PARAMETERS
'_____________________________________
'at this point:
'W0 = ADC SUM
'W1 = current Counter
'W2 = memory address
'________________________________________
'Repackage ADC SUM and Counter to free up B0[0]
B0[0] = B0[0] << 4 'shift bits of B0[0] over to high side
B0[2] = B0[2] + B0[0] 'add shifted bits of B0[0] to B0[2]
W2 = 32981
GOSUB writemem
'
ADCON0 = %11001100 'must be in this state for some reason
OPTION_REG = %01000000 'SET OPTION REGISTER FOR WAKE ON CHANGE
TRISIO = %00001111 'wake ups on GP3 and GP0
'PAUSE 2000
'GOTO wake
B0[0] = GPIO 'read pins to establish change state.
'....and go to sleep.
@ SLEEP
'
'SUBROUTINES
'
readmem:
I2CREAD SDA,SCL,$A0,W2,[W0,W1,W2]
RETURN
'
writemem:
B0[0] = 1 'set initial B0[0] value
writeagain:
I2CWRITE SDA,SCL,$A0,W2,[B0[B0[0]]] 'write byte designated by B0[0]
IF W2 < 31981 THEN RETURN
IF B0[0] = 3 THEN RETURN
B0[0] = B0[0] + 1
W2 = W2 + 1
GOTO writeagain
end