TheoV2Sensor1.ino 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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 : R109 - DS18B20 and BH1750 and Vcc test
  12. * Date : 20140502
  13. *
  14. * This code turns an Atmel ATTiny85 chip into a Sensor using the TheoV2 protocol.
  15. * This code is not of any use without running a Unit within RF range to receive sensor data.
  16. \***************************************************************************************************************/
  17. #define SENSOR_TYPE 1 // 1 = DS18B20 and BH1750 sensor
  18. // Uncomment for test purpose
  19. //#define THEO_TEST
  20. //*****************************************************************************
  21. #ifdef THEO_TEST
  22. #define CHANNEL 0 // 0 - 7, 0 discard by plugin
  23. #define SEND_DELAY 2 // Send Delay in multiples of 4 seconds, so 2 = 2x4=8 seconds
  24. #define VCC_LOOP 2
  25. #else
  26. #define CHANNEL 1 // 0 - 7, 0 discard by plugin
  27. #define SEND_DELAY 30 // Send Delay in multiples of 4 seconds, so 70 = 70x4=280 seconds
  28. #define VCC_LOOP 24 // Send Vcc once every hour
  29. #endif
  30. #define VREF_35 10885 // Measured value for Vref at 3.5V Vcc * 10 (Chip dependent)
  31. #define BATT_LOW 30 // 3.0V Battery low warning voltage * 10 (Functionality dependent)
  32. //*****************************************************************************
  33. #define DALLAS_PIN 1 // data to DS18B20, fysieke pin 6 on ATTiny85
  34. #define BH1750_ADDRESS 0x23 // i2c address BH1750
  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 PB2 (AI 1) Pin 2 - SCL
  41. // Pin 4 (AI 2) PB4 3| |6 PB1 PWM Pin 1 - PCINT1
  42. // GND 4| |5 PB0 PWM Pin 0 - SDA
  43. // +----+
  44. // Used by DS18B20
  45. #include <OneWire.h> // http://www.pjrc.com/teensy/arduino_libraries/OneWire.zip
  46. // Used by BH1750
  47. // Prepare library TinyWireM for 8MHz by editing the following files:
  48. // 1) file USI_TWI_Master.cpp define F_CPU from 1000000UL to 8000000UL
  49. // 2) file USI_TWI_Master.h define SYS_CLK from 1000.0 to 8000.0
  50. #include <TinyWireM.h> // http://playground.arduino.cc/Code/USIi2c
  51. byte VccTest;
  52. byte Voltage;
  53. //*****************************************************************************
  54. // Setup stuff
  55. //*****************************************************************************
  56. void setup()
  57. {
  58. VccTest = VCC_LOOP;
  59. pinMode(RF_TransmitDataPin,OUTPUT);
  60. TinyWireM.begin();
  61. Watchdog_setup(8); // Setup watchdog to notify us every 4 seconds
  62. }
  63. //*****************************************************************************
  64. // Main loop
  65. //*****************************************************************************
  66. void loop()
  67. {
  68. int payload1 = 0;
  69. int payload2 = 0;
  70. VccTest++;
  71. if (GetPayload(payload1, payload2) == 0)
  72. SendData(payload1, payload2);
  73. Watchdog_sleep(SEND_DELAY + CHANNEL); // Go to deep sleep mode for some time
  74. }
  75. //*****************************************************************************
  76. // Sleep stuff
  77. //*****************************************************************************
  78. #include <avr/sleep.h>
  79. #include <avr/wdt.h>
  80. void Watchdog_setup(int ii)
  81. {
  82. // 0=16ms, 1=32ms, 2=64ms, 3=125ms, 4=250ms, 5=500ms, 6=1s, 7=2s, 8=4s, 9=8s
  83. // The prescale value is held in bits 5,2,1,0
  84. // This block moves ii into these bits
  85. byte bb;
  86. if (ii > 9 ) ii=9;
  87. bb=ii & 7;
  88. if (ii > 7) bb|= (1<<5);
  89. bb|= (1<<WDCE);
  90. MCUSR &= ~(1<<WDRF); // Reset the watchdog reset flag
  91. WDTCR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
  92. WDTCR = bb; // Set new watchdog timeout value
  93. WDTCR |= _BV(WDIE); // Enable interrupts instead of reset
  94. }
  95. void Watchdog_sleep(int waitCounter)
  96. {
  97. while (waitCounter != 0)
  98. {
  99. bitClear(ADCSRA,ADEN); // Switch Analog to Digital converter OFF
  100. set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode
  101. sleep_mode(); // System sleeps here
  102. waitCounter--;
  103. }
  104. }
  105. void Watchdog_delay(int prescale)
  106. {
  107. Watchdog_setup(prescale);
  108. Watchdog_sleep(1);
  109. Watchdog_setup(8);
  110. }
  111. ISR(WDT_vect)
  112. {
  113. // Don't do anything here but we must include this
  114. // block of code otherwise the interrupt calls an
  115. // uninitialized interrupt handler.
  116. }
  117. //*****************************************************************************
  118. // Send data via RF
  119. //*****************************************************************************
  120. #define RF_PULSE_0 500 // PWM: Tijdsduur van de puls bij verzenden van een '0' in uSec.
  121. #define RF_PULSE_MID 1000 // PWM: Pulsen langer zijn '1'
  122. #define RF_PULSE_1 1500 // PWM: Tijdsduur van de puls bij verzenden van een '1' in uSec. (3x RF_PULSE_0)
  123. #define RF_SPACE 500 // PWM: Tijdsduur van de space tussen de bitspuls bij verzenden van een '1' in uSec.
  124. #define TransmitRepeat 2
  125. void SendData(int payload1, int payload2)
  126. {
  127. struct
  128. {
  129. byte Checksum; // Checksum over following bytes
  130. byte Channel: 3; // 3 bits channel
  131. byte Type: 5; // 5 bits type
  132. byte Voltage; // Vcc like 45 = 4.5V, bit 8 is batt low
  133. int Payload1;
  134. int Payload2;
  135. } DataBlock;
  136. byte Size = sizeof(DataBlock);
  137. DataBlock.Type = SENSOR_TYPE;
  138. DataBlock.Channel = CHANNEL;
  139. if (VccTest >= VCC_LOOP) // Do not run the Vcc test too often to save Battery power
  140. {
  141. VccTest = 0;
  142. Voltage = ReadVcc();
  143. if (Voltage <= BATT_LOW)
  144. Voltage |= 0x80;
  145. }
  146. DataBlock.Voltage = Voltage;
  147. DataBlock.Payload1 = payload1;
  148. DataBlock.Payload2 = payload2;
  149. byte c = 0, *B = (byte*)&DataBlock; // bereken checksum: crc-8 uit bovenstaande bytes in de struct
  150. for (byte x = 1; x < Size; x++)
  151. c +=*(B+x);
  152. DataBlock.Checksum = c;
  153. pinMode(RF_TransmitDataPin, OUTPUT);
  154. digitalWrite(RF_TransmitDataPin, LOW); // 0
  155. for (byte y = 0; y < TransmitRepeat; y++) // herhaal verzenden RF code
  156. {
  157. digitalWrite(RF_TransmitDataPin, HIGH); // 1
  158. delayMicroseconds(RF_PULSE_1 * 4);
  159. digitalWrite(RF_TransmitDataPin, LOW); // 0
  160. delayMicroseconds(RF_SPACE * 2);
  161. for (byte x = 0; x < Size; x++)
  162. {
  163. for (byte Bit = 0; Bit <= 7; Bit++)
  164. {
  165. digitalWrite(RF_TransmitDataPin, HIGH); // 1
  166. if ((*(B + x) >> Bit) & 1)
  167. delayMicroseconds(RF_PULSE_1);
  168. else
  169. delayMicroseconds(RF_PULSE_0);
  170. digitalWrite(RF_TransmitDataPin, LOW); // 0
  171. delayMicroseconds(RF_SPACE);
  172. }
  173. }
  174. delayMicroseconds(RF_PULSE_1 * 10);
  175. }
  176. }
  177. //*****************************************************************************
  178. // Measure battery voltage using internal bandgap voltage
  179. //*****************************************************************************
  180. byte ReadVcc()
  181. {
  182. int result;
  183. bitSet(ADCSRA, ADEN); // switch Analog to Digital converter ON
  184. ADMUX = 0x0C; // use VCC and internal bandgap (ATTiny85)
  185. delayMicroseconds(250); // delay substantially improves accuracy
  186. bitSet(ADCSRA, ADSC); // start conversion
  187. while (bit_is_set(ADCSRA, ADSC)); // wait until ADSC is clear
  188. bitClear(ADCSRA, ADEN); // Switch Analog to Digital converter OFF
  189. result = ADCW;
  190. return result ? VREF_35 / result : 0; // 35 = 3.5V
  191. }
  192. //*****************************************************************************
  193. // DS18B20 Temperature Sensor and BH1750 light sensor support
  194. //*****************************************************************************
  195. byte GetPayload(int &temperature, int &light)
  196. {
  197. if (GetDS18B20(temperature) != 0) return 1;
  198. if (GetBH1750(light) != 0) return 1;
  199. return 0;
  200. }
  201. //*****************************************************************************
  202. // DS18B20 Temperature
  203. //*****************************************************************************
  204. byte GetDS18B20(int &temperature)
  205. {
  206. byte msb, lsb;
  207. int temp;
  208. OneWire ds(DALLAS_PIN); // Setup a oneWire instance
  209. ds.reset();
  210. ds.skip();
  211. ds.write(0x44); // Start conversion
  212. Watchdog_delay(6); // Wait 750ms. Here 1 second
  213. ds.reset(); // Read DS18B20
  214. ds.skip();
  215. ds.write(0xBE); // Read scratchpad
  216. lsb = ds.read();
  217. msb = ds.read();
  218. ds.reset();
  219. temp = (msb<< 8) | lsb;
  220. temperature = ((((6 * temp) + temp / 4) + 5) / 10) * 10; // multiply by (100 * 0.0625) or 6.25 and round to tenth
  221. return 0;
  222. }
  223. //*****************************************************************************
  224. // BH1750 light
  225. //*****************************************************************************
  226. byte GetBH1750(int &light)
  227. {
  228. byte msb, lsb;
  229. unsigned int value;
  230. TinyWireM.beginTransmission(BH1750_ADDRESS); // Setup BH1750
  231. TinyWireM.send(0x20); // One time high resolution low power
  232. TinyWireM.endTransmission();
  233. Watchdog_delay(4); // Wait 160-180ms. Here 250ms
  234. TinyWireM.beginTransmission(BH1750_ADDRESS); // Read BH1750
  235. TinyWireM.requestFrom(BH1750_ADDRESS, 2);
  236. msb = TinyWireM.receive();
  237. lsb = TinyWireM.receive();
  238. value = (msb<<8 | lsb) / 1.2;
  239. if (value > 0x7fff) value = 0x7fff;
  240. light = int(value);
  241. return 0;
  242. }