2 Updated code for receiving data from WH2 weather station
3 This code implements timeouts to make decoding more robust
4 Decodes received packets and writes a summary of each packet to the Arduino's
6 Created by Luc Small on 19 July 2013.
7 Released into the public domain.
14 // DHT11 and BMP085 wired sensors
18 // Humidity sensor at pin 4
27 // Read data from 433MHz receiver on digital pin 3
29 // For better efficiency, the port is read directly
30 // the following two lines should be changed appropriately
31 // if the line above is changed.
32 #define RF_IN_RAW PIND4
33 #define RF_IN_PIN PIND
35 // Port that is hooked to LED to indicate a packet has been received
37 #define COUNTER_RATE 3200-1 // 16,000,000Hz / 3200 = 5000 interrupts per second, ie. 200us between interrupts
38 // 1 is indicated by 500uS pulse
39 // wh2_accept from 2 = 400us to 3 = 600us
40 #define IS_HI_PULSE(interval) (interval >= 2 && interval <= 3)
41 // 0 is indicated by ~1500us pulse
42 // wh2_accept from 7 = 1400us to 8 = 1600us
43 #define IS_LOW_PULSE(interval) (interval >= 7 && interval <= 8)
44 // worst case packet length
45 // 6 bytes x 8 bits x (1.5 + 1) = 120ms; 120ms = 200us x 600
46 #define HAS_TIMED_OUT(interval) (interval > 600)
47 // we expect 1ms of idle time between pulses
48 // so if our pulse hasn't arrived by 1.2ms, reset the wh2_packet_state machine
50 #define IDLE_HAS_TIMED_OUT(interval) (interval > 6)
51 // our expected pulse should arrive after 1ms
52 // we'll wh2_accept it if it arrives after
54 #define IDLE_PERIOD_DONE(interval) (interval >= 4)
55 // Shorthand for tests
56 //#define RF_HI (digitalRead(RF_IN) == HIGH)
57 //#define RF_LOW (digitalRead(RF_IN) == LOW)
58 #define RF_HI (bit_is_set(RF_IN_PIN, RF_IN_RAW))
59 #define RF_LOW (bit_is_clear(RF_IN_PIN, RF_IN_RAW))
62 #define GOT_PULSE 0x01
64 volatile byte wh2_flags = 0;
65 volatile byte wh2_packet_state = 0;
66 volatile int wh2_timeout = 0;
68 byte wh2_calculated_crc;
75 ISR(TIMER1_COMPA_vect)
77 static byte sampling_state = 0;
79 static boolean was_low = false;
81 switch(sampling_state) {
94 case 1: // acquiring first pulse
98 if (IS_HI_PULSE(count)) {
99 wh2_flags = GOT_PULSE | LOGIC_HI;
102 } else if (IS_LOW_PULSE(count)) {
103 wh2_flags = GOT_PULSE; // logic low
111 case 2: // observe 1ms of idle time
114 if (IDLE_HAS_TIMED_OUT(count)) {
116 } else if (IDLE_PERIOD_DONE(count)) {
124 if (wh2_timeout > 0) {
126 if (HAS_TIMED_OUT(wh2_timeout)) {
127 wh2_packet_state = 0;
141 Serial1.begin(115200); // Set the baud.
143 // Wait for U-boot to finish startup. Consume all bytes until we are done.
145 while (Serial1.available() > 0) {
150 } while (Serial1.available()>0);
152 Serial1.begin(57600);
154 Serial1.println("STATUS:STARTING");
158 pinMode(REDPIN,OUTPUT);
159 pinMode(GREENPIN,OUTPUT);
161 pinMode(RF_IN, INPUT);
162 digitalWrite(RF_IN,HIGH);
167 OCR1A = COUNTER_RATE;
174 unsigned long previousMillis = 0;
175 unsigned long indoor_interval = 60000;
176 unsigned long outdoor_interval = 45000;
177 unsigned long previousIndoor = 0;
178 unsigned long previousOutdoor = 0;
198 Serial1.print("SENSOR:TYPE=OUTDOOR,");
200 Serial1.print("ID=");
201 Serial1.print(wh2_sensor_id(), HEX);
203 Serial1.print(",HUMIDITY=");
204 Serial1.print(wh2_humidity(), DEC);
206 Serial1.print(",TEMPERATURE=");
207 Serial1.println(format_temp(wh2_temperature()));
209 previousOutdoor = now;
210 digitalWrite(REDPIN,HIGH);
215 Serial1.println("ERROR:OUTDOOR");
216 previousOutdoor = now;
217 digitalWrite(REDPIN,LOW);
225 if ((unsigned long)(now - previousMillis) >= indoor_interval) {
227 previousMillis = now;
229 int chk = DHT.read11(DHT11PIN);
234 Serial1.print("SENSOR:TYPE=INDOOR,");
235 Serial1.print("HUMIDITY=");
236 Serial1.print(DHT.humidity);
237 Serial1.print(",TEMPERATURE=");
238 Serial1.print(DHT.temperature);
240 previousIndoor = now;
241 digitalWrite(GREENPIN,HIGH);
247 Serial1.println("ERROR:INDOOR");
248 previousIndoor = now;
249 digitalWrite(GREENPIN,LOW);
253 pressure=bmp.readPressure();
254 temperature=bmp.readTemperature();
256 Serial1.print("SENSOR:TYPE=BARO,");
257 Serial1.print("PRESSURE=");
258 Serial1.print(pressure);
259 Serial1.print(",TEMPERATURE=");
260 Serial1.println(temperature);
262 gas = analogRead(sensorPin); // Получаем значения из датчика
263 Serial1.print("SENSOR:TYPE=GAS,VALUE=");
264 Serial1.println(gas); // Пишем в серийный порт
268 if ((unsigned long)(now - previousIndoor) > indoor_interval*10) {
271 Serial1.println("ERROR:INDOOR TIMEOUT");
272 previousIndoor = now;
273 digitalWrite(GREENPIN,LOW);
277 if ((unsigned long)(now - previousOutdoor) > outdoor_interval*10) {
280 Serial1.println("ERROR:OUTDOOR TIMEOUT");
281 previousOutdoor = now;
282 digitalWrite(REDPIN,LOW);
290 // processes new pulse
293 static byte packet_no, bit_no, history;
295 // reset if in initial wh2_packet_state
296 if(wh2_packet_state == 0) {
297 // should history be 0, does it matter?
299 wh2_packet_state = 1;
300 // enable wh2_timeout
302 } // fall thru to wh2_packet_state one
305 if (wh2_packet_state == 1) {
306 // shift history right and store new value
308 // store a 1 if required (right shift along will store a 0)
309 if (wh2_flags & LOGIC_HI) {
312 // check if we have a valid start of frame
314 if ((history & B00000111) == B00000110) {
315 // need to clear packet, and counters
317 // start at 1 becuase only need to acquire 7 bits for first packet byte.
319 wh2_packet[0] = wh2_packet[1] = wh2_packet[2] = wh2_packet[3] = wh2_packet[4] = 0;
320 // we've acquired the preamble
321 wh2_packet_state = 2;
326 if (wh2_packet_state == 2) {
328 wh2_packet[packet_no] <<= 1;
329 if (wh2_flags & LOGIC_HI) {
330 wh2_packet[packet_no] |= 0x01;
347 // start the sampling process from scratch
348 wh2_packet_state = 0;
358 void wh2_calculate_crc()
360 wh2_calculated_crc = crc8(wh2_packet, 4);
365 return (wh2_calculated_crc == wh2_packet[4]);
370 return (wh2_packet[0] << 4) + (wh2_packet[1] >> 4);
375 return wh2_packet[3];
378 /* Temperature in deci-degrees. e.g. 251 = 25.1 */
379 int wh2_temperature()
382 temperature = ((wh2_packet[1] & B00000111) << 8) + wh2_packet[2];
384 if (wh2_packet[1] & B00001000) {
385 temperature = -temperature;
390 String format_temp(int temperature)
396 temperature = -temperature;
400 whole = temperature / 10;
401 partial = temperature - (whole*10);
403 s += String(whole, DEC);
405 s += String(partial, DEC);
411 uint8_t crc8( uint8_t *addr, uint8_t len)
415 // Indicated changes are from reference CRC-8 function in OneWire library
417 uint8_t inbyte = *addr++;
418 for (uint8_t i = 8; i; i--) {
419 uint8_t mix = (crc ^ inbyte) & 0x80; // changed from & 0x01
420 crc <<= 1; // changed from right shift
421 if (mix) crc ^= 0x31;// changed from 0x8C;
422 inbyte <<= 1; // changed from right shift