Skip to content

Instantly share code, notes, and snippets.

Created November 9, 2014 10:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/f1a43c00c34a4ac7eaa1 to your computer and use it in GitHub Desktop.
Save anonymous/f1a43c00c34a4ac7eaa1 to your computer and use it in GitHub Desktop.
RFM12B temperature monitor code for WiNode or Nanode RF
// Winode RTC Datalogger
// Ken Boak 28-10-2013 - cooked up in an idle moment as part of the longterm temperature monitoring project
// This program exercises the MCP94710 Real Time Clock and the microSD card
// This Version to Run on Nanode RF or WiNode hardware
// It takes temperature readings every 15 seconds and writes them to the SD card
// It looks for received RF data packets (temperature readings) from any active RFM12B based emonTx and logs these
// to a file along with any loca readings taken from thermistors connected to the ADC inputs
// This code is the remote RF and local temperature monitoring for a potential Nanode RF gateway
// It sets and reads the time and date back from the RTC
// It sets Alarm 1 and Alarm 2 on the RTC and acts on them accordingly
// It writes a 64 character message to the SRAM - which it pronts out on forst power up - and on every alarm
#include <SD.h>
#include <Wire.h>
#include <math.h>
#include <JeeLib.h>
#include <avr/pgmspace.h>
static int payload;
int old;
int hours = 0 ;
int mins = 0 ;
int secs = 0 ;
int old_secs;
unsigned long time_now = 0 ;
int alarm1;
int alarm2;
int data ;
int j = 0;
unsigned int acc0; // Accumulator for ADC0 64 readings
unsigned int acc1; // Accumulator for ADC1 64 readings
unsigned int acc2; // Accumulator for ADC2 64 readings
unsigned int acc3; // Accumulator for ADC3 64 readings
double temp;
double temp0; // storage for temperature readings from sensors
double temp1;
double temp2;
double temp3;
double temp_average;
double temp_out;
int adc0;
int adc1;
int adc2;
int adc3;
int temp_0;
int temp_1;
int temp_2;
int temp_3;
//char RAM_message[64] = "The Quick Brown Foxy Leapt over the Lazy Dog whilst he snoozed";
//char out_string[64];
long id = 0 ;
String dataString = " ";
String timeString = " ";
String stringZero = " ";
String stringOne = " ";
String stringTwo = " ";
String stringThree = " ";
String stringId = " ";
String stringHours = " ";
String stringMins = " ";
String stringSecs = " ";
String stringLZM = " ";
String stringLZS = " ";
//Set by default for the SD Card Library
//MOSI = Pin 11
//MISO = Pin 12
//SCLK = PIN 13
//We always need to set the CS Pin
int CS_pin = 4;
//int pow_pin = 8;
//--------------------------------------------------------------------------------------------
// RFM12B Settings
//--------------------------------------------------------------------------------------------
#define MYNODE 14 // Should be unique on network, node ID 30 reserved for base station
#define freq RF12_868MHZ // frequency - match to same frequency as RFM12B module (change to 868Mhz or 915Mhz if appropriate)
#define group 210 // network group, must be same as emonTx and emonBase
unsigned long fast_update, slow_update;
//double temp,maxtemp,mintemp;
//---------------------------------------------------
// Data structures for transfering data between units
//---------------------------------------------------
typedef struct { int temp1, temp2, temp3, temp4; } PayloadTX; // neat way of packaging data for RF comms
PayloadTX emontx;
const int greenLED=6; // Green LED
const int redLED=5; // Red LED
//--------------------------------------------------------------------------------------------
// Flow control
//--------------------------------------------------------------------------------------------
unsigned long last_emontx; // Used to count time from last emontx update
unsigned long last_emonbase; // Used to count time from last emontx update
//--------------------------------------------------------------------------------------------
// Setup
//--------------------------------------------------------------------------------------------
void setup()
{
Serial.begin(9600);
rf12_initialize(MYNODE, freq,group);
Wire.begin();
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
Serial.print("Navitrino Lite V1.0 ");
/*
print_message(); // print out the 64 Character messsage from NV SRAM
// Writing to SRAM from 0x20 to 0x5F
for (int i = 0; i<63; i++)
{
WriteRTCByte(i+0x20,RAM_message[i]); // Write the message to SRAM
}
*/
/*
// Comment this out so as not to reset the RTC
WriteRTCByte(0,0); //STOP RTC
WriteRTCByte(1,0x43); //MINUTE=43
WriteRTCByte(2,0x14); //HOUR=14
WriteRTCByte(3,0x09); //DAY=1(MONDAY) AND VBAT=1
WriteRTCByte(4,0x28); //DATE=28
WriteRTCByte(5,0x10); //MONTH=10
WriteRTCByte(6,0x13); //YEAR=13
WriteRTCByte(0,0x80); //START RTC, SECOND=00
delay(100);
*/
set_alarm_1();
WriteRTCByte(7,0x30); //Set both alarms active
Serial.println("RTC Initialised");
get_time();
Serial.print(" ");
print_date();
Serial.println();
Serial.println("Initializing Card");
//CS Pin is an output
pinMode(CS_pin, OUTPUT);
if (!SD.begin(CS_pin))
{
Serial.println("Card Failure");
return;
}
Serial.println("Card Ready");
digitalWrite(5,HIGH);
digitalWrite(6,HIGH);
}
void loop()
{
//--------------------------------------------------------------------------------------------
// Get the RF Received packet
//--------------------------------------------------------------------------------------------
if (rf12_recvDone())
{
if (rf12_crc == 0 && (rf12_hdr & RF12_HDR_CTL) == 0) // and no rf errors
{
int node_id = (rf12_hdr & 0x1F);
if (node_id == 15) {emontx = *(PayloadTX*) rf12_data; last_emontx = millis();}
/*
if (node_id == 16)
{
RTC.adjust(DateTime(2012, 1, 1, rf12_data[1], rf12_data[2], rf12_data[3]));
last_emonbase = millis();
}
*/
}
}
//--------------------------------------------------------------------------------------------
// Print to serial every second
//--------------------------------------------------------------------------------------------
if ((millis()-fast_update)>10000)
{
fast_update = millis();
get_time();
print_time();
temp_0 = emontx.temp1; // Get the temperature readings for the RFM12 received packet
temp_1 = emontx.temp2; // and scale to correct decimal
temp_2 = emontx.temp3;
temp_3 = emontx.temp4;
Serial.print(temp_0);
Serial.print(" ");
Serial.print(temp_1);
Serial.print(" ");
Serial.print(temp_2);
Serial.print(" ");
Serial.print(temp_3);
Serial.println("");
stringZero = String(temp_0);
stringOne = String(temp_1);
stringTwo = String(temp_2);
stringThree = String(temp_3);
stringId = String(id);
//--------------------------------------------------------------------------------------------
// Read and convert any local ADC/Thermistor readings
//--------------------------------------------------------------------------------------------
// get_ADCs();
// convert_ADCs();
// print_Temps();
/*
stringZero = String(temp0);
stringOne = String(temp1);
stringTwo = String(temp2);
stringThree = String(temp3);
stringId = String(id);
*/
// Form RTC time string
stringHours = String(hours);
stringMins = String(mins);
if (mins<10) stringLZM = String(0); //leading zero
if (mins>=10) stringLZM = String("");
stringSecs = String(secs);
if (secs<10) stringLZS = String(0); //leading zero
if (secs>=10) stringLZS = String("");
timeString = stringHours + ":" + stringLZM + stringMins + ":" +stringLZS + stringSecs ;
//Create Data string for storing to SD card
//We will use CSV Format
dataString = timeString + ", " + stringZero + ", " + stringOne + ", " + stringTwo + ", " + stringThree;
//Open a file to write to
//Only one file can be open at a time
digitalWrite(6,HIGH);
File dataFile = SD.open("log1.txt", FILE_WRITE);
if (dataFile)
{
dataFile.println(dataString);
dataFile.close();
// Serial.print(dataString);
}
else
{
Serial.println("Couldn't open log file");
}
digitalWrite(6,LOW);
/*
if (alarm1>>0) { alarm1_handler(); }
else {
Serial.println("");
}
if ( j <= 60) {
temp_average = temp_average + temp0;
j++;
}
if (j == 60) {
j = 0;
temp_out = temp_average/60;
temp_average = 0;
}
*/
}
// delay(1000);
}
//******************************************************************************************************
// Misc Routines
unsigned char ReadRTCByte(const unsigned char adr){
unsigned char data;
// Serial.print("*");
Wire.beginTransmission(0x6f);
Wire.write(adr);
Wire.endTransmission();
Wire.requestFrom(0x6f,1);
while (Wire.available()) data=Wire.read();
return data;
}
void WriteRTCByte(const unsigned char adr, const unsigned char data){
Wire.beginTransmission(0x6f);
Wire.write(adr);
Wire.write(data);
Wire.endTransmission();
}
void DisplayRTCData(const unsigned char adr, const unsigned char validbits){
unsigned char data;
data=ReadRTCByte(adr);
data=data & 0xff>>(8-validbits);
if (data<10) Serial.print("0"); //leading zero
Serial.print(data,HEX);
}
void get_time(){
unsigned char data;
data = ReadRTCByte(2);
hours = (data & 0x0f) + 10 *( (data & 0x30)/16);
data = ReadRTCByte(1);
mins = (data & 0x0f) + 10 *( (data & 0x70)/16);
data = ReadRTCByte(0);
secs = (data & 0x0f) + 10 *( (data & 0x70)/16);
}
void print_RTC() {
Serial.print(hours);
Serial.print(":");
if (mins<10) Serial.print("0"); //leading zero
Serial.print(mins);
Serial.print(":");
if (secs<10) Serial.print("0"); //leading zero
Serial.print(secs);
}
// Print out the RTC
void print_time(){
DisplayRTCData(2,6);
Serial.print(":");
DisplayRTCData(1,7);
Serial.print(":");
DisplayRTCData(0,7);
Serial.print(" ");
}
void print_date(){
DisplayRTCData(4,6);
Serial.print("/");
DisplayRTCData(5,5);
Serial.print("/");
Serial.print("20"); //year beginning with 20xx
DisplayRTCData(6,8);
}
void set_alarm_1()
{
WriteRTCByte(0x0A,0x00); //SECS=00
WriteRTCByte(0x0B,0x45); //MINUTE=45
WriteRTCByte(0x0C,0x14); //HOUR=12
WriteRTCByte(0x0D,0x01); //DAY=1(MONDAY) AND Match = seconds
WriteRTCByte(0x0E,0x01); //DATE=01
WriteRTCByte(0x0F,0x10); //MONTH=10
}
void set_alarm_2()
{
WriteRTCByte(0x11,0x00); //SECS=00
WriteRTCByte(0x12,0x43); //MINUTE=54
WriteRTCByte(0x13,0x13); //HOUR=12
WriteRTCByte(0x14,0x01); //DAY=1(MONDAY) AND Match = seconds
WriteRTCByte(0x15,0x01); //DATE=01
WriteRTCByte(0x16,0x10); //MONTH=10
}
void read_alarm_1()
{
data = ReadRTCByte(0x0D);
alarm1 = (data & 0x08);
}
void read_alarm_2()
{
data = ReadRTCByte(0x14);
alarm2 = (data & 0x08);
}
void alarm1_handler() {
WriteRTCByte(0x0D,0x01); // Clear the alarm flag
/*
// Write the RAM message
for (int i = 0; i<=63; i++)
{
data=ReadRTCByte(i+0x20);
out_string[i] = data ;
}
Serial.print(out_string); // Print out the SRAM message
*/
Serial.println(" ");
} // Cancel the alarm
/*
void print_message() {
// Write the RAM message
for (int i = 0; i<=63; i++)
{
data=ReadRTCByte(i+0x20);
out_string[i] = data ;
}
Serial.print(" ");
Serial.print(out_string); // Print out the SRAM message
Serial.println(" ");
}
*/
//*********************************************************************************************************
//*****************************************************************************************************
// Thermistor Linearisation and temperature print-out code
// Thermistor Linearisation Code
double Thermistor(int RawADC) {
// Inputs ADC Value from Thermistor and outputs Temperature in Celsius
// requires: include <math.h>
// Utilizes the Steinhart-Hart Thermistor Equation:
// Temperature in Kelvin = 1 / {A + B[ln(R)] + C[ln(R)]^3}
// where A = 0.001129148, B = 0.000234125 and C = 8.76741E-08
long Resistance; double Temp; // Dual-Purpose variable to save space.
Resistance=((10240000/RawADC) - 10000); // Assuming a 10k Thermistor. Calculation is actually: Resistance = (1024 * BalanceResistor/ADC) - BalanceResistor
Temp = log(Resistance); // Saving the Log(resistance) so not to calculate it 4 times later. // "Temp" means "Temporary" on this line.
Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp)); // Now it means both "Temporary" and "Temperature"
Temp = Temp - 273.15; // Convert Kelvin to Celsius // Now it only means "Temperature"
/*
// BEGIN- Remove these lines for the function not to display anything
Serial.print("ADC: "); Serial.print(RawADC); Serial.print("/1024"); // Print out RAW ADC Number
Serial.print(", Volts: "); printDouble(((RawADC*4.860)/1024.0),3); // 4.860 volts is what my USB Port outputs.
Serial.print(", Resistance: "); Serial.print(Resistance); Serial.print("ohms");
// END- Remove these lines for the function not to display anything
*/
// Uncomment this line for the function to return Fahrenheit instead.
//Temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert to Fahrenheit
return Temp; // Return the Temperature
}
//*****************************************************************************************************
void printDouble(double val, byte precision) {
// prints val with number of decimal places determine by precision
// precision is a number from 0 to 6 indicating the desired decimal places
// example: printDouble(3.1415, 2); // prints 3.14 (two decimal places)
Serial.print (int(val)); //prints the int part
if( precision > 0) {
Serial.print("."); // print the decimal point
unsigned long frac, mult = 1;
byte padding = precision -1;
while(precision--) mult *=10;
if(val >= 0) frac = (val - int(val)) * mult; else frac = (int(val) - val) * mult;
unsigned long frac1 = frac;
while(frac1 /= 10) padding--;
while(padding--) Serial.print("0");
Serial.print(frac,DEC) ;
}
}
//*****************************************************************************************************
//*************************************************************************************************************************
// Get the average of 64 ADC readings
//*************************************************************************************************************************
// Read the ADCs. Leave 10mS between each reading, and at least 60mS between consecutive reads.
// 64 x 60mS
void get_ADCs() {
acc0 = 0; // Reset the acummulators for ADC totals
acc1 = 0;
acc2 = 0;
acc3 = 0;
for ( int i = 0; i<=63; i++) { // Read the ADCs 64 times and average
acc0 = acc0 + analogRead(0);
acc1 = acc1 + analogRead(1);
acc2 = acc2 + analogRead(2);
acc3 = acc3 + analogRead(3);
}
adc0 = acc0/64; // scale back down
adc1 = acc1/64;
adc2 = acc2/64;
adc3 = acc3/64;
} // End of get_ADCs()
//****************************************************************************************************
// Convert the averaged ADC Readings to Centigrade
//****************************************************************************************************
void convert_ADCs() { // Take the averaged ADC readings and convert to degrees centigrade
temp0 = Thermistor(adc0);
temp1 = Thermistor(adc1);
temp2 = Thermistor(adc2);
temp3 = Thermistor(adc3);
}
//***********************************************************************************************
// Print out the temperature readings to serial terminal
//***********************************************************************************************
void print_Temps(){ // Print out the temperature readings to serial terminal
// Serial.print(acc0);
// Serial.print(" ");
Serial.print(temp0); // outside temp
Serial.print(", ");
Serial.print(temp1); // room temp - lounge
Serial.print(", ");
Serial.print(temp2); // tank temp top
Serial.print(", ");
Serial.print(temp3); // flow temp
Serial.print(", ");
// Serial.print(j); // average
// Serial.print(", ");
// Serial.print(temp_average); // average
// Serial.print(", ");
// Serial.print(temp_out); // average
// Serial.print(", ");
// Serial.println("");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment