Blog Archive

Thursday 6 March 2014

Low power Arduino clone with RF24 and DS18B20 temperature sensor

This low power Arduino clone on a breadboard is sampling the temperature every three seconds and transmitting it to a Raspberry Pi which is acting as a hub. This is done using Nordic nrf24l01+ transceivers. They're dead cheap so ideal for this. The low power and therefore long battery life (not tested how long the batteries last yet) is due to a combination of removing most unneeded components and the use of a MCP1700-3302E/TO power regulator and power saving software from Jeelabs. More info to follow...

The RF24 library for Arduino
The RF24 library ported to Raspberry Pi 








#The Raspberry Pi Code:
#include <cstdlib>
#include <iostream>
#include "../RF24.h"
#include <time.h>
#include <stdio.h>
 
using namespace std;
 
// spi device, spi speed, ce gpio pin
RF24 radio("/dev/spidev0.0",8000000,25);
 
void setup(void)
{
    // init radio for reading
    radio.begin();
    radio.enableDynamicPayloads();
    radio.setAutoAck(1);
    radio.setRetries(15,15);
    radio.setDataRate(RF24_2MBPS);
    radio.setPALevel(RF24_PA_LOW);
    radio.setCRCLength(RF24_CRC_16);
    radio.openReadingPipe(1,0xF0F0F0F0E4LL);
    radio.powerUp();
    radio.startListening();
}
 
int main(int argc, char** argv) 
{
 int count = 0;
 int timeout = 5;
 int returncode = 0;
 time_t starttime;
 time_t currtime;
 double difftime = 0;
 time(&starttime);
 setup();
 char receivePayload[11] = "";

 while ( (count < 1) && (difftime < timeout) ){
  if ( radio.available() )
  {
   // Dump the payloads until we've gotten everything
   bool done = false;
   while (!done)
   {
    // Fetch the payload, and see if this was the last one.
    uint8_t len = radio.getDynamicPayloadSize();
    done = radio.read(receivePayload, len);
    count++;
    printf("%s\n",receivePayload);
   }
  }
  time(&currtime);
  difftime=((double)currtime - (double)starttime);
 }
 if(difftime > timeout - 1){
  printf("timeout after %.f seconds\n",difftime);
  returncode = 1;
 }
  return returncode;
}
#-----------------------
#-----------------------
#Arduino Code:
// Voltage divider used for this circuit : Vin 4.8v (3 x AA batteries) and 2 x 10k Ohm resistors
// connected to analog 0.  The input voltage from the voltage regulator is 3.3v
#include <SPI.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port D3 on the Arduino
#define ONE_WIRE_BUS 3
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);
// arrays to hold device address
DeviceAddress insideThermometer;

//power stuff
//#include <avr/sleep.h>
#include <JeeLib.h>  // Include library containing low power functions
ISR(WDT_vect) { Sleepy::watchdogEvent(); } // Setup for low power waiting


#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
RF24 radio(8,7); // (CE, CSN)


void setup()
{
  Serial.begin(9600);
  Serial.println();
  Serial.println(__FILE__);
  Serial.println("ready...");

  sensors.begin();
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");
  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
  sensors.setResolution(insideThermometer, 12);
  
  printf_begin();
  radio.begin();
  //radio.setChannel(0x6c);
  radio.setAutoAck(1);    
  radio.setRetries(15,15);
  radio.setPayloadSize(11);
  radio.setDataRate(RF24_2MBPS);
  radio.openWritingPipe(0xF0F0F0F0E4LL); //3LL for nona, 2LL for nano, 1LL for UNO

  radio.setPALevel(RF24_PA_MAX);
  radio.enableDynamicPayloads();

  //radio.printDetails();
// analogReference(INTERNAL);
}

void loop()
{
  //voltage
  int sensorValue = analogRead(A0);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 3.3V):
  float voltage = sensorValue * (3.3 / 1023.0);
  float undivided = (voltage * 20000)/10000;
  
  //----------------  
  
  sensors.requestTemperatures(); // Send the command to get temperatures
  float tempC = sensors.getTempC(insideThermometer);
  
  radio.stopListening();
  
  
  char outBuffer[11]= "";
  char temp[8]="";
  char hum[8]="09.0";
  int volt = readVcc();
  ftoa(temp,tempC,2);
  ftoa(hum, undivided,2);

  sprintf(outBuffer,"%s,%s",temp,hum);
  
  
  //Serial.println(outBuffer);
  
  radio.powerUp();
  radio.write(outBuffer, strlen(outBuffer));
  radio.powerDown();
  Sleepy::loseSomeTime(3000);    // SLEEP (DEEP) for 3 seconds
}

//===============================================================================
// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}
//===============================================================================
// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print("Temp C: ");
  Serial.print(tempC);
  Serial.print(" Temp F: ");
  Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}
//==========================================================================================
char *ftoa(char *a, double f, int precision)
{
  long p[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000};
  
  char *ret = a;
  long heiltal = (long)f;
  itoa(heiltal, a, 10);
  while (*a != '\0') a++;
  *a++ = '.';
  long desimal = abs((long)((f - heiltal) * p[precision]));
  itoa(desimal, a, 10);
  return ret;
}

//===============================================================================
long readVcc() {

  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1126400L / result; // Back-calculate AVcc in mV
  return result;

} 

#-----------------------
code here
#-----------------------

#-----------------------
code here
#-----------------------

#-----------------------
code here
#-----------------------