254 lines
8.6 KiB
Arduino
254 lines
8.6 KiB
Arduino
|
|
// **********************************************************************************
|
||
|
|
// Sample RFM69 sender/node sketch for DS18B20
|
||
|
|
// Periodically wakes up, reads the sensor, and goes back to sleep
|
||
|
|
// Compensates sleep time for the conversion time which can take up to 700ms on this sensor
|
||
|
|
//
|
||
|
|
// ************************************
|
||
|
|
// **** IMPORTANT NOTES ON DS18B20 ****
|
||
|
|
// ************************************
|
||
|
|
//
|
||
|
|
// DS18B20 requires a pullup on the data pin (2.2K-10K)
|
||
|
|
// Adjust DS18B20 read resolution based on required accuracy and conversion time
|
||
|
|
// Radio & MCU are WDT slept during conversion but DS18B20 still uses ~1mA during conversion
|
||
|
|
// Conversion times: ~95ms @9bit, ~180ms @10bit, 370ms @11bit, ~650ms @12bit)
|
||
|
|
// **********************************************************************************
|
||
|
|
// Copyright Felix Rusu 2020, http://www.LowPowerLab.com/contact
|
||
|
|
// **********************************************************************************
|
||
|
|
// License
|
||
|
|
// **********************************************************************************
|
||
|
|
// This program is free software; you can redistribute it
|
||
|
|
// and/or modify it under the terms of the GNU General
|
||
|
|
// Public License as published by the Free Software
|
||
|
|
// Foundation; either version 3 of the License, or
|
||
|
|
// (at your option) any later version.
|
||
|
|
//
|
||
|
|
// This program is distributed in the hope that it will
|
||
|
|
// be useful, but WITHOUT ANY WARRANTY; without even the
|
||
|
|
// implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||
|
|
// PARTICULAR PURPOSE. See the GNU General Public
|
||
|
|
// License for more details.
|
||
|
|
//
|
||
|
|
// Licence can be viewed at
|
||
|
|
// http://www.gnu.org/licenses/gpl-3.0.txt
|
||
|
|
//
|
||
|
|
// Please maintain this license information along with authorship
|
||
|
|
// and copyright notices in any redistribution of this code
|
||
|
|
// **********************************************************************************
|
||
|
|
//*********************************************************************************************
|
||
|
|
#include <RFM69.h> //https://www.github.com/lowpowerlab/rfm69
|
||
|
|
#include <RFM69_ATC.h> //included in RFM69
|
||
|
|
#include <LowPower.h> //https://www.github.com/lowpowerlab/lowpower
|
||
|
|
#include <OneWire.h> //https://github.com/PaulStoffregen/OneWire
|
||
|
|
//*********************************************************************************************
|
||
|
|
#define DALLAS_PIN 7
|
||
|
|
#define DALLAS_RESOLUTION 12
|
||
|
|
#define TRANSMITPERIOD 5000 //read and send data every this many ms (WDT sleep)
|
||
|
|
//*********************************************************************************************
|
||
|
|
#define NODEID 789
|
||
|
|
#define NETWORKID 100
|
||
|
|
#define GATEWAYID 1 //as a rule of thumb the gateway ID should always be 1
|
||
|
|
#define FREQUENCY RF69_915MHZ //match the RFM69 version! Others: RF69_433MHZ, RF69_868MHZ
|
||
|
|
//#define FREQUENCY_EXACT 916000000
|
||
|
|
#define ENCRYPTKEY "sampleEncryptKey" //same 16 characters on all nodes, comment this line to disable encryption
|
||
|
|
#define IS_RFM69HW_HCW //uncomment only for RFM69HW/HCW! Leave out if you have RFM69W/CW!
|
||
|
|
//*********************************************************************************************
|
||
|
|
#define ENABLE_ATC //comment out this line to disable AUTO TRANSMISSION CONTROL
|
||
|
|
#define ATC_RSSI -90
|
||
|
|
//*********************************************************************************************
|
||
|
|
#define SERIAL_BAUD 115200 //comment out to turn off serial output
|
||
|
|
#ifdef SERIAL_BAUD
|
||
|
|
#define DEBUG(input) Serial.print(input)
|
||
|
|
#define DEBUGln(input) Serial.println(input)
|
||
|
|
#define DEBUGHEX(x) Serial.print(x, HEX)
|
||
|
|
#define DEBUGflush() Serial.flush()
|
||
|
|
#else
|
||
|
|
#define DEBUG(input)
|
||
|
|
#define DEBUGln(input)
|
||
|
|
#define DEBUGflush()
|
||
|
|
#define DEBUGHEX(x)
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#define LED_HIGH digitalWrite(LED_BUILTIN, HIGH)
|
||
|
|
#define LED_LOW digitalWrite(LED_BUILTIN, LOW)
|
||
|
|
//*********************************************************************************************
|
||
|
|
#ifdef ENABLE_ATC
|
||
|
|
RFM69_ATC radio;
|
||
|
|
#else
|
||
|
|
RFM69 radio;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
int HighByte, LowByte, TReading, SignBit, Tc_100, Fh_100, Whole, Fract;
|
||
|
|
char buff[61]; //max packet size is 61 with encryption enabled
|
||
|
|
char Fstr[10];
|
||
|
|
byte buffLen;
|
||
|
|
float fahrenheit, celsius;
|
||
|
|
uint32_t time=0, now=0, LASTPACKETTIME=-1;
|
||
|
|
uint16_t conversionTime=0;
|
||
|
|
|
||
|
|
void setup() {
|
||
|
|
#ifdef SERIAL_BAUD
|
||
|
|
Serial.begin(SERIAL_BAUD);
|
||
|
|
#endif
|
||
|
|
pinMode(LED_BUILTIN, OUTPUT);
|
||
|
|
|
||
|
|
radio.initialize(FREQUENCY,NODEID,NETWORKID);
|
||
|
|
#ifdef IS_RFM69HCW
|
||
|
|
radio.setHighPower(); //uncomment only for RFM69HW!
|
||
|
|
#endif
|
||
|
|
#ifdef FREQUENCY_EXACT
|
||
|
|
radio.setFrequency(FREQUENCY_EXACT); //set frequency to some custom frequency
|
||
|
|
#endif
|
||
|
|
#ifdef ENCRYPTKEY
|
||
|
|
radio.encrypt(ENCRYPTKEY);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifdef ENABLE_ATC
|
||
|
|
radio.enableAutoPower(ATC_RSSI);
|
||
|
|
#endif
|
||
|
|
radio.sleep();
|
||
|
|
sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
|
||
|
|
DEBUGln(buff);
|
||
|
|
}
|
||
|
|
|
||
|
|
void loop() {
|
||
|
|
fahrenheit = 0;
|
||
|
|
celsius = 0;
|
||
|
|
getTemp(DALLAS_PIN, DALLAS_RESOLUTION);
|
||
|
|
|
||
|
|
if (fahrenheit !=0) {
|
||
|
|
dtostrf(fahrenheit, 3,2, Fstr);
|
||
|
|
sprintf(buff, "F:%s", Fstr);
|
||
|
|
buffLen = strlen(buff);
|
||
|
|
|
||
|
|
LED_HIGH;
|
||
|
|
DEBUG("Sending '"); DEBUG(buff); DEBUG("' .. ");
|
||
|
|
if (radio.sendWithRetry(GATEWAYID, buff, buffLen))
|
||
|
|
DEBUG("ok!");
|
||
|
|
else DEBUG("nok...");
|
||
|
|
radio.sleep();
|
||
|
|
DEBUGln();
|
||
|
|
LED_LOW;
|
||
|
|
}
|
||
|
|
else DEBUGln("Nothing to send: fahrenheit=0");
|
||
|
|
|
||
|
|
DEBUGflush();
|
||
|
|
LowPower.longPowerDown(TRANSMITPERIOD - conversionTime);
|
||
|
|
DEBUGln("WAKEUP");
|
||
|
|
}
|
||
|
|
|
||
|
|
void getTemp(byte dataPin, byte resolution) {
|
||
|
|
byte dsaddr[8]; // Device identifier
|
||
|
|
OneWire myds(dataPin);
|
||
|
|
getFirstDSAddr(myds,dsaddr);
|
||
|
|
conversionTime=0;
|
||
|
|
|
||
|
|
DEBUG(F("DallasAddress:"));
|
||
|
|
for (int j=0;j<8;j++) {
|
||
|
|
if (dsaddr[j] < 16) DEBUG('0');
|
||
|
|
DEBUGHEX(dsaddr[j]);
|
||
|
|
}
|
||
|
|
DEBUGln();
|
||
|
|
getdstemp(myds, dsaddr, resolution);
|
||
|
|
}
|
||
|
|
|
||
|
|
void getFirstDSAddr(OneWire myds, byte firstAddr[]){
|
||
|
|
byte i;
|
||
|
|
byte present = 0;
|
||
|
|
byte addr[8];
|
||
|
|
float celsius, fahrenheit;
|
||
|
|
int length = 8;
|
||
|
|
|
||
|
|
//DEBUGln("Looking for 1-Wire devices...");
|
||
|
|
while(myds.search(addr)) {
|
||
|
|
for( i = 0; i < 8; i++) firstAddr[i]=addr[i];
|
||
|
|
if (OneWire::crc8( addr, 7) != addr[7]) {
|
||
|
|
DEBUGln("FAIL:INVALID CRC");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
float getdstemp(OneWire myds, byte addr[8], byte resolution) {
|
||
|
|
byte present = 0;
|
||
|
|
byte data[12];
|
||
|
|
byte type_s;
|
||
|
|
uint32_t starttime=millis();
|
||
|
|
uint32_t sleeptime=0;
|
||
|
|
|
||
|
|
switch (addr[0]) {
|
||
|
|
case 0x10:
|
||
|
|
//DEBUGln(F(" Chip = DS18S20")); // or old DS1820
|
||
|
|
type_s = 1;
|
||
|
|
break;
|
||
|
|
case 0x28:
|
||
|
|
//DEBUGln(F(" Chip = DS18B20"));
|
||
|
|
type_s = 0;
|
||
|
|
break;
|
||
|
|
case 0x22:
|
||
|
|
//DEBUGln(F(" Chip = DS1822"));
|
||
|
|
type_s = 0;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
DEBUGln(F("Device is not a DS18x20 family device."));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Set reading resolution
|
||
|
|
byte resbyte = 0x1F;
|
||
|
|
if (resolution == 12) resbyte = 0x7F;
|
||
|
|
else if (resolution == 11) resbyte = 0x5F;
|
||
|
|
else if (resolution == 10) resbyte = 0x3F;
|
||
|
|
|
||
|
|
// Set configuration
|
||
|
|
myds.reset();
|
||
|
|
myds.select(addr);
|
||
|
|
myds.write(0x4E); // Write scratchpad
|
||
|
|
myds.write(0); // TL
|
||
|
|
myds.write(0); // TH
|
||
|
|
myds.write(resbyte); // Configuration Register
|
||
|
|
myds.write(0x48); // Copy Scratchpad
|
||
|
|
myds.reset();
|
||
|
|
myds.select(addr);
|
||
|
|
myds.write(0x44,1); // start conversion, with parasite power on at the end
|
||
|
|
|
||
|
|
// Sleep while waiting for conversion to complete
|
||
|
|
while (!myds.read()) {
|
||
|
|
LowPower.powerDown(SLEEP_15MS, ADC_OFF, BOD_OFF);
|
||
|
|
sleeptime+=15;
|
||
|
|
}
|
||
|
|
|
||
|
|
conversionTime = millis() - starttime+sleeptime;
|
||
|
|
DEBUG("Conversion took: "); DEBUG(conversionTime); DEBUGln(" ms");
|
||
|
|
|
||
|
|
present = myds.reset();
|
||
|
|
myds.select(addr);
|
||
|
|
myds.write(0xBE); // Read Scratchpad
|
||
|
|
|
||
|
|
DEBUG("Raw Scratchpad Data: ");
|
||
|
|
for (byte i = 0; i < 9; i++) { // we need 9 bytes
|
||
|
|
data[i] = myds.read();
|
||
|
|
DEBUGHEX(data[i]);
|
||
|
|
}
|
||
|
|
DEBUGln();
|
||
|
|
|
||
|
|
// convert the data to actual temperature
|
||
|
|
unsigned int raw = (data[1] << 8) | data[0];
|
||
|
|
if (type_s) {
|
||
|
|
raw = raw << 3; // 9 bit resolution default
|
||
|
|
if (data[7] == 0x10) {
|
||
|
|
// count remain gives full 12 bit resolution
|
||
|
|
raw = (raw & 0xFFF0) + 12 - data[6];
|
||
|
|
} else {
|
||
|
|
byte cfg = (data[4] & 0x60);
|
||
|
|
// default is 12 bit resolution: ~650 ms conversion time
|
||
|
|
if (cfg == 0x00) raw = raw << 3; // 9 bit resolution: ~95ms
|
||
|
|
else if (cfg == 0x20) raw = raw << 2; // 10 bit res: ~180ms
|
||
|
|
else if (cfg == 0x40) raw = raw << 1; // 11 bit res: ~370ms
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
celsius = (float)raw / 16.0;
|
||
|
|
fahrenheit = celsius * 1.8 + 32.0;
|
||
|
|
return conversionTime;
|
||
|
|
}
|