ds18b20.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // Copyright 2021 IOsetting <iosetting(at)outlook.com>
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "ds18b20.h"
  15. void DS18B20_Init(void)
  16. {
  17. /* Pull up 2 seconds for possible capacitor charging */
  18. DS18B20_DQ_PULLUP();
  19. DS18B20_DQ_OUTPUT();
  20. DS18B20_DQ = SET;
  21. SYS_Delay(1000);
  22. DS18B20_DQ = RESET;
  23. SYS_Delay(1);
  24. DS18B20_DQ = SET;
  25. SYS_Delay(1000);
  26. }
  27. __BIT DS18B20_Reset(void)
  28. {
  29. __BIT b;
  30. /* Line low, and wait 480us */
  31. DS18B20_DQ = RESET;
  32. DS18B20_DQ_OUTPUT();
  33. SYS_DelayUs(500);
  34. /* Release line and wait for 70us */
  35. DS18B20_DQ_INPUT();
  36. SYS_DelayUs(70);
  37. /* Check bit value, success if low */
  38. b = DS18B20_DQ;
  39. /* Delay for 410 us */
  40. SYS_DelayUs(410);
  41. /* Return value of presence pulse, 0 = OK, 1 = ERROR */
  42. return b;
  43. }
  44. __BIT DS18B20_ReadBit(void)
  45. {
  46. __BIT b = RESET;
  47. /* Line low */
  48. DS18B20_DQ = RESET;
  49. DS18B20_DQ_OUTPUT();
  50. SYS_DelayUs(2);
  51. /* Release line */
  52. DS18B20_DQ_INPUT();
  53. SYS_DelayUs(10);
  54. /* Read line value */
  55. if (DS18B20_DQ) {
  56. /* Bit is HIGH */
  57. b = SET;
  58. }
  59. /* Wait 50us to complete 60us period */
  60. SYS_DelayUs(50);
  61. /* Return bit value */
  62. return b;
  63. }
  64. uint8_t DS18B20_ReadByte(void)
  65. {
  66. uint8_t i = 8, byte = 0;
  67. while (i--)
  68. {
  69. byte >>= 1;
  70. if (DS18B20_ReadBit())
  71. {
  72. byte |= 0x80;
  73. }
  74. }
  75. return byte;
  76. }
  77. void DS18B20_WriteBit(__BIT b)
  78. {
  79. if (b)
  80. {
  81. /* Set line low */
  82. DS18B20_DQ = RESET;
  83. DS18B20_DQ_OUTPUT();
  84. SYS_DelayUs(10);
  85. /* Bit high */
  86. DS18B20_DQ_INPUT();
  87. /* Wait for 55 us and release the line */
  88. SYS_DelayUs(55);
  89. DS18B20_DQ_INPUT();
  90. }
  91. else
  92. {
  93. /* Set line low */
  94. DS18B20_DQ = RESET;
  95. DS18B20_DQ_OUTPUT();
  96. SYS_DelayUs(65);
  97. /* Bit high */
  98. DS18B20_DQ_INPUT();
  99. /* Wait for 5 us and release the line */
  100. SYS_DelayUs(5);
  101. DS18B20_DQ_INPUT();
  102. }
  103. }
  104. void DS18B20_WriteByte(uint8_t byte)
  105. {
  106. uint8_t i = 8;
  107. /* Write 8 bits */
  108. while (i--)
  109. {
  110. /* LSB bit is first */
  111. DS18B20_WriteBit(byte & 0x01);
  112. byte >>= 1;
  113. }
  114. }
  115. void DS18B20_ReadScratchpad(uint8_t *buf)
  116. {
  117. uint8_t i = 0;
  118. /* Reset line */
  119. DS18B20_Reset();
  120. /* Skip ROM */
  121. DS18B20_WriteByte(ONEWIRE_CMD_SKIPROM);
  122. /* Read scratchpad command by onewire protocol */
  123. DS18B20_WriteByte(ONEWIRE_CMD_RSCRATCHPAD);
  124. /* Get data */
  125. for (i = 0; i < 9; i++)
  126. {
  127. /* Read byte by byte */
  128. *buf++ = DS18B20_ReadByte();
  129. }
  130. }
  131. uint8_t DS18B20_Crc(uint8_t *addr, uint8_t len)
  132. {
  133. uint8_t crc = 0, inbyte, i, mix;
  134. while (len--)
  135. {
  136. inbyte = *addr++;
  137. for (i = 8; i; i--)
  138. {
  139. mix = (crc ^ inbyte) & 0x01;
  140. crc >>= 1;
  141. if (mix)
  142. {
  143. crc ^= 0x8C;
  144. }
  145. inbyte >>= 1;
  146. }
  147. }
  148. /* Return calculated CRC */
  149. return crc;
  150. }
  151. void DS18B20_StartAll(void)
  152. {
  153. /* Reset pulse */
  154. DS18B20_Reset();
  155. /* Skip rom */
  156. DS18B20_WriteByte(ONEWIRE_CMD_SKIPROM);
  157. /* Start conversion on all connected devices */
  158. DS18B20_WriteByte(DS18B20_CMD_CONVERTTEMP);
  159. }
  160. __BIT DS18B20_AllDone(void)
  161. {
  162. /* If read bit is low, then device is not finished yet with calculation temperature */
  163. return DS18B20_ReadBit();
  164. }
  165. void DS18B20_ReadRom(uint8_t *buf)
  166. {
  167. uint8_t i = 0;
  168. /* Reset pulse */
  169. DS18B20_Reset();
  170. /* Read rom */
  171. DS18B20_WriteByte(ONEWIRE_CMD_READROM);
  172. /* Get data */
  173. for (i = 0; i < 8; i++)
  174. {
  175. /* Read byte by byte */
  176. *buf++ = DS18B20_ReadByte();
  177. }
  178. }
  179. void DS18B20_Select(const uint8_t* addr)
  180. {
  181. uint8_t len = 8;
  182. DS18B20_WriteByte(ONEWIRE_CMD_MATCHROM);
  183. while (len--)
  184. {
  185. DS18B20_WriteByte(*addr++);
  186. }
  187. }
  188. void DS18B20_Start(const uint8_t *addr)
  189. {
  190. /* Reset pulse */
  191. DS18B20_Reset();
  192. /* Select ROM number */
  193. DS18B20_Select(addr);
  194. /* Start conversion on selected device */
  195. DS18B20_WriteByte(DS18B20_CMD_CONVERTTEMP);
  196. }
  197. void DS18B20_ReadScratchpadFromAddr(const uint8_t *addr, uint8_t *buf)
  198. {
  199. uint8_t i = 0;
  200. /* Reset line */
  201. DS18B20_Reset();
  202. /* Select ROM number */
  203. DS18B20_Select(addr);
  204. /* Read scratchpad command by onewire protocol */
  205. DS18B20_WriteByte(ONEWIRE_CMD_RSCRATCHPAD);
  206. /* Get data */
  207. for (i = 0; i < 9; i++)
  208. {
  209. /* Read byte by byte */
  210. *buf++ = DS18B20_ReadByte();
  211. }
  212. }
  213. uint8_t DS18B20_Search(uint8_t *buff, uint8_t *stack, uint8_t split_point)
  214. {
  215. uint8_t len = 64, pos = 0;
  216. /* Start from deepest point */
  217. split_point = (split_point == 0x00)? 0xFF : split_point;
  218. /* Reset line */
  219. DS18B20_Reset();
  220. /* Start searching */
  221. DS18B20_WriteByte(ONEWIRE_CMD_SEARCHROM);
  222. while (len--)
  223. {
  224. // Read the value and its complement value of this bit
  225. __BIT pb = DS18B20_ReadBit();
  226. __BIT cb = DS18B20_ReadBit();
  227. if (pb && cb) // no device
  228. {
  229. return 0;
  230. }
  231. else if (pb) // bit = 1
  232. {
  233. *(buff + pos / 8) |= 0x01 << (pos % 8);
  234. DS18B20_WriteBit(SET);
  235. // confirm: set this bit to 1
  236. *(stack + pos / 8) |= 0x01 << (pos % 8);
  237. }
  238. else if (cb) // bit = 0
  239. {
  240. *(buff + pos / 8) &= ~(0x01 << (pos % 8));
  241. DS18B20_WriteBit(RESET);
  242. // confirm: set this bit to 1
  243. *(stack + pos / 8) |= 0x01 << (pos % 8);
  244. }
  245. else // bit can be 0 or 1, possible split point
  246. {
  247. if (split_point == 0xFF || pos > split_point)
  248. {
  249. // new split point, try 0
  250. *(buff + pos / 8) &= ~(0x01 << (pos % 8));
  251. DS18B20_WriteBit(RESET);
  252. // unconfirm: set this bit to 0
  253. *(stack + pos / 8) &= ~(0x01 << (pos % 8));
  254. // record this new split point
  255. split_point = pos;
  256. }
  257. else if (pos == split_point)
  258. {
  259. // reach split point, try 1
  260. *(buff + pos / 8) |= 0x01 << (pos % 8);
  261. DS18B20_WriteBit(SET);
  262. // confirm: set this bit to 1
  263. *(stack + pos / 8) |= 0x01 << (pos % 8);
  264. }
  265. else // middle point, use existing bit
  266. {
  267. DS18B20_WriteBit(*(buff + pos / 8) >> (pos % 8) & 0x01);
  268. }
  269. }
  270. pos++;
  271. }
  272. // Relocate split point, move it to the last *unconfirmed* bit of stack
  273. while (split_point > 0 && *(stack + split_point / 8) >> (split_point % 8) & 0x01 == 0x01) split_point--;
  274. return split_point;
  275. }