-
-
Save onetransistor/773ceee205a55e7e74146d75d93300b5 to your computer and use it in GitHub Desktop.
Arduino test sketch to capture and decode data from a weather station. A 433 MHz receiver module is required
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
#define BITS_PER_PACKET 36 | |
#define PACKETS_PER_STREAM 10 | |
const int decPin = 3; /* signal input pin; must be interrupt capable */ | |
volatile unsigned long lastInt = 0; /* the most recent interrupt time */ | |
volatile unsigned long currInt, currMicros; /* current interrupt time and current time for main loop */ | |
volatile unsigned long timeInt1 = 0, timeInt2 = 0; /* These variables store the last two pulse timings */ | |
volatile bool keepWaiting = true; /* this is reset when the signal is idle and we can start processing sampled data */ | |
bool rawBits[PACKETS_PER_STREAM][BITS_PER_PACKET + 1]; /* two dimension array for raw bitstream; number of rows and columns is set for expected signal */ | |
/* there is one extra bit at the end which will be used as complete flag (i.e. if the row has been filled by exactly 36 bits) */ | |
uint8_t i = 0, j = 0; /* i is the column, j is the row */ | |
uint8_t deviceID; | |
bool batteryState; | |
uint8_t channelNo; | |
float temperature; | |
uint8_t humidity; | |
void setup() { | |
Serial.begin(115200); | |
Serial.println("Decoder test..."); | |
pinMode(decPin, INPUT); | |
attachInterrupt(digitalPinToInterrupt(decPin), mapPulseTimingsToBits, CHANGE); | |
} | |
void loop() { | |
currMicros = micros(); | |
// if no interrupt has occured 10 ms after last change of signal | |
if (currMicros > lastInt + 10000 && keepWaiting == true) { | |
// and the current state of the signal is LOW (this is an optional check) | |
// current code gets pulse timings; it doesn't care about polarity | |
// only this state check is a basic polarity test, expecting LOW when idle | |
if (digitalRead(decPin) == LOW) { | |
// disable sampling pulses and process existing data | |
keepWaiting = false; | |
// if at least one packet received | |
if (j > 0) processRawBitstream(); | |
j = 0; | |
i = 0; // reset indexes | |
//Serial.println("\nData end"); | |
} | |
} | |
} | |
void mapPulseTimingsToBits() { | |
currInt = micros(); | |
// Copy the second pulse timing to the first variable | |
timeInt1 = timeInt2; | |
// Update the second pulse timing with the last measured pulse | |
timeInt2 = currInt - lastInt; | |
// Update the most recent interrupt time | |
lastInt = currInt; | |
// if the first pulse timing fits the ON state | |
if (timeInt1 > 400 && timeInt1 < 600) { | |
// continue sampling the signal | |
keepWaiting = true; | |
// check if the pulse that followed matches bit 0 | |
if (timeInt2 > 900 && timeInt2 < 1100) { | |
rawBits[j][i] = 0; | |
if (i < BITS_PER_PACKET) | |
i += 1; | |
else rawBits[j][BITS_PER_PACKET] = 0; // more than expected bits received; set error flag | |
// DEBUG: Serial.print("0"); | |
} | |
// otherwise if it maches bit 1 | |
else if (timeInt2 > 1900 && timeInt2 < 2100) { | |
rawBits[j][i] = 1; | |
if (i < BITS_PER_PACKET) | |
i += 1; | |
else rawBits[j][BITS_PER_PACKET] = 0; // more than expected bits received; set error flag | |
// DEBUG: Serial.print("1"); | |
} | |
// if it is longer than that is probably a sync pulse | |
else if (timeInt2 < 4500) { | |
// if less than 36 bits received, set the flag to false | |
if (i < (BITS_PER_PACKET - 1)) { | |
rawBits[j][BITS_PER_PACKET] = 0; | |
} else { | |
rawBits[j][BITS_PER_PACKET] = 1; | |
} | |
i = 0; // reset column | |
// start filling the next row; ignore extra streams | |
if (j < PACKETS_PER_STREAM) | |
j += 1; | |
// DEBUG: Serial.println(); | |
} | |
} | |
} | |
void processRawBitstream() { | |
bool finalBits[BITS_PER_PACKET] = { 0 }; | |
int8_t bitLowCnt = 0, bitHighCnt = 0; | |
for (int8_t b = 0; b < BITS_PER_PACKET; b++) { | |
for (int8_t a = 0; a < PACKETS_PER_STREAM; a++) { | |
// only if packet is complete | |
if (rawBits[a][BITS_PER_PACKET] == 1) { | |
// take each bit in the same position over all packets | |
// in theory all should be identical | |
// assuming poor signal strength, go with the majority | |
// by counting packets with each of the two bit states | |
if (rawBits[a][b] == 1) bitHighCnt += 1; | |
else bitLowCnt += 1; | |
if (bitHighCnt >= bitLowCnt) finalBits[b] = 1; | |
else finalBits[b] = 0; | |
bitLowCnt = 0; | |
bitHighCnt = 0; | |
} | |
} | |
} | |
Serial.print("\nProcessed bitstream: "); | |
for (int8_t i = 0; i < BITS_PER_PACKET; i++) { | |
Serial.print(finalBits[i], BIN); | |
} | |
Serial.println(); | |
// another sanity check | |
if (finalBits[24] && finalBits[25] && finalBits[26] && finalBits[27]) { | |
// get device ID | |
deviceID = 0; | |
for (int8_t i = 0; i < 8; i++) { | |
if (finalBits[i] == 1) deviceID |= 1 << (7 - i); | |
} | |
// get battery state | |
batteryState = finalBits[8]; | |
// get channel number | |
channelNo = (int8_t(finalBits[10]) << 1) | int8_t(finalBits[11]); | |
// get temperature | |
int16_t t12 = 0; | |
for (int8_t i = 0; i < 12; i++) { | |
if (finalBits[i + 12] == 1) t12 |= 1 << (11 - i); | |
} | |
temperature = t12 / 10.0; | |
// get humidity | |
humidity = 0; | |
for (int8_t i = 0; i < 8; i++) { | |
if (finalBits[i + 28] == 1) humidity |= 1 << (7 - i); | |
} | |
processDecodedData(); | |
} | |
} | |
void processDecodedData() { | |
Serial.println("\nDecoded data:"); | |
Serial.print("Device ID: "); | |
Serial.println(deviceID, DEC); | |
Serial.print("Battery State: "); | |
Serial.println(batteryState ? "Normal" : "Low"); | |
Serial.print("Channel: "); | |
Serial.println(channelNo); | |
Serial.print("Temperature: "); | |
Serial.println(temperature, 2); | |
Serial.print("Humidity: "); | |
Serial.println(humidity, DEC); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment