Created
November 9, 2014 10:41
-
-
Save anonymous/f1a43c00c34a4ac7eaa1 to your computer and use it in GitHub Desktop.
RFM12B temperature monitor code for WiNode or Nanode RF
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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