Created
January 19, 2015 22:20
-
-
Save Scott216/3cd6cc56393bccdf2981 to your computer and use it in GitHub Desktop.
Testing MoteinoMega with Davis ISS Weather Station
This file contains hidden or 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
/* | |
Testing MoteinoMega with Weather station and SD card | |
Want to see how sketch works with no ethernet code | |
Does it still have long delays while syncing the frequency hopping | |
MoteinoMega and SD Card breakout borad from ebay will work with 5v or 3.3 volts - via selector switch | |
Forum: http://bit.ly/14thCKB | |
GitHub Repo: http://github.com/LowPowerLab | |
*/ | |
// #define USE_SD_CARD // comment this out if not using SD card | |
#include <SPI.h> // DavisRFM69.h needs this http://arduino.cc/en/Reference/SPI | |
#include <DavisRFM69.h> // http://github.com/dekay/DavisRFM69 | |
#include <SD.h> // Micro SD Card. http://arduino.cc/en/Reference/SD | |
// Reduce number of bogus compiler warnings, see http://bit.ly/1pU6XMe | |
#undef PROGMEM | |
#define PROGMEM __attribute__(( section(".progmem.data") )) | |
const byte SS_PIN_MICROSD = 13; | |
#ifdef __AVR_ATmega1284P__ | |
#define MOTEINO_LED 15 // Moteino MEGAs have LEDs on D15 | |
const byte SS_PIN_RADIO = 4; | |
#else | |
#define MOTEINO_LED 9 // Moteinos have LEDs on D9 | |
const byte SS_PIN_RADIO = 10; | |
#endif | |
#define ISS_UV_INDEX 0x4 | |
#define ISS_RAIN_SECONDS 0x5 | |
#define ISS_SOLAR_RAD 0x6 | |
#define ISS_OUTSIDE_TEMP 0x8 | |
#define ISS_WIND_GUST 0x9 | |
#define ISS_HUMIDITY 0xA | |
#define ISS_RAIN 0xE | |
DavisRFM69 radio; | |
const byte TRANSMITTER_STATION_ID = 3; // ISS station ID to be monitored. Default station ID is normally 1 | |
// Weather data | |
byte g_rainCounter = 0; // rain data sent from outside weather station. 1 = 0.01". Just counts up to 127 then rolls over to zero | |
byte g_windgustmph = 0; // Wind in MPH | |
uint16_t g_dayRain = 0; // Accumulated rain for the day in 1/100 inch | |
float g_rainRate = 0; // Rain rate in inches per hour | |
int16_t g_outsideTemperature = 0; // Outside temperature in tenths of degrees | |
byte g_outsideHumidity = 0; // Outside relative humidity in %. | |
byte g_windSpeed = 0; // Wind speed in miles per hour | |
float g_windDirection_Now = 0; // Instantanious wind direction, from 1 to 360 degrees (0 = no wind data) | |
uint16_t g_windDirection_Avg = 0; // Average wind direction, from 1 to 360 degrees (0 = no wind data) | |
//============================================================================= | |
// Setup radio | |
//============================================================================= | |
void setup() | |
{ | |
Serial.begin(9600); | |
pinMode(MOTEINO_LED, OUTPUT); | |
digitalWrite(MOTEINO_LED, LOW); | |
#ifdef USE_SD_CARD | |
pinMode(SS_PIN_MICROSD, OUTPUT); | |
digitalWrite(SS_PIN_MICROSD, HIGH); | |
// Initialize SD Card | |
if ( SD.begin(SS_PIN_MICROSD) ) | |
{ Serial.println(F("\ncard initialized")); } | |
else | |
{ Serial.println(F("\nCard failed, or not present")); } | |
#endif | |
// Setup Moteino radio | |
radio.initialize(); | |
radio.setChannel(0); // Frequency - Channel is *not* set in the initialization. Need to do it now | |
delay(10000); | |
printRadioInfo(); | |
printFreeRam(); | |
Serial.println(F("MoteinoMega test for Davis ISS")); | |
} // end setup() | |
//============================================================================= | |
// Main loop() | |
//============================================================================= | |
void loop() | |
{ | |
bool haveFreshWeatherData = getWirelessData(); | |
#ifdef USE_SD_CARD | |
if ( haveFreshWeatherData ) | |
{ logDataToSdCard( g_windDirection_Now ); } | |
#endif | |
// Heartbeat LED | |
static uint32_t heartBeatLedTimer = millis(); | |
if ( (long)(millis() - heartBeatLedTimer) > 200 ) | |
{ | |
digitalWrite(MOTEINO_LED, !digitalRead(MOTEINO_LED)); | |
heartBeatLedTimer = millis(); | |
} | |
} // end loop() | |
//============================================================================= | |
// Read wireless data coming from Davis ISS weather station | |
//============================================================================= | |
bool getWirelessData() | |
{ | |
static uint32_t lastRxTime = 0; // timestamp of last received data. Doesn't have to be good data | |
static byte hopCount = 0; | |
bool gotGoodData = false; | |
// Process ISS packet | |
if ( radio.receiveDone() ) | |
{ | |
packetStats.packetsReceived++; | |
// check CRC | |
unsigned int crc = radio.crc16_ccitt(radio.DATA, 6); | |
if ((crc == (word(radio.DATA[6], radio.DATA[7]))) && (crc != 0)) | |
{ | |
processPacket(); | |
packetStats.receivedStreak++; | |
hopCount = 1; | |
gotGoodData = true; | |
} | |
else | |
{ | |
packetStats.crcErrors++; | |
packetStats.receivedStreak = 0; | |
Serial.print("CRC errors "); | |
Serial.println(packetStats.crcErrors); | |
} | |
// Whether CRC is right or not, we count that as reception and hop | |
lastRxTime = millis(); | |
radio.hop(); | |
} // end if(radio.receiveDone()) | |
// If a packet was not received at the expected time, hop the radio anyway | |
// in an attempt to keep up. Give up after 25 failed attempts. Keep track | |
// of packet stats as we go. I consider a consecutive string of missed | |
// packets to be a single resync. Thx to Kobuki for this algorithm. | |
const uint16_t PACKET_INTERVAL = 2555; | |
if ( (hopCount > 0) && ((millis() - lastRxTime) > (hopCount * PACKET_INTERVAL + 200)) ) | |
{ | |
packetStats.packetsMissed++; | |
if (hopCount == 1) | |
{ packetStats.numResyncs++; } | |
if (++hopCount > 25) | |
{ hopCount = 0; } | |
radio.hop(); | |
} | |
return gotGoodData; | |
} // end getWirelessData() | |
//========================================================================================================= | |
// Log data to SD Card | |
//========================================================================================================= | |
bool logDataToSdCard(float testData) | |
{ | |
#ifdef USE_SD_CARD | |
// Build log file name: YYYYMMDD.log | |
char logfile[13]; | |
sprintf(logfile, "%02d%02d%02d.log", 2015, 1, 11); | |
// Check to see if the file exists: | |
if (!SD.exists(logfile)) | |
{ | |
// log file doesn't exist, create it | |
File newFile = SD.open(logfile, FILE_WRITE); | |
// Create header row | |
newFile.print(F("Timestamp\tRx delta sec\tWind Dir")); // time stamp in minutes since reboot, Rx delta sec is seconds between date received | |
newFile.println(); | |
newFile.close(); | |
} | |
// open the file. note that only one file can be open at a time, | |
// so you have to close this one before opening another. | |
File dataFile = SD.open(logfile, FILE_WRITE); | |
// if the file is available, write to it: | |
static uint32_t lastRxTime = millis(); | |
if (dataFile) | |
{ | |
dataFile.print(millis() / 60000L ); // minutes since startup | |
dataFile.print(F("\t")); | |
dataFile.print((millis() - lastRxTime)/1000L); // seconds from last time data was receied | |
dataFile.print(F("\t")); | |
dataFile.print(testData); | |
dataFile.println(); | |
dataFile.close(); | |
lastRxTime = millis(); // timestamp for when data was received | |
return true; | |
} | |
// if the file isn't open, pop up an error: | |
else | |
{ | |
Serial.print(F("error opening ")); | |
Serial.println(logfile); | |
return false; | |
} | |
#endif | |
} // logDataToSdCard() | |
//============================================================================= | |
// Read the data from the ISS | |
//============================================================================= | |
void processPacket() | |
{ | |
// Flags are set true as each variable comes in for the first time | |
static bool gotTempData = false; | |
static bool gotHumidityData = false; | |
static bool gotRainData = false; | |
uint16_t rainSeconds = 0; // seconds between rain bucket tips | |
byte byte4MSN = 0; // Holds MSB of byte 4 - used for seconds between bucket tips | |
// station ID - the low order three bits are the station ID. Station ID 1 is 0 in this data | |
byte stationId = (radio.DATA[0] & 0x07) + 1; | |
if ( stationId != TRANSMITTER_STATION_ID ) | |
{ return; } // exit function if this isn't the station ID program is monitoring | |
// Every packet has wind speed, wind direction and battery status in it | |
g_windSpeed = radio.DATA[1]; | |
// There is a dead zone on the wind vane. No values are reported between 8 | |
// and 352 degrees inclusive. These values correspond to received byte | |
// values of 1 and 255 respectively | |
// See http://www.wxforum.net/index.php?topic=21967.50 | |
// float windDir = 9 + radio.DATA[2] * 342.0f / 255.0f; - formula has dead zone from 352 to 10 degrees | |
if ( radio.DATA[2] == 0 ) | |
{ g_windDirection_Now = 0; } | |
else | |
{ g_windDirection_Now = ((float)radio.DATA[2] * 1.40625) + 0.3; } // This formula doesn't have dead zone, see: http://bit.ly/1uxc9sf | |
// 0 = battery ok, 1 = battery low. Not used by anything in program | |
byte transmitterBatteryStatus = (radio.DATA[0] & 0x8) >> 3; | |
// Look at MSB in firt byte to get data type | |
switch (radio.DATA[0] >> 4) | |
{ | |
case ISS_OUTSIDE_TEMP: | |
g_outsideTemperature = (int16_t)(word(radio.DATA[3], radio.DATA[4])) >> 4; | |
gotTempData = true; // one-time flag when data first arrives. Used to track when all the data has arrived and can be sent to PWS | |
break; | |
case ISS_HUMIDITY: | |
// Round humidity to nearest integer | |
g_outsideHumidity = (byte) ( (float)( word((radio.DATA[4] >> 4), radio.DATA[3]) ) / 10.0 + 0.5 ); | |
gotHumidityData = true; // one-time flag when data first arrives | |
break; | |
case ISS_WIND_GUST: | |
g_windgustmph = radio.DATA[3]; | |
break; | |
case ISS_RAIN: | |
g_rainCounter = radio.DATA[3]; | |
gotRainData = true; // one-time flag when data first arrives | |
break; | |
case ISS_RAIN_SECONDS: // Seconds between bucket tips, used to calculate rain rate. See: http://www.wxforum.net/index.php?topic=10739.msg190549#msg190549 | |
byte4MSN = radio.DATA[4] >> 4; | |
if ( byte4MSN < 4 ) | |
{ rainSeconds = (radio.DATA[3] >> 4) + radio.DATA[4] - 1; } | |
else | |
{ rainSeconds = radio.DATA[3] + (byte4MSN - 4) * 256; } | |
break; | |
default: | |
break; | |
} | |
printData(rainSeconds); // Print data, useful for debuggging | |
} // end processPacket() | |
//============================================================================= | |
// Prints radio channel and RSSI | |
//============================================================================= | |
void printRadioInfo() | |
{ | |
Serial.print(F("ISS ID ")); | |
Serial.print((radio.DATA[0] & 0x07) + 1); | |
Serial.print(F("\tch: ")); | |
Serial.print(radio.CHANNEL); | |
Serial.print(F("\tRSSI: ")); | |
Serial.println(radio.RSSI); | |
} // end printRadioInfo() | |
//============================================================================= | |
// print ISS data packet in Hex | |
//============================================================================= | |
void printPacket() | |
{ | |
for (byte i = 0; i < DAVIS_PACKET_LEN; i++) | |
{ | |
if( radio.DATA[i] < 16 ) | |
{ Serial.print(F("0"));} // leading zero | |
Serial.print(radio.DATA[i], HEX); | |
Serial.print(F(" ")); | |
} | |
} // end printPacket() | |
//============================================================================= | |
// Prints KSS data - used for debugging | |
//============================================================================= | |
void printData(uint16_t rainSeconds) | |
{ | |
static uint32_t timeElapsed = millis(); // time elapsed since last tiem printData() was called. Pretty much the same as time between data packets received | |
static byte headerCounter = 0; | |
// Header | |
if (headerCounter == 0) | |
{ Serial.println("RxTime\tR-Cnt\tdaily\tr_secs\tr-rate\tmillis_sec\tspeed\tgusts\tAvgDir\tNowDir\ttemp\thumid\t\tpacket"); } | |
if( headerCounter++ > 20) | |
{ headerCounter = 0; } | |
Serial.print(millis() - timeElapsed); | |
Serial.print("\t"); | |
Serial.print(g_rainCounter); | |
Serial.print("\t"); | |
Serial.print(g_dayRain); | |
Serial.print("\t"); | |
Serial.print(rainSeconds); | |
Serial.print("\t"); | |
Serial.print(g_rainRate); | |
Serial.print("\t"); | |
Serial.print(millis()/1000); | |
Serial.print("\t"); | |
Serial.print(g_windSpeed); | |
Serial.print("\t"); | |
Serial.print(g_windgustmph); | |
Serial.print("\t"); | |
Serial.print(g_windDirection_Now); | |
Serial.print("\t"); | |
Serial.print(g_windDirection_Avg); | |
Serial.print("\t"); | |
Serial.print(g_outsideTemperature); | |
Serial.print("\t"); | |
Serial.print(g_outsideHumidity); | |
Serial.print("\t"); | |
printPacket(); | |
Serial.println(); | |
timeElapsed = millis(); // save new timestamp | |
} // end printData() | |
//============================================================================= | |
// Prints free RAM | |
//============================================================================= | |
void printFreeRam() | |
{ | |
extern int __heap_start, *__brkval; | |
int v; | |
Serial.print(F("Free mem: ")); | |
Serial.println((int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval)); | |
} // end printFreeRam() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello,
I have a problem.
When compile I have this message:
MoteinoMega_Davis_ISS_Test.ino:314: undefined reference to `DavisRFM69::DATA'