TheoV2Sensor2.ino 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /****************************************************************************************************************************\
  2. * Arduino project "TheoTinySensor" Copyright 2013 Theo Arends
  3. * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
  4. * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
  5. *
  6. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  7. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  8. ******************************************************************************************************************************
  9. ****************************************************************************************************************
  10. * Purpose : Arduino Source code for Sensor based on Atmel ATTiny85, running on 8MHz
  11. * Version : R201 - DHT11 or DHT22 and Vcc test
  12. * Date : 20140414
  13. * 20140507 - R202 - Verwijdering VCC_LOOP
  14. *
  15. * This code turns an Atmel ATTiny85 chip into a Sensor using the TheoV2 protocol.
  16. * This code is not of any use without running a Unit within RF range to receive sensor data.
  17. \***************************************************************************************************************/
  18. #define SENSOR_TYPE 2 // 2 = DHT22 or DHT11 sensor
  19. #define DHT22 // DHT22 Temperatuur en luchtvochtigheid
  20. //#define DHT11 // DHT11 Temperatuur en luchtvochtigheid
  21. // Uncomment for test purpose
  22. //#define THEO_TEST
  23. //*****************************************************************************
  24. #ifdef THEO_TEST
  25. #define CHANNEL 0 // 0 - 7, 0 discard by plugin
  26. #define SEND_DELAY 2 // Max Send Delay in multiples of 4.4 seconds, so 2 = 2x4.4=9 seconds
  27. #else
  28. #define CHANNEL 1 // 0 - 7, 0 discard by plugin
  29. #define SEND_DELAY 32 // Max Send Delay in multiples of 4.4 seconds, so 32 = 32x4.4=141 seconds
  30. #endif
  31. #define VREF_35 10675 // Measured value for Vref at 3.5V Vcc * 10 (Chip dependent)
  32. #define BATT_LOW 33 // 3.3V Battery low warning voltage * 10 (Functionality dependent)
  33. //*****************************************************************************
  34. #define DHT_PIN 1 // data to DHT11, fysieke pin 6 on ATTiny85
  35. #define RF_TransmitDataPin 4 // data to RF Transmitter, fysieke pin 3 on ATTiny85
  36. // ATMEL ATTINY85
  37. // AI=Analog Input
  38. // o-\/-+
  39. // reset 1| |8 VCC
  40. // Pin 3 (AI 3) PB3 2| |7
  41. // Pin 4 (AI 2) PB4 3| |6 PB1 PWM Pin 1 - PCINT1
  42. // GND 4| |5
  43. // +----+
  44. byte VccTest;
  45. byte Voltage;
  46. //*****************************************************************************
  47. // Setup stuff
  48. //*****************************************************************************
  49. void setup()
  50. {
  51. VccTest = 255;
  52. pinMode(RF_TransmitDataPin,OUTPUT);
  53. pinMode(DHT_PIN, OUTPUT);
  54. digitalWrite(DHT_PIN, HIGH); // Pull high
  55. delay(3000);
  56. Watchdog_setup(8); // Setup watchdog to notify us every 4.4 seconds
  57. }
  58. //*****************************************************************************
  59. // Main loop
  60. //*****************************************************************************
  61. void loop()
  62. {
  63. int payload1 = 0;
  64. int payload2 = 0;
  65. VccTest++;
  66. if (VccTest == 0) // Do not run the Vcc test too often to save Battery power
  67. {
  68. Voltage = ReadVcc();
  69. if (Voltage <= BATT_LOW)
  70. Voltage |= 0x80;
  71. }
  72. if (GetPayload(payload1, payload2) == 0)
  73. SendData(payload1, payload2);
  74. // Watchdog_sleep(SEND_DELAY + CHANNEL); // Go to deep sleep mode for some time
  75. Watchdog_sleep(SEND_DELAY - SENSOR_TYPE - CHANNEL); // Go to deep sleep mode for some time but not longer than 150 sec
  76. }
  77. //*****************************************************************************
  78. // Sleep stuff
  79. //*****************************************************************************
  80. #include <avr/sleep.h>
  81. #include <avr/wdt.h>
  82. void Watchdog_setup(int ii)
  83. {
  84. // 0=16ms, 1=32ms, 2=64ms, 3=125ms, 4=250ms, 5=500ms, 6=1s, 7=2s, 8=4s, 9=8s
  85. // The prescale value is held in bits 5,2,1,0
  86. // This block moves ii into these bits
  87. byte bb;
  88. if (ii > 9 ) ii=9;
  89. bb=ii & 7;
  90. if (ii > 7) bb|= (1<<5);
  91. bb|= (1<<WDCE);
  92. MCUSR &= ~(1<<WDRF); // Reset the watchdog reset flag
  93. WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
  94. WDTCR = bb; // Set new watchdog timeout value
  95. WDTCR |= _BV(WDIE); // Enable interrupts instead of reset
  96. }
  97. void Watchdog_sleep(int waitCounter)
  98. {
  99. while (waitCounter != 0)
  100. {
  101. bitClear(ADCSRA,ADEN); // Switch Analog to Digital converter OFF
  102. set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode
  103. sleep_mode(); // System sleeps here
  104. waitCounter--;
  105. }
  106. }
  107. ISR(WDT_vect)
  108. {
  109. // Don't do anything here but we must include this
  110. // block of code otherwise the interrupt calls an
  111. // uninitialized interrupt handler.
  112. }
  113. //*****************************************************************************
  114. // Send data via RF
  115. //*****************************************************************************
  116. #define RF_PULSE_0 500 // PWM: Tijdsduur van de puls bij verzenden van een '0' in uSec.
  117. #define RF_PULSE_MID 1000 // PWM: Pulsen langer zijn '1'
  118. #define RF_PULSE_1 1500 // PWM: Tijdsduur van de puls bij verzenden van een '1' in uSec. (3x RF_PULSE_0)
  119. #define RF_SPACE 500 // PWM: Tijdsduur van de space tussen de bitspuls bij verzenden van een '1' in uSec.
  120. #define TransmitRepeat 2
  121. void SendData(int payload1, int payload2)
  122. {
  123. struct
  124. {
  125. byte Checksum; // Checksum over following bytes
  126. byte Channel: 3; // 3 bits channel
  127. byte Type: 5; // 5 bits type
  128. byte Voltage; // Vcc like 45 = 4.5V, bit 8 is batt low
  129. int Payload1;
  130. int Payload2;
  131. } DataBlock;
  132. byte Size = sizeof(DataBlock);
  133. DataBlock.Type = SENSOR_TYPE;
  134. DataBlock.Channel = CHANNEL;
  135. DataBlock.Voltage = Voltage;
  136. DataBlock.Payload1 = payload1;
  137. DataBlock.Payload2 = payload2;
  138. byte c = 0, *B = (byte*)&DataBlock; // bereken checksum: crc-8 uit bovenstaande bytes in de struct
  139. for (byte x = 1; x < Size; x++)
  140. c +=*(B+x);
  141. DataBlock.Checksum = c;
  142. pinMode(RF_TransmitDataPin, OUTPUT);
  143. digitalWrite(RF_TransmitDataPin, LOW); // 0
  144. for (byte y = 0; y < TransmitRepeat; y++) // herhaal verzenden RF code
  145. {
  146. digitalWrite(RF_TransmitDataPin, HIGH); // 1
  147. delayMicroseconds(RF_PULSE_1 * 4);
  148. digitalWrite(RF_TransmitDataPin, LOW); // 0
  149. delayMicroseconds(RF_SPACE * 2);
  150. for (byte x = 0; x < Size; x++)
  151. {
  152. for (byte Bit = 0; Bit <= 7; Bit++)
  153. {
  154. digitalWrite(RF_TransmitDataPin, HIGH); // 1
  155. if ((*(B + x) >> Bit) & 1)
  156. delayMicroseconds(RF_PULSE_1);
  157. else
  158. delayMicroseconds(RF_PULSE_0);
  159. digitalWrite(RF_TransmitDataPin, LOW); // 0
  160. delayMicroseconds(RF_SPACE);
  161. }
  162. }
  163. delayMicroseconds(RF_PULSE_1 * 10);
  164. }
  165. }
  166. //*****************************************************************************
  167. // Measure battery voltage using internal bandgap voltage
  168. //*****************************************************************************
  169. byte ReadVcc()
  170. {
  171. int result;
  172. bitSet(ADCSRA, ADEN); // switch Analog to Digital converter ON
  173. ADMUX = 0x0C; // use VCC and internal bandgap (ATTiny85)
  174. delayMicroseconds(250); // delay substantially improves accuracy
  175. bitSet(ADCSRA, ADSC); // start conversion
  176. while (bit_is_set(ADCSRA, ADSC)); // wait until ADSC is clear
  177. bitClear(ADCSRA, ADEN); // Switch Analog to Digital converter OFF
  178. result = ADCW;
  179. return result ? VREF_35 / result : 0; // 35 = 3.5V
  180. }
  181. //*****************************************************************************
  182. // DHT11 or DHT22 Temperature and humidity sensor support
  183. //*****************************************************************************
  184. byte GetPayload(int &temperature, int &humidity)
  185. {
  186. return GetDHT(temperature, humidity);
  187. }
  188. //*****************************************************************************
  189. // DHT11 or DHT22 Temperature and humidity
  190. // http://forums.adafruit.com/viewtopic.php?f=25&t=43933
  191. // https://github.com/markruys/arduino-DHT
  192. //*****************************************************************************
  193. byte GetDHT(int &temperature, int &humidity)
  194. {
  195. unsigned long startTime = millis();
  196. word rawHumidity;
  197. word rawTemperature;
  198. word data;
  199. digitalWrite(DHT_PIN, LOW); // Send start signal
  200. pinMode(DHT_PIN, OUTPUT);
  201. #ifdef DHT22
  202. delayMicroseconds(800);
  203. #else
  204. delay(18);
  205. #endif
  206. pinMode(DHT_PIN, INPUT);
  207. digitalWrite(DHT_PIN, HIGH); // Switch bus to receive data
  208. // We're going to read 83 edges:
  209. // - First a FALLING, RISING, and FALLING edge for the start bit
  210. // - Then 40 bits: RISING and then a FALLING edge per bit
  211. // To keep our code simple, we accept any HIGH or LOW reading if it's max 85 usecs long
  212. for (int8_t i = -3 ; i < 2 * 40; i++)
  213. {
  214. byte age;
  215. startTime = micros();
  216. do
  217. {
  218. age = (unsigned long)(micros() - startTime);
  219. if (age > 90) return 1;
  220. }
  221. while (digitalRead(DHT_PIN) == (i & 1) ? HIGH : LOW);
  222. if (i >= 0 && (i & 1))
  223. {
  224. data <<= 1; // Now we are being fed our 40 bits
  225. if (age > 30) data |= 1; // A zero max 30 usecs, a one at least 68 usecs. We got a one
  226. }
  227. switch (i)
  228. {
  229. case 31:
  230. rawHumidity = data;
  231. break;
  232. case 63:
  233. rawTemperature = data;
  234. data = 0;
  235. break;
  236. }
  237. }
  238. // Verify checksum
  239. if ((byte)(((byte)rawHumidity) + (rawHumidity >> 8) + ((byte)rawTemperature) + (rawTemperature >> 8)) != data)
  240. return 2;
  241. #ifdef DHT22
  242. int t = (rawTemperature & 0x7fff) * 10;
  243. temperature = rawTemperature & 0x8000 ? - t : t;
  244. // humidity = (rawHumidity / 10) * 100; // round to whole
  245. humidity = rawHumidity * 10;
  246. #else
  247. humidity = (rawHumidity >> 8) * 100;
  248. temperature = (rawTemperature >> 8) * 100;
  249. #endif
  250. return 0;
  251. }