I am trying to get a temperature sensor (tmp36) working with an Attiny and if possible I would like it to run for several weeks. I have tried to power down the Attiny and it appears to be drawing only 0.2mA current when asleep, and around 4mA when awake (using a multimeter). However the CR2032 battery went from 3.24V to 2.9V in about 1.5 days. If it was really only using 0.2mA I would have thought it would go down much more slowly than this.
I wonder if it's using a lot of current every 8s when it turns on briefly and I'm not seeing this on the multimeter, or drawing a lot of current every hour when it reads the temperature or is there something else that I'm missing.
My circuit is an Attiny85 connected directly to a tmp36 temperature sensor. I have a capacitor connected across the GND and Vcc of the tmp36. Since I am using a surface mount tmp36 I also have the shutdown pin on the tmp36 pulled high (connected directly to Vcc). Otherwise there are no other connections, it's a very simple circuit and since the current normally appears to be 0.2mA I'm not sure why the battery voltage reading is going down so fast.
I am new to turning off the attiny(and still pretty new to arduino programming) and I copied most of the code for putting the arduino to sleep from here: https://folk.uio.no/jeanra/Microelectronics/ArduinoWatchdog.html (and possibly other places).
The code I have is as follows:
#include <stdlib.h>
#include <EEPROM.h>
#include <SoftwareSerial.h>
#include <avr/sleep.h> // Sleep Modes
#include <avr/power.h> // Power management
#include <avr/wdt.h> // Watchdog timer
#include <avr/interrupt.h> // Interrupts handling
// Definitions
#define rxPin 3
#define txPin 4
// 0 1 0 Internal 1.1V Voltage Reference, calling INTERNAL should set the reference voltage to 1.1
SoftwareSerial mySerial(rxPin, txPin);
int currentTime = 0;
int timeLastSaveFullTemp = 0;
int nbr_remaining;
int sensorPin = 7; // This is the 7th pin on the ATtiny85,
// it is an analog input when reading as digital call it 7? analogpintochannel function
// (On the HLT tutorial it is labelled as Pin2: Analog input 1, SCK )
float temperature = -500.00f; // Create a new float called temperature and give it the value -500 to start with
float prevTemp = -500.00f;
float tempDiff = -500.00f;
int tempAsInt = 0;
int tempDiffAsInt = 0; // create int to store temperature difference between samples
signed char tempDiffAsChar; // create char to store temp difference between samples, hopefully this saves as a 1 byte no. between -128 and 127 (will store like this on EEPROM where difference is small enough since only 1 byte) (range around -128 to 128 so can't use for temp diff greater than 10 deg)
signed char warningNextDataIsTwoBytes = 111;
int eepromAddress = 0; // initialize variable for position in eeprom to store data collected
int decideWhatToSaveFlag = 1; // Decide what to save, if this = 0 then save the temp difference as a char (1 byte), otherwise save the entire temperature as an integer.
// interrupt raised by the watchdog firing
// when the watchdog fires during sleep, this function will be executed
// remember that interrupts are disabled in ISR functions
ISR(WDT_vect)
{
// not hanging, just waiting
// reset the watchdog
wdt_reset();
}
// function to configure the watchdog: let it sleep 8 seconds before firing
// when firing, configure it for resuming program execution
void configure_wdt(void)
{
cli(); // disable interrupts for changing the registers
MCUSR = 0; // reset status register flags
// Put timer in interrupt-only mode:
WDTCR |= 0b00011000; // Set WDCE (5th from left) and WDE (4th from left) to enter config mode,
// using bitwise OR assignment (leaves other bits unchanged).
WDTCR = 0b01000000 | 0b100001; // set WDIE: interrupt enabled, 8 seconds
// clr WDE: reset disabled
// and set delay interval (right side of bar) to 8 seconds
sei(); // re-enable interrupts
}
// Put arduino to sleep.
void sleep(int ncycles)
{
nbr_remaining = ncycles; // defines how many cycles should sleep
// Set sleep to full power down. Only external interrupts or
// the watchdog timer can wake the CPU!
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
// Turn off the ADC while asleep.
power_adc_disable();
while (nbr_remaining > 0){ // while some cycles left, sleep!
// Enable sleep and enter sleep mode.
sleep_mode();
// CPU is now asleep and program execution completely halts!
// Once awake, execution will resume at this point if the
// watchdog is configured for resume rather than restart
// When awake, disable sleep mode
sleep_disable();
// we have slept one time more
nbr_remaining = nbr_remaining - 1;
}
// put everything on again
power_all_enable();
}
// the setup routine runs once when you press reset:
void setup() {
analogReference(INTERNAL); // This sets the internal ref to be 1.1V (or close to this), note that this makes 1.1V the highest voltage. The TMP36 gives 1.1V at around 55 or 60 deg so need to not put the chip in temperatures hotter than 55deg
pinMode(sensorPin, INPUT); // make pin 7 on the ATTiny an input pin
delay(1000);
configure_wdt(); // configure the watchdog
mySerial.begin(9600); // begin software serial at rate of 9600
}
// the loop routine runs over and over forever:
void loop() {
sleep(450); // sleep for a given number of cycles (here, 450 * 8 seconds = 60mins) in lowest power mode
currentTime = currentTime + 60; // add 60 min to current time
if((eepromAddress<=510)) // the eeprom still has space
{
/***********Get temperature from sensor, then calculate difference since previous reading****************/
//Earlier set the reference voltage for the analog to digital converter to 1.1V. This means a value of 1.1V will be read as the maximum (not sure if 1023 or 1024, but anyway)
//Note that this means an input greater than 1.1V from the temperature sensor (temperature about 55deg) is bad, not sure if it will damage the circuit or give bad readings but avoid.
temperature = analogRead(sensorPin)*1100.0/1024.0; // read value on pin 7, between 0 and 1023 where 1023 is max, convert result back to a voltage in millivolts.
temperature = (temperature - 500)/ 10; //Celcius temperature = [(analog voltage in mV) - 500] / 10
tempDiff = temperature - prevTemp;
/******* Change temperature diffence to integer and a signed char if it's between -2 and 2 deg ***********/
tempAsInt = int(round(temperature*10)); // multiply temp. by 10 then round and change to an integer type, this should give temp. as a three digit integer scaled by x10, e.g. 335 = 33.5deg, 120 = 12.0deg etc.
tempDiffAsInt = int (round(tempDiff*10));
// work out whether want to save complete temperature or just temp difference
if ((currentTime - timeLastSaveFullTemp) >=10) // If the entire temperature hasn't been saved for more than 10 min, then want to save the entire temperature rather than just difference
{
decideWhatToSaveFlag = 1; // Set flag to 1, since want to save entire temperature
}
else
decideWhatToSaveFlag = 0; // If the entire temperature has already been saved recently then set flag to zero since only want to save the difference.
if ((tempDiffAsInt>-20 and tempDiffAsInt<20)and (decideWhatToSaveFlag == 0)) // if temp change is less than 2 degrees and if the decideWhatToSaveFlag hasn't been previously set to 1 for another reason.
tempDiffAsChar = (char)(tempDiffAsInt);
else decideWhatToSaveFlag = 1; // if the temp diff since prev sample is > 2 degrees or less than -2 degrees then set flag to 1 since want to save the entire temp. not just the difference
if (decideWhatToSaveFlag == 0)
{
//mySerial.print(" Temp diff");
EEPROM.put(eepromAddress, tempDiffAsChar);
eepromAddress = eepromAddress + sizeof(tempDiffAsChar);
}
else
{
EEPROM.put(eepromAddress, warningNextDataIsTwoBytes);
eepromAddress = eepromAddress + sizeof(warningNextDataIsTwoBytes);
EEPROM.put(eepromAddress, tempAsInt);
eepromAddress = eepromAddress + sizeof(tempAsInt);
timeLastSaveFullTemp = currentTime; // Update time entire temperature was last saved to the current time.
}
prevTemp = temperature; // copy temp to prev temp for next time.
}
}
Please excuse my coding I'm still learning. I deleted my comments at the start of the program which explain why I'm changing the temp. to char etc. as they weren't really relevant to this question but if anyone wants them let me know.
Here is the circuit, a 3V battery is connected between Vcc and GND. The capacitor is 0.1uF ceramic. I am using the SOIC (surfacemount) type package of the tmp36, the (not) shutdown pin in the SOIC version needs to be pulled high so I have connected it to Vcc as specified in the datasheet (this pin doesn't exist in the TO92 through-hole version of the tmp36).
All help is greatly appreciated,
I'm also interested in suggestions for reducing the current further. (Or for how to store more temperatures in a 512 byte EEPROM but that's less important than the battery)
Thanks very much!!
p.s. I have tested this code and it did save one temperature per hour as expected. (The section of code that saves temperature differences rather than temperature doesn't run when there is a 60 min gap between temperatures so all temperatures were saved to the eeprom as integers).