I am working with a promini and have been following some of the info provided by Nick Gammon: Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors, with the intention of putting my MCU to sleep and waking it hourly using an inturrupt from the nrf24l01. I am using an unbranded version of the NCR18650B battery that boasts a 3400mAh capacity. I have played with turning off the different power registers, but at best, the battery lasts ~2 weeks. I am sharing a simplified version of the code where I intend to sleep the MCU.
While I have not removed the voltage regulator or the on board LED, I would hope to have achieved a lower current draw than the 19mA by sleeping the CPU.
The code includes a function to read an SDI-12 sensor. The datasheet:
http://www.ictinternational.com/pdf/?product_id=255
I removed the sensor and saw marginal improvement of battery life.
Am I missing something or did I goof up by buying cheap batteries?
Thanks for taking the time to read.
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <avr/sleep.h> // this is for sleep mode
#include <avr/power.h>// power reduction register (prr) can be used to turn off parts of the arduino we arent using such as adc or SPI interface or uart
#define CE_PIN 7//pins for nrf24l01
#define CSN_PIN 8
float Ea = 0.00;
float temp = 0.00f;
float batteryVoltage;
int ID;
int channel;
#define vcc A0 //analog pin to read battery level
byte NRFIrq = 3; //inturrupt pin used by NRF
const byte thisSlaveAddress[5] = {'R', 'x', 'A', 'A', 'A'};
//{'R','x','A','A','A'} {'R','x','A','A','B'} or {'R','x','A','A','C'}
RF24 radio(CE_PIN, CSN_PIN);
char dataReceived[10]; // this must match dataToSend in the TX
float ackData[3] = {Ea, temp, batteryVoltage}; // the three values to be sent to the master
bool newData = false;
//5tm stuff. a moisture sensor. Datasheet: http://www.ictinternational.com/pdf/?product_id=255
#include <SDI12.h>
#define POWER_PIN -1 // The sensor power pin (or -1 if not switching power)
#define DATAPIN 2 // change to the proper pin for sdi-12 data pin,
#define SENSOR_ADDRESS 1
SDI12 mySDI12(DATAPIN);
String data;//this is the string that will get sent with the rf transmitter redundant?
String myCommand = ""; //this is where the command is sent consisting of 3 parts
String sdiResponse = ""; //this is where the data will be held
//these parts are the sensor address, the command and ! which ends the command
void do_sleep(void);//call function
//==============
void setup() {
power_adc_disable(); // disable the clock on the adc module.
Serial.begin(9600);
mySDI12.begin();
Serial.println("for sampling multiple SDI12 sensors");
delay(100);
radio.begin();
radio.setDataRate( RF24_250KBPS );
radio.openReadingPipe(1, thisSlaveAddress);
radio.enableAckPayload();
radio.enableDynamicPayloads();
radio.startListening();
radio.writeAckPayload(1, &ackData, sizeof(ackData)); // pre-load data
attachInterrupt(digitalPinToInterrupt(NRFIrq), myISR, LOW); //when signal is recieved myISR function is ran when pin three is pulled low
}
//================================================================================================
void loop() {
//all that should be in the loop is the sleep command. the measurement commands will go in the interrupt service routine
//do_sleep();
getData();
showData();
delay(100);
do_sleep();
}
//======================================================
void do_sleep(void)
{
Serial.println("sleep");
sleep_enable();
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
power_adc_disable();
//noInterrupts ();
attachInterrupt(digitalPinToInterrupt(NRFIrq), myISR, LOW);
delay (50);
sleep_cpu ();
delay (100);
Serial.println("awake");
}
//========================================================
void myISR() {
sleep_disable(); //interrupt service routine this is what happens when the wakeup signal is recieved from the logger
//ADCSRA = old_ADCSRA; //enable the adc by setting the register to 1
noInterrupts ();
}
//========================================================
//added function for debugging to read battery power
float readVcc() {
power_adc_enable(); // enable the clock on the adc module.
float batteryVoltage = ((analogRead(vcc) / 511.5) * 3.3);
//ADCSRA = 0; //disable the adc by setting the register to 0
return batteryVoltage;
power_adc_disable(); // disable the clock on the adc module.
}
//============
void getData() {
if ( radio.available() ) {
radio.read( &dataReceived, sizeof(dataReceived) );
delay (50);
updateReplyData();
delay(100);
newData = true;
}
}
//================
void showData() {
if (newData == true) {
Serial.print("Data received ");
Serial.println(dataReceived);
Serial.print(" ackPayload sent ");
Serial.print(ackData[0]);
Serial.print(", ");
Serial.print(ackData[1]);
Serial.print(", ");
// Serial.println(ackData[3]);
// Serial.print(", ");
Serial.println(ackData[2]);
newData = false;
}
}
//================
void updateReplyData() {
measure(); // polls the sensor for a string 'o data
batteryVoltage = readVcc();
//sent data are up dated
ackData[0] = Ea;
ackData[1] = temp;
ackData[2] = batteryVoltage;
//ackData[3] = batteryVoltage;
radio.writeAckPayload(1, &ackData, sizeof(ackData)); // load the payload for the next time
}
//===================
//5tm read function
void measure () {
myCommand = String(SENSOR_ADDRESS) + "M!";
// Serial.println(myCommand); // echo command to terminal
mySDI12.sendCommand(myCommand);
delay(30); // wait a while for a response
while (mySDI12.available()) { // build response string
char c = mySDI12.read();
if ((c != '\n') && (c != '\r')) {
sdiResponse += c;
delay(5);
}
}
if (sdiResponse.length() > 1); //Serial.println(sdiResponse); //write the response to the screen
data = sdiResponse;
// Serial.println (data);
mySDI12.clearBuffer();
delay(1000); // delay between taking reading and requesting data
sdiResponse = ""; // clear the response string
// next command to request data from last measurement
myCommand = String(SENSOR_ADDRESS) + "D0!";
//Serial.println(myCommand); // echo command to terminal
mySDI12.sendCommand(myCommand);
delay(30); // wait a while for a response
while (mySDI12.available()) { // build string from response
channel = mySDI12.parseInt();
ID = mySDI12.parseFloat(3);
Ea = mySDI12.parseFloat();
temp = mySDI12.parseFloat();
// Serial.print("Sensor: ");
// Serial.print(channel);
Serial.print("Sensor ID: ");
Serial.print(ID);
Serial.print(" Ea=");
Serial.print(Ea);
Serial.print("temp= ");
Serial.print(temp);
char c = mySDI12.read();
Serial.println(c);
//
if ((c != '\n') && (c != '\r')) {
sdiResponse += c;
//Serial.println(sdiResponse);
delay(5);
}
}
}