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 #-----------------------