xsns_05_ds18b20.ino 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. xsns_05_ds18b20.ino - DS18B20 temperature sensor support for Sonoff-Tasmota
  3. Copyright (C) 2018 Theo Arends
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #ifdef USE_DS18B20
  16. /*********************************************************************************************\
  17. * DS18B20 - Temperature - Single sensor
  18. \*********************************************************************************************/
  19. #define XSNS_05 5
  20. #define W1_SKIP_ROM 0xCC
  21. #define W1_CONVERT_TEMP 0x44
  22. #define W1_READ_SCRATCHPAD 0xBE
  23. float ds18b20_temperature = 0;
  24. uint8_t ds18b20_valid = 0;
  25. uint8_t ds18x20_pin = 0;
  26. char ds18b20_types[] = "DS18B20";
  27. /*********************************************************************************************\
  28. * Embedded stripped and tuned OneWire library
  29. \*********************************************************************************************/
  30. uint8_t OneWireReset(void)
  31. {
  32. uint8_t retries = 125;
  33. //noInterrupts();
  34. pinMode(ds18x20_pin, INPUT);
  35. do {
  36. if (--retries == 0) {
  37. return 0;
  38. }
  39. delayMicroseconds(2);
  40. } while (!digitalRead(ds18x20_pin));
  41. pinMode(ds18x20_pin, OUTPUT);
  42. digitalWrite(ds18x20_pin, LOW);
  43. delayMicroseconds(480);
  44. pinMode(ds18x20_pin, INPUT);
  45. delayMicroseconds(70);
  46. uint8_t r = !digitalRead(ds18x20_pin);
  47. //interrupts();
  48. delayMicroseconds(410);
  49. return r;
  50. }
  51. void OneWireWriteBit(uint8_t v)
  52. {
  53. static const uint8_t delay_low[2] = { 65, 10 };
  54. static const uint8_t delay_high[2] = { 5, 55 };
  55. v &= 1;
  56. //noInterrupts();
  57. digitalWrite(ds18x20_pin, LOW);
  58. pinMode(ds18x20_pin, OUTPUT);
  59. delayMicroseconds(delay_low[v]);
  60. digitalWrite(ds18x20_pin, HIGH);
  61. //interrupts();
  62. delayMicroseconds(delay_high[v]);
  63. }
  64. uint8_t OneWireReadBit(void)
  65. {
  66. //noInterrupts();
  67. pinMode(ds18x20_pin, OUTPUT);
  68. digitalWrite(ds18x20_pin, LOW);
  69. delayMicroseconds(3);
  70. pinMode(ds18x20_pin, INPUT);
  71. delayMicroseconds(10);
  72. uint8_t r = digitalRead(ds18x20_pin);
  73. //interrupts();
  74. delayMicroseconds(53);
  75. return r;
  76. }
  77. void OneWireWrite(uint8_t v)
  78. {
  79. for (uint8_t bit_mask = 0x01; bit_mask; bit_mask <<= 1) {
  80. OneWireWriteBit((bit_mask & v) ? 1 : 0);
  81. }
  82. }
  83. uint8_t OneWireRead(void)
  84. {
  85. uint8_t r = 0;
  86. for (uint8_t bit_mask = 0x01; bit_mask; bit_mask <<= 1) {
  87. if (OneWireReadBit()) {
  88. r |= bit_mask;
  89. }
  90. }
  91. return r;
  92. }
  93. boolean OneWireCrc8(uint8_t *addr)
  94. {
  95. uint8_t crc = 0;
  96. uint8_t len = 8;
  97. while (len--) {
  98. uint8_t inbyte = *addr++; // from 0 to 7
  99. for (uint8_t i = 8; i; i--) {
  100. uint8_t mix = (crc ^ inbyte) & 0x01;
  101. crc >>= 1;
  102. if (mix) {
  103. crc ^= 0x8C;
  104. }
  105. inbyte >>= 1;
  106. }
  107. }
  108. return (crc == *addr); // addr 8
  109. }
  110. /********************************************************************************************/
  111. void Ds18b20Convert(void)
  112. {
  113. OneWireReset();
  114. OneWireWrite(W1_SKIP_ROM); // Address all Sensors on Bus
  115. OneWireWrite(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end
  116. // delay(750); // 750ms should be enough for 12bit conv
  117. }
  118. boolean Ds18b20Read(void)
  119. {
  120. uint8_t data[9];
  121. int8_t sign = 1;
  122. if (ds18b20_valid) { ds18b20_valid--; }
  123. /*
  124. if (!OneWireReadBit()) { // Check end of measurement
  125. AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSOR_BUSY));
  126. return;
  127. }
  128. */
  129. for (uint8_t retry = 0; retry < 3; retry++) {
  130. OneWireReset();
  131. OneWireWrite(W1_SKIP_ROM);
  132. OneWireWrite(W1_READ_SCRATCHPAD);
  133. for (uint8_t i = 0; i < 9; i++) {
  134. data[i] = OneWireRead();
  135. }
  136. if (OneWireCrc8(data)) {
  137. uint16_t temp12 = (data[1] << 8) + data[0];
  138. if (temp12 > 2047) {
  139. temp12 = (~temp12) +1;
  140. sign = -1;
  141. }
  142. ds18b20_temperature = ConvertTemp(sign * temp12 * 0.0625);
  143. ds18b20_valid = SENSOR_MAX_MISS;
  144. return true;
  145. }
  146. }
  147. AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSOR_CRC_ERROR));
  148. return false;
  149. }
  150. /********************************************************************************************/
  151. void Ds18b20EverySecond(void)
  152. {
  153. ds18x20_pin = pin[GPIO_DSB];
  154. if (uptime &1) {
  155. // 2mS
  156. Ds18b20Convert(); // Start conversion, takes up to one second
  157. } else {
  158. // 12mS
  159. if (!Ds18b20Read()) { // Read temperature
  160. AddLogMissed(ds18b20_types, ds18b20_valid);
  161. }
  162. }
  163. }
  164. void Ds18b20Show(boolean json)
  165. {
  166. if (ds18b20_valid) { // Check for valid temperature
  167. char temperature[33];
  168. dtostrfd(ds18b20_temperature, Settings.flag2.temperature_resolution, temperature);
  169. if(json) {
  170. snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMP, mqtt_data, ds18b20_types, temperature);
  171. #ifdef USE_DOMOTICZ
  172. if (0 == tele_period) {
  173. DomoticzSensor(DZ_TEMP, temperature);
  174. }
  175. #endif // USE_DOMOTICZ
  176. #ifdef USE_KNX
  177. if (0 == tele_period) {
  178. KnxSensor(KNX_TEMPERATURE, ds18b20_temperature);
  179. }
  180. #endif // USE_KNX
  181. #ifdef USE_WEBSERVER
  182. } else {
  183. snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, ds18b20_types, temperature, TempUnit());
  184. #endif // USE_WEBSERVER
  185. }
  186. }
  187. }
  188. /*********************************************************************************************\
  189. * Interface
  190. \*********************************************************************************************/
  191. boolean Xsns05(byte function)
  192. {
  193. boolean result = false;
  194. if (pin[GPIO_DSB] < 99) {
  195. switch (function) {
  196. case FUNC_EVERY_SECOND:
  197. Ds18b20EverySecond();
  198. break;
  199. case FUNC_JSON_APPEND:
  200. Ds18b20Show(1);
  201. break;
  202. #ifdef USE_WEBSERVER
  203. case FUNC_WEB_APPEND:
  204. Ds18b20Show(0);
  205. break;
  206. #endif // USE_WEBSERVER
  207. }
  208. }
  209. return result;
  210. }
  211. #endif // USE_DS18B20