{"id":5000,"date":"2023-04-27T13:23:21","date_gmt":"2023-04-27T11:23:21","guid":{"rendered":"https:\/\/www.dclabs.lt\/dainiaus\/?p=5000"},"modified":"2026-03-20T09:23:58","modified_gmt":"2026-03-20T07:23:58","slug":"ds18b20-temperature-sensor-with-stm32","status":"publish","type":"post","link":"https:\/\/www.dclabs.lt\/dainiaus\/ds18b20-temperature-sensor-with-stm32\/","title":{"rendered":"DS18B20 temperature sensor with STM32"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">This one is for my friend Nico <img decoding=\"async\" draggable=\"false\" class=\"eedee-emoji\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/12.0.0-1\/svg\/1f60b.svg\" alt=\"\ud83d\ude0b\"> and other readers who knows English. Some readers remember, that we already tested the work of <a href=\"https:\/\/www.dclabs.lt\/dainiaus\/?p=2076\" data-type=\"URL\" data-id=\"https:\/\/www.dclabs.lt\/dainiaus\/?p=2076\" target=\"_blank\" rel=\"noreferrer noopener\">DS18B20 with Atmega328P on Arduino board<\/a>, that was easy, because of ready libraries. But lets put away toys and use <a href=\"https:\/\/www.dclabs.lt\/dainiaus\/?p=4023\" data-type=\"URL\" data-id=\"https:\/\/www.dclabs.lt\/dainiaus\/?p=4023\" target=\"_blank\" rel=\"noreferrer noopener\">STM32F466RE on Nucleo-F446RE<\/a> development board. We already have <a href=\"https:\/\/www.dclabs.lt\/dainiaus\/?p=4072\" data-type=\"URL\" data-id=\"https:\/\/www.dclabs.lt\/dainiaus\/?p=4072\" target=\"_blank\" rel=\"noreferrer noopener\">LCD display outputting some information<\/a>, so lets use it to display temperature, but we will not use DMA this time. First, lets prepare the DS18B20 sensor for connection with microprocessor. The only required thing in 3 wire configuration is 4,7 k\u2126 pull-up resistor:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-14.png\"><img loading=\"lazy\" decoding=\"async\" width=\"486\" height=\"327\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-14.png\" alt=\"\" class=\"wp-image-5005\" style=\"width:339px;height:228px\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-14.png 486w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-14-300x202.png 300w\" sizes=\"auto, (max-width: 486px) 100vw, 486px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Thus, between positive power (+3,3V or +5V) and DQ (data) wires connected 4,7 k\u2126 resistor. If the microprocessor or microcontroller has internal pull-up resistors, they might be enabled in program, so we wouldn&#8217;t need additional external resistor. Next &#8211; let&#8217;s connect the sensor and configure STM32 to use LCD and assign pin for DS18B20. Connection is easy, used +3,3V, GND and PA0 pins. Why PA0 ? Because its closest to power pins:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-15.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"828\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-15-1024x828.png\" alt=\"\" class=\"wp-image-5009\" style=\"width:496px;height:401px\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-15-1024x828.png 1024w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-15-300x243.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-15-768x621.png 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-15.png 1180w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Could be any other pin, which can be configured as GPIO_Output. Later we will also try enabling the internal pull-up and dropping the external resistor. After configuring the microprocessor pins, view should be similar to:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-17.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"972\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-17-1024x972.png\" alt=\"\" class=\"wp-image-5012\" style=\"width:642px;height:609px\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-17-1024x972.png 1024w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-17-300x285.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-17-768x729.png 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-17.png 1414w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Pins:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>DS18B20_Data &#8211; GPIO_Output, PA0 pin, where we connected the Data (DQ) pin of the DS18B20;<\/li>\n\n\n\n<li>HEARTBEAT &#8211; GPIO_Output, PA5 pin, this pin has LED connected, used for troubleshooting and will not be used in the final program;<\/li>\n\n\n\n<li>TFT_Backlight &#8211; TIM14_CH1, PA7 pin, uses Channel1 PWM generation for LCD backlight control;<\/li>\n\n\n\n<li>TFT_SCK &#8211; SPI2_SCK, PB13 pin, used to clock the LCD;<\/li>\n\n\n\n<li>TFT_MISO &#8211; SPI2_MISO, PB14 pin, used for MISO data (Master Input, Slave Output);<\/li>\n\n\n\n<li>TFT_MOSI &#8211; SPI2_MOSI, PB15 pin, used for MOSI data (Master Output, Slave Input);<\/li>\n\n\n\n<li>TFT_D-C &#8211; GPIO_Output, PC7 pin, D\/C signal for LCD (Data\/Control);<\/li>\n\n\n\n<li>SD_CS &#8211; GPIO_Output, SD card Chip Select signal, not used in our program;<\/li>\n\n\n\n<li>TFT_CD &#8211; GPIO_Output, TFT Chip Select signal;<\/li>\n\n\n\n<li>TFT_Reset &#8211; GPIO_Output, TFT Reset signal.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Ok, that is all configuration. Next &#8211; programming <img decoding=\"async\" draggable=\"false\" class=\"eedee-emoji\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/12.0.0-1\/svg\/1f601.svg\" alt=\"\ud83d\ude01\">, step by step. First lets initialize the HEARBEAT, so the on board LED would blink, showing, that the microprocessor is alive. To the &#8222;main(void)&#8221;, which runs only once, after the microprocessor is started:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  \/* USER CODE BEGIN 2 *\/\n  static unsigned short pin_state = 0; \/\/ Init variable\n  \/* USER CODE END 2 *\/<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  while (1)\n  {\n    \/* USER CODE END WHILE *\/\n\t  HAL_GPIO_WritePin(GPIOA, HEARTBEAT_Pin, pin_state);  \/\/ Yellow LED\n\t  pin_state = !pin_state;\n\t  HAL_Delay(500);\n    \/* USER CODE BEGIN 3 *\/\n  }<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">So, initialized the variable pin_state and in the cycle &#8222;while 1&#8221;, which is running always again and again, with each iteration doing what is inside, we change the pin_state to opposite. First line HAL_GPIO_WritePin write the pin_state to pin, thus at first iteration it writes &#8222;0&#8221; = 0V (from init variable line), then second line makes the pin_state opposite, thus &#8222;1&#8221; = 3,3V, then waist 0,5 second and then everything starts from the beginning, only that pin_state is already changed to &#8222;1&#8221; so the first line makes microprocessor pin output 3,3V and LED is ON. Easy, lets go further. We need to make the LCD work, so let&#8217;s initialize it. We can use some already made libraries, but heh, I never choose the easy way, if there is a chance to train the brains to work more. As we already know the LCD controller datasheet information, easy to define all he commands that may be used with this particular LCD:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/* Private define ------------------------------------------------------------*\/\n\/* USER CODE BEGIN PD *\/\n\/\/ All commands\n#define NOP     \t0x00 \/\/ DC = 0\n#define SWRESET \t0x01 \/\/ DC = 0\n#define RDDID   \t0x04 \/\/ DC = 0 + 1\n#define RDDST   \t0x09 \/\/ DC = 0 + 1\n#define RDDPM   \t0x0A \/\/ DC = 0 + 1\n#define RDDMADCTL   0x0B \/\/ DC = 0 + 1\n#define RDDCOLMOD   0x0C \/\/ DC = 0 + 1\n#define RDDIM   \t0x0D \/\/ DC = 0 + 1\n#define RDDSM  \t\t0x0E \/\/ DC = 0 + 1\n#define SLPIN   \t0x10 \/\/ DC = 0\n#define SLPOUT  \t0x11 \/\/ DC = 0\n#define PTLON   \t0x12 \/\/ DC = 0\n#define NORON   \t0x13 \/\/ DC = 0\n#define INVOFF   \t0x20 \/\/ DC = 0\n#define INVON   \t0x21 \/\/ DC = 0\n#define GAMSET \t\t0x26 \/\/ DC = 0 + 1\n#define DISPOFF \t0x28 \/\/ DC = 0\n#define DISPON  \t0x29 \/\/ DC = 0\n#define CASET   \t0x2A \/\/ DC = 0 + 1\n#define RASET   \t0x2B \/\/ DC = 0 + 1\n#define RAMWR   \t0x2C \/\/ DC = 0 + 1\n#define RAMRD   \t0x2E \/\/ DC = 0 + 1\n#define PTLAR   \t0x30 \/\/ DC = 0 + 1\n#define TEOFF  \t\t0x34 \/\/ DC = 0\n#define TEON  \t\t0x35 \/\/ DC = 0 + 1\n#define MADCTL  \t0x36 \/\/ DC = 0 + 1\n#define IDMOFF  \t0x38 \/\/ DC = 0\n#define IDMON  \t\t0x39 \/\/ DC = 0\n#define COLMOD  \t0x3A \/\/ DC = 0 + 1\n#define FRMCTR1  \t0xB1 \/\/ DC = 0 + 1\n#define FRMCTR2  \t0xB2 \/\/ DC = 0 + 1\n#define FRMCTR3  \t0xB3 \/\/ DC = 0 + 1\n#define INVCTR  \t0xB4 \/\/ DC = 0 + 1\n#define DISSET5  \t0xB6 \/\/ DC = 0 + 1\n#define PWCTR1  \t0xC0 \/\/ DC = 0 + 1\n#define PWCTR2  \t0xC1 \/\/ DC = 0 + 1\n#define PWCTR3  \t0xC2 \/\/ DC = 0 + 1\n#define PWCTR4  \t0xC3 \/\/ DC = 0 + 1\n#define PWCTR5  \t0xC4 \/\/ DC = 0 + 1\n#define VMCTR1  \t0xC5 \/\/ DC = 0 + 1\n#define VMOFCTR  \t0xC7 \/\/ DC = 0 + 1\n#define WRID2\t  \t0xD1 \/\/ DC = 0 + 1\n#define WRID3   \t0xD2 \/\/ DC = 0 + 1\n#define PWCTR6   \t0xFC \/\/ DC = 0 + 1\n#define NVCTR1   \t0xD9 \/\/ DC = 0 + 1\n#define NVCTR2   \t0xDE \/\/ DC = 0 + 1\n#define NVCTR3   \t0xDF \/\/ DC = 0 + 1\n#define RDID1   \t0xDA \/\/ DC = 0 + 1\n#define RDID2   \t0xDB \/\/ DC = 0 + 1\n#define RDID3   \t0xDC \/\/ DC = 0 + 1\n#define GAMCTRP1   \t0xE0 \/\/ DC = 0 + 1\n#define GAMCTRN1   \t0xE1 \/\/ DC = 0 + 1\n#define EXTCTRL   \t0xF0 \/\/ DC = 0 + 1\n#define VCOM4L   \t0xFF \/\/ DC = 0 + 1\n\/* USER CODE END PD *\/<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">DC = 0 + 1 means sending Command and Data, if no + 1 &#8211; then sending only command. Just my way to memorize the format of information that must be sent to LCD. When we have all the commands, lets try to initialize the LCD. We will need:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void TFT_start_init(void);\nvoid SPI_sendCommand(uint8_t command);\nvoid SPI_sendData(uint8_t *buff, size_t buff_size);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Initialize TFT, and send commands and data to it. Lets write functions doing that:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/============================================================================\nvoid TFT_start_init(void) {\n\n\tHAL_GPIO_WritePin(GPIOB, TFT_Reset_Pin, RESET);\t\/\/ RS - active low, thus resetting display with low\n\tHAL_Delay(20);\t\t\t\t\t\/\/ Min reset time 10 ms, doubled to be sure\n\tHAL_GPIO_WritePin(GPIOB, TFT_Reset_Pin, SET); \/\/ RS - active low, thus defaulting to high\n\tHAL_Delay(120);\t\t\t\t\t\t\t\t   \/\/ After HW reset time 120 ms\n\n\tSPI_sendCommand(SWRESET);\t\t\t\t\t\t\/\/ 0x01\n\tHAL_Delay(120);\t\t\t\t\t\t\t\t\t\/\/ After SWRESET time 120 ms\n\n\tSPI_sendCommand(SLPOUT);\t\t\t\t\t\t\/\/ 0x11\n\tHAL_Delay(120);\t\t\t\t\t\t\t\t\t\/\/ After SLPOUT time 120 ms\n\n\tSPI_sendCommand(FRMCTR1);\t\t\t\t\t\t\/\/ 0xB1\n\tuint8_t FRMCTR1data&#91;] = { 0x03, 0x01, 0x01 };\n\tSPI_sendData(FRMCTR1data, sizeof(FRMCTR1data));\n\n\tSPI_sendCommand(FRMCTR2);\t\t\t\t\t\t\/\/ 0xB2\n\tuint8_t FRMCTR2data&#91;] = { 0x03, 0x01, 0x01 };\n\tSPI_sendData(FRMCTR2data, sizeof(FRMCTR2data));\n\n\tSPI_sendCommand(FRMCTR3);\t\t\t\t\t\t\/\/ 0xB3\n\tuint8_t FRMCTR3data&#91;] = { 0x03, 0x01, 0x01, 0x03, 0x01, 0x01 };\n\tSPI_sendData(FRMCTR3data, sizeof(FRMCTR3data));\n\n\tSPI_sendCommand(INVCTR);\t\t\t\t\t\t\/\/ 0xB4\n\tuint8_t INVCTRdata&#91;] = { 0x07 };\n\tSPI_sendData(INVCTRdata, sizeof(INVCTRdata));\n\n\tSPI_sendCommand(PWCTR1);\t\t\t\t\t\t\/\/ 0xC0\n\tuint8_t PWCTR1data&#91;] = { 0x1D, 0x70, };\t\/\/ 1D = 3,35 V 0x11 = 1 uA\n\tSPI_sendData(PWCTR1data, sizeof(PWCTR1data));\n\n\tSPI_sendCommand(PWCTR2);\t\t\t\t\t\t\/\/ 0xC1\n\tuint8_t PWCTR2data&#91;] = { 0x05 };\t\t\t\t\/\/\n\tSPI_sendData(PWCTR2data, sizeof(PWCTR2data));\n\n\tSPI_sendCommand(PWCTR3);\t\t\t\t\t\t\/\/ 0xC2\n\tuint8_t PWCTR3data&#91;] = { 0x03, 0x00 };\t\t\t\/\/\n\tSPI_sendData(PWCTR3data, sizeof(PWCTR3data));\n\n\tSPI_sendCommand(PWCTR4);\t\t\t\t\t\t\/\/ 0xC3\n\tuint8_t PWCTR4data&#91;] = { 0x03, 0x00 };\t\t\t\/\/\n\tSPI_sendData(PWCTR4data, sizeof(PWCTR4data));\n\n\tSPI_sendCommand(PWCTR5);\t\t\t\t\t\t\/\/ 0xC4\n\tuint8_t PWCTR5data&#91;] = { 0x03, 0x00 };\t\t\t\/\/\n\tSPI_sendData(PWCTR5data, sizeof(PWCTR5data));\n\n\tSPI_sendCommand(VMCTR1);\t\t\t\t\t\t\/\/ 0xC4\n\tuint8_t VMCTR1data&#91;] = { 0x20, 0x64 };\t\t\t\/\/\n\tSPI_sendData(VMCTR1data, sizeof(VMCTR1data));\n\n\tSPI_sendCommand(INVOFF);\t\t\t\t\t\t\/\/ Color inversion\n\n\tSPI_sendCommand(MADCTL);\t\t\t\t\t\t\/\/ 0x36\n\tuint8_t MADCTLdata&#91;] = { 0x08 };\t\t\t\t\/\/\n\tSPI_sendData(MADCTLdata, sizeof(MADCTLdata));\n\n\tSPI_sendCommand(COLMOD);\t\t\t\t\t\t\/\/ 0x3A\n\tuint8_t COLMODdata&#91;] = { 0x05 };\t\t\t\t\/\/\n\tSPI_sendData(COLMODdata, sizeof(COLMODdata));\n\n\tSPI_sendCommand(CASET);\t\t\t\t\t\t\t\/\/ 0x2A\n\tuint8_t CASETdata&#91;] = { 0x00, 0x00, 0x00, 0x00 };\t\t\t\t\/\/\n\tSPI_sendData(CASETdata, sizeof(CASETdata));\n\n\tSPI_sendCommand(RASET);\t\t\t\t\t\t\t\/\/ 0x2B\n\tuint8_t RASETdata&#91;] = { 0x00, 0x00, 0x00, 0x00 };\t\t\t\t\/\/\n\tSPI_sendData(RASETdata, sizeof(RASETdata));\n\n\tSPI_sendCommand(NORON);\t\t\t\t\t\t\t\/\/ 0x13\n\tHAL_Delay(10);\n\n\tSPI_sendCommand(DISPON);\t\t\t\t\t\t\/\/ 0x29\n\tST7735_FillScreen(0x001F);  \t\t\t\t\t\/\/ Set brown background\n\tST7735_WriteString(0, 0, \"Temperature:\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\n}\n\nvoid SPI_sendCommand(uint8_t command) {\n\tHAL_GPIO_WritePin(GPIOA, TFT_CS_Pin, RESET); \/\/ Chipselect, active low - selected\n\tHAL_GPIO_WritePin(GPIOC, TFT_D_C_Pin, RESET);\t\/\/ Command register - low\n\tHAL_SPI_Transmit(&amp;hspi2, &amp;command, sizeof(command), HAL_MAX_DELAY);\t\/\/ Send command\n\tHAL_GPIO_WritePin(GPIOA, TFT_CS_Pin, SET);\/\/ Chipselect, active low - unselected\n\n}\n\/\/----------------------------------------------------------------------------\nvoid SPI_sendData(uint8_t *buff, size_t buff_size) {\n\tHAL_GPIO_WritePin(GPIOA, TFT_CS_Pin, RESET); \/\/ Chipselect, active low - selected\n\tHAL_GPIO_WritePin(GPIOC, TFT_D_C_Pin, SET);\t\t\t\/\/ Data register - high\n\tHAL_SPI_Transmit(&amp;hspi2, buff, buff_size, HAL_MAX_DELAY);\t\/\/ Send data\n\tHAL_GPIO_WritePin(GPIOA, TFT_CS_Pin, SET);\/\/ Chipselect, active low - unselected\n}\n\/\/----------------------------------------------------------------------------<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Its a bit long, but also quite clear from comments, so I&#8217;ll skip the explanation. Ok, now we have the initialization function, lets add it to be run once, after the system starts (to the main(void)):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t\/* USER CODE BEGIN 2 *\/\n\tstatic unsigned short pin_state = 0; \/\/ Init variable\n\tTFT_start_init();\n\t\/* USER CODE END 2 *\/<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now the microprocessor will start, init all it needs in the background, then make a variable and then TFT_start_init(). At this point decided to use ST7735 LCD controller library, just to speed up the development, but, probably, later will write a complete program without a library. So, the TFT_start_init function is doing all the things, which must be done according to ST7735 datasheet, to initialize it, and then in the end we use the library:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\tST7735_FillScreen(0x001F);  \t\t\t\t\t\/\/ Set brown background\n\tST7735_WriteString(0, 0, \"Temperature:\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">First line &#8211; filling screen with blue color, second line &#8211; writing &#8222;Temperature:&#8221; starting from coordinate 0 and 0 (x and y), with preset font and yellow characters on blue background. Good idea &#8211; later we will talk about how to create your own fonts <img decoding=\"async\" draggable=\"false\" class=\"eedee-emoji\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/12.0.0-1\/svg\/1f643.svg\" alt=\"\ud83d\ude43\">. So now we have some of the static things, now we need to show temperature on display and it looks like this:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230322091732-scaled.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"459\" height=\"1024\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230322091732-459x1024.jpg\" alt=\"\" class=\"wp-image-5028\" style=\"width:286px;height:638px\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230322091732-459x1024.jpg 459w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230322091732-134x300.jpg 134w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230322091732-768x1715.jpg 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230322091732-688x1536.jpg 688w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230322091732-917x2048.jpg 917w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230322091732-scaled.jpg 1146w\" sizes=\"auto, (max-width: 459px) 100vw, 459px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">We will add some more static text later. Now lets try to make DS18B20 work. The datasheet says: <em>all communication with the DS18B20 begins with an initialization<\/em>, so lets do that. Datasheet explains, how to do that: <em>During the initialization sequence the bus master transmits (TX) the reset pulse by pulling the 1-Wire bus low for a minimum of 480\u03bcs. The bus master then releases the bus and goes into receive mode (RX). When the bus is released, the 5k\u03a9 pullup resistor pulls the 1-Wire bus high. When the DS18B20 detects this rising edge, it waits 15\u03bcs to 60\u03bcs and then transmits a presence pulse by pulling the 1-Wire bus low for 60\u03bcs to 240\u03bcs<\/em>. And here we have a slight problem &#8211; native STM32 HAL (Hardware Abstraction Layer) delay command provides delay function in milliseconds (ms), whilst DS18B20 should use timing in \u03bcs, thus 1000 times faster, or shorter periods (1 ms = 1000 \u03bcs). So we cant use HAL to wait 480 \u03bcs, because that&#8217;s 0,480 ms and HAL&#8217;s minimum is 1 ms. We have to make STM32 count microseconds&#8230; Lets look at the microprocessor diagram in the datasheet:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-18.png\"><img loading=\"lazy\" decoding=\"async\" width=\"799\" height=\"1024\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-18-799x1024.png\" alt=\"\" class=\"wp-image-5034\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-18-799x1024.png 799w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-18-234x300.png 234w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-18-768x985.png 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-18-1198x1536.png 1198w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-18.png 1343w\" sizes=\"auto, (max-width: 799px) 100vw, 799px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">We have bunch of timers, which can count time. Here we see, that timers are clocked by APB2 @ 90 MHz and APB1 @ 45 MHz. The timer clock is doubled, so 2\u00d745 MHz clock should be enough to count in \u03bcs, and 16 bits (65536) should be enough, so lets take TIMER6. The Clock Configuration window:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-20.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"893\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-20-1024x893.png\" alt=\"\" class=\"wp-image-5040\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-20-1024x893.png 1024w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-20-300x262.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-20-768x669.png 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-20-1536x1339.png 1536w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-20.png 1691w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">As TIMER6 is connected to APB1, and here we see APB1 timer clocks runs on 90 MHz because of x2 multiplier. Lets adjust the delay, so the minimal delay time would be 1 \u03bcs. Default configuration:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-21.png\"><img loading=\"lazy\" decoding=\"async\" width=\"914\" height=\"344\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-21.png\" alt=\"\" class=\"wp-image-5043\" style=\"width:566px;height:213px\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-21.png 914w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-21-300x113.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-21-768x289.png 768w\" sizes=\"auto, (max-width: 914px) 100vw, 914px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Now we need to configure prescaler &#8211; it divides the clock by the entered value. We have to have 1 \u03bcs delay steps, so the frequency should be:<\/p>\n\n\n\n<div class=\"wp-block-mathml-mathmlblock\">\\begin{equation}\nF = \\frac{1}{t} = \\frac{1}{0,000001s} = 1 000 000 Hz = 1 MHz\n\\end{equation}<script id=\"wp-hooks-js\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-includes\/js\/dist\/hooks.min.js?ver=f0f188028580e8dc1255\"><\/script>\n<script id=\"wp-i18n-js\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-includes\/js\/dist\/i18n.min.js?ver=1dfe7db3940c23ea9216\"><\/script>\n<script id=\"wp-i18n-js-after\">\nwp.i18n.setLocaleData( { 'text direction\\u0004ltr': [ 'ltr' ] } );\n\/\/# sourceURL=wp-i18n-js-after\n<\/script>\n<script  async id=\"mathjax-js\" src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/mathjax\/2.7.7\/MathJax.js?config=TeX-MML-AM_CHTML\"><\/script>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">So the timer should run at 1 MHz and out clock is 90 MHz, so prescaler should divide it by 90. The configuration:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-22.png\"><img loading=\"lazy\" decoding=\"async\" width=\"871\" height=\"342\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-22.png\" alt=\"\" class=\"wp-image-5046\" style=\"width:525px;height:205px\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-22.png 871w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-22-300x118.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-22-768x302.png 768w\" sizes=\"auto, (max-width: 871px) 100vw, 871px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Prescaler value 90-1, why ? Could write 89, would be the same, but easier to see that we are dividing by 90 and prescaler adds 1 to the digit, so we need to subtract 1. I think this is because first value is 0 and it also counts, maybe because you cant divide by zero. Counter period I left maximum, so we can count to 65534 \u03bcs if needed. Now we need to write a function, which will make the delay in \u03bcs work.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void Delay_in_us (uint16_t us){\t\t\t\t\t\/\/ delay function variable us, 16 bit length max\n\tHAL_TIM_SET_COUNTER(&amp;htim6,0);  \t\t\t\/\/ set the counter value a 0\n\twhile (HAL_TIM_GET_COUNTER(&amp;htim6) &lt; us);   \/\/ wait for the counter to count to us set in the variable\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Function Delay_in_us, with 16b parameter us, first line sets the counter to 0 and second counts till counter reaches the required \u03bcs value, so the loop will be processed required period of time, thus processor will not be doing anything, except counting, thus &#8211; delay for anything else <img decoding=\"async\" draggable=\"false\" class=\"eedee-emoji\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/12.0.0-1\/svg\/1f642.svg\" alt=\"\ud83d\ude42\">. Lets toggle the HEATBEAT pin with our new delay function:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>while (1) {\n\/* USER CODE END WHILE *\/\n\n    HAL_GPIO_WritePin(GPIOA, HEARTBEAT_Pin, pin_state);  \/\/ Yellow LED\n    pin_state = !pin_state;\n    Delay_in_us (1000);\n\n\/* USER CODE BEGIN 3 *\/\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Tested with 10 \u03bcs, 100 \u03bcs and 1000 \u03bcs, the oscilloscope shows:<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/10-us.png\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"480\" data-id=\"5053\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/10-us.png\" alt=\"\" class=\"wp-image-5053\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/10-us.png 800w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/10-us-300x180.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/10-us-768x461.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/100-us.png\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"480\" data-id=\"5054\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/100-us.png\" alt=\"\" class=\"wp-image-5054\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/100-us.png 800w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/100-us-300x180.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/100-us-768x461.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/1000-us.png\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"480\" data-id=\"5055\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/1000-us.png\" alt=\"\" class=\"wp-image-5055\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/1000-us.png 800w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/1000-us-300x180.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/1000-us-768x461.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><\/figure>\n<\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Seems correct, so the function and timer is working. With bigger values there is slight deviation, for example, instead of 1000 \u03bcs we get 990 \u03bcs, that&#8217;s, probably, because the switching of the pin takes some time, and counter counts 1000 whilst pin switches only 990 times. Not a big tragedy, can adjust that by letting the timer count till 1010 or something. We can troubleshoot that later, when will generate actual timings for the temp sensor. And now we can get back to the sensor initialization, when we need to send specific pulse and wait for sensor response. To do this lets write a simple function:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void DS18B20_init() {\n\tGPIO_InitTypeDef GPIO_InitStruct = { 0 }; \/\/ Setting the DS18B20_Data_Pin as output\n\tGPIO_InitStruct.Pin = DS18B20_Data_Pin;\t\/\/ This is already done by the configuration\n\tGPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;\t\/\/ in the IOC, but just to train how to do it\n\tGPIO_InitStruct.Pull = GPIO_NOPULL;\t\t\t\/\/ separately repeating here.\n\tGPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;\n\tHAL_GPIO_Init(GPIOA, &amp;GPIO_InitStruct);\n\n\tHAL_GPIO_WritePin(GPIOA, DS18B20_Data_Pin, 0);\/\/ And as specified in the sensor datasheet pulling the line low for\n\tDelay_in_us(480);\t\t\t\t\t\t\t\t\t\t\/\/ 480 us and then\n\n\tGPIO_InitStruct.Pin = DS18B20_Data_Pin;\t\/\/ This time setting the pin as input, to see if\n\tGPIO_InitStruct.Mode = GPIO_MODE_INPUT;\t\/\/ sensor responds in timely manner.\n\tGPIO_InitStruct.Pull = GPIO_PULLUP;\t\/\/ Enabled the internal pullup, to filter out noise if nothing connected to the pin\n\tGPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;\n\tHAL_GPIO_Init(GPIOA, &amp;GPIO_InitStruct);\n\n\tDelay_in_us(70);\/\/ Datasheet says sensor will respond after 15-60 us, so 70 is a reasonable value\n\n\tif (HAL_GPIO_ReadPin(GPIOA, DS18B20_Data_Pin) == 0) {\t\/\/ After waiting the 70 us checking if we see the low level on the line.\n\n\t\tDelay_in_us(410);\/\/ From datasheet, Master RX = 480 us, counting since pulling the pin high, so delay 70us+410us = 480us\n\t\tDS18B20_Sensor_present = 1;\t\t\t\t\t\/\/ Light up the LED if sensor detected\n\t}\n\n\telse {\n\n\t\tDelay_in_us(410);\/\/ From datasheet, Master RX = 480 us, counting since pulling the pin high, so delay 70us+410us = 480us\n\t\tDS18B20_Sensor_present = 0;\t\t\t\t\/\/ Nothing on the LED if sensor not detected\n\t}\n\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">I put comments on each line, so only short explanation &#8211; first, we set the pin as output, then set it to low level, logical 0 and wait for specified time. Then we set the pin as input and after some specified time check if we see response from senor. Timing is taken from datasheet:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-23.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"414\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-23-1024x414.png\" alt=\"\" class=\"wp-image-5059\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-23-1024x414.png 1024w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-23-300x121.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-23-768x310.png 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-23.png 1237w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">The only missing time in this graph is the time after which the sensor responds, but its in the text &#8211; <em>When the DS18B20 detects this rising edge, it waits 15 \u03bcs to 60 \u03bcs and then transmits a presence pulse by pulling<br>the 1-Wire bus low for 60 \u03bcs to 240 \u03bcs<\/em>. Out development board lights a LED if sensor is detected, but to get even deeper, we want to look what can be seen on the oscilloscope:<\/p>\n\n\n\n<figure class=\"wp-block-gallery aligncenter has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323101953.png\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"480\" data-id=\"5061\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323101953.png\" alt=\"\" class=\"wp-image-5061\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323101953.png 800w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323101953-300x180.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323101953-768x461.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323102050.png\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"480\" data-id=\"5063\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323102050.png\" alt=\"\" class=\"wp-image-5063\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323102050.png 800w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323102050-300x180.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323102050-768x461.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323102123.png\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"480\" data-id=\"5062\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323102123.png\" alt=\"\" class=\"wp-image-5062\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323102123.png 800w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323102123-300x180.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_2023323102123-768x461.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><\/figure>\n<\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Here we can see, that our microprocessor sets the signal low for exactly 480 \u03bcs, then it releases the line and pullup resistor brings it back to 3,3 V, then, after 28 \u03bcs, the sensor responds by holding line low for 116 \u03bcs. So far so good <img decoding=\"async\" draggable=\"false\" class=\"eedee-emoji\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/12.0.0-1\/svg\/1f601.svg\" alt=\"\ud83d\ude01\">. At this point also renamed the pin_state variable to DS18B20_Sensor_present and a short code for HEARTBEAT, to see if the sensor responds with LED:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\twhile (1) {\n\t\t\/* USER CODE END WHILE *\/\n\t\tDS18B20_init();\n\t\tHAL_GPIO_WritePin(GPIOA, HEARTBEAT_Pin, DS18B20_Sensor_present);  \/\/ Yellow LED\n\t\tHAL_Delay(500);\n\t\tHAL_GPIO_WritePin(GPIOA, HEARTBEAT_Pin, 0);  \/\/ Yellow LED\n\t\tHAL_Delay(500);\n\t\t\/* USER CODE BEGIN 3 *\/\n\t}\n\t\/* USER CODE END 3 *\/\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Not much here &#8211; just run the DS18B20_init() function, it responds with 0 or 1, depending if the sensor is found, and HAL_GPIO_WritePin writes received 0 ir 1 to HEARTBEAT LED, then waits 0,5 s, turns off the LED, waits another 0,5 s and it all starts again, so when sensor connected the LED is blinking, and when sensor disconnected LED is off. This part of code is just to make sure we are on the right path, so it will be removed at the final stage of coding. By the way &#8211; if there are multiple DS18B20 sensors on the same bus &#8211; they all will respond simultaneously. So response does not mean we have only one sensor, it just means, that we have at least one sensor. Each device on the bus should have some identifier, this applies to DS18B20 too, it has a special 64 bit code, different for all the DS18B20 in the world. For now we will always have only one sensor, so lets just ask it to show the code.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em><strong>Read Rom [33h]<\/strong><br><\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>This command can only be used when there is one slave on the bus. It allows the bus master to read the slave\u2019s 64-bit ROM code without using the Search ROM procedure. If this command is used when there is more than one slave present on the bus, a data collision will occur when all the slaves attempt to respond at the same time.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And that means, if we will detect a presence pulse, we will have to ask for ROM code. Naturally, in our test device, we will always have only one device, but later, we might try to make the program universal, so it would search for ROM codes on the bus. The process is in the datasheet, so no need to worry about how to do it:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-24.png\"><img loading=\"lazy\" decoding=\"async\" width=\"882\" height=\"1024\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-24-882x1024.png\" alt=\"\" class=\"wp-image-5074\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-24-882x1024.png 882w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-24-258x300.png 258w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-24-768x892.png 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-24.png 1234w\" sizes=\"auto, (max-width: 882px) 100vw, 882px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">I will try to make a list of procedures that must be performed in the DS18B20_Read_ROM procedure:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Microprocessor sends initialization sequence (low pulse on bus);<\/li>\n\n\n\n<li>Sensor\/-s respond with low pulse;<\/li>\n\n\n\n<li>If the low pulse is detected by microprocessor, it sends READ ROM command, to which the sensor will respond accordingly. The command F33, it must be sent as a bit sequence to the sensors, so it would understand it. Hexadecimal digit F33 in binary is 0011 0011, this is a sequence that needs to be sent to sensors. To write 1 and 0 there is specific diagram:<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-25.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"350\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-25-1024x350.png\" alt=\"\" class=\"wp-image-5085\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-25-1024x350.png 1024w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-25-300x102.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-25-768x262.png 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-25.png 1142w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Means, if microprocessor (MASTER), want to write &#8222;0&#8221;, it must hold the line low for 15+15+30 \u03bcs = 60 \u03bcs. The transmitting of &#8222;0&#8221; must be between 60 \u03bcs and 120 \u03bcs, lets do 60 \u03bcs for start. To write &#8222;1&#8221; Master must pull the line low for less than 15 \u03bcs, let&#8217;s say 5 \u03bcs and then do nothing for about 60 \u03bcs. The datasheet refers to writing &#8222;1&#8221; and &#8222;0&#8221; as &#8222;Write 1 time slot&#8221; and &#8222;Write 0 time slot&#8221;. And basically explains how to write: <em>To generate a Write 1 time slot, after pulling the 1-Wire bus low, the bus master must release the 1-Wire bus within 15\u03bcs. When the bus is released, the 5k\u03a9 pullup resistor will pull the bus high. To generate a Write 0 time slot, after pulling the 1-Wire bus low, the bus master must continue to hold the bus low for the duration of the time  slot (at least 60\u03bcs and 1\u03bcs recovery time between individual write slots)<\/em>. We will have to write another procedure, which will do just that. And writing should be done bit by bit, generating the correct bits and timings for complete byte.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">At this point we need to write procedures to write and read information.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void Write_Byte(uint8_t bit_to_send_to_DS18B20) {\n\tSet_DS18B20_Pin_as_Output();\n\n\tfor (int i = 0; i &lt; 8; i++) {\n\n\t\tif ((bit_to_send_to_DS18B20 &amp; (1 &lt;&lt; i)) != 0) \/\/ writing 1 if the bit is high\n\t\t\t\t{\n\n\t\t\tSet_DS18B20_Pin_as_Output();\n\t\t\tHAL_GPIO_WritePin(GPIOA, DS18B20_Data_Pin, 0); \/\/ writing 0 to the bus\n\t\t\tDelay_in_us(1);  \/\/ wait for 1 us\n\t\t\tSet_DS18B20_Pin_as_Input();  \/\/ set as input\n\t\t\tDelay_in_us(60);  \/\/ wait for 60 us\n\t\t}\n\n\t\telse  \/\/ writing 0 if the bit is low:\n\t\t{\n\n\t\t\tSet_DS18B20_Pin_as_Output();\n\t\t\tHAL_GPIO_WritePin(GPIOA, DS18B20_Data_Pin, 0); \/\/ writing 0 to the bus\n\t\t\tDelay_in_us(60);\n\t\t\tSet_DS18B20_Pin_as_Input();\n\t\t}\n\t}\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Basically what it does is makes the pin as output, takes our &#8222;bit_to_send_to_DS18B20&#8221;, which is 0x33 or 0011 0011 and bit by bit, till reaches all 8 bits toggles the output pin accordingly to logical 0 and logical 1. To write 1 we just put pin to 0 for 1 \u03bcs and then release it back to pullup, to write 0 we keep pin low for 60 \u03bcs and then release it. On the oscilloscope it looks like this:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_202332914622.png\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"480\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_202332914622.png\" alt=\"\" class=\"wp-image-5102\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_202332914622.png 800w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_202332914622-300x180.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/DS2_202332914622-768x461.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">The DS18B20 responds to this with bunch of data, 64 bits, to be exact. Now we need to read that information.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>uint8_t Read_Byte(void) {\n\tuint8_t byte = 0;\n\n\tSet_DS18B20_Pin_as_Input();\n\n\tfor (int i = 0; i &lt; 8; i++) {\n\t\tSet_DS18B20_Pin_as_Output();   \/\/ set as output\n\n\t\tHAL_GPIO_WritePin(GPIOA, DS18B20_Data_Pin, 0);  \/\/ pull the data pin LOW\n\t\tDelay_in_us(1);  \/\/ wait for &gt; 1us\n\n\t\tSet_DS18B20_Pin_as_Input();  \/\/ set as input\n\t\tif (HAL_GPIO_ReadPin(GPIOA, DS18B20_Data_Pin))  \/\/ if the pin is HIGH\n\t\t\t\t{\n\t\t\tbyte |= 1 &lt;&lt; i;  \/\/ read = 1\n\t\t}\n\t\tDelay_in_us(50);  \/\/ wait for 60 us\n\t}\n\treturn byte;\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Again, forming the read time slot as described in the datasheet, reading 8 bytes, which is 64 bits and assigning 1 or 0, reacting to the signal length in sensor response. Now we can send commands and read response, so we can try to ask the sensor to tell us its ROM code:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void DS18B20_Read_ROM() {\n\n\tif (DS18B20_Sensor_present == 1) {\n\n\t\tWrite_Byte(0x33);\t\t\t\/\/ 0x33 = 0b 0011 0011 ; 0xF0 = 0b 1111 0000\n\n\t\tfor (int i = 0; i &lt; 8; i++) {\n\t\t\tROM_address&#91;i] = Read_Byte();\n\t\t}\n\t}\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">First we check if there is a sensor connected, if yes, then ask him 0x33 (to tell the ROM code) and read the answer to ROM_adress. Having ROM address we can quickly check which temperature sensor of the family is connected: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t\tif (DS18B20_Sensor_present == 1) {\n\t\t\tST7735_WriteString(35, 0, \"PONG\", Font_7x10, ST7735_YELLOW,\n\t\t\tST7735_BLUE);\n\t\t\tDS18B20_Read_ROM();\n\n\t\t\tif (ROM_address&#91;0] == 0x10) {\n\t\t\t\tST7735_WriteString(0, 12, \"DS18S20 found\", Font_7x10,\n\t\t\t\tST7735_YELLOW,\n\t\t\t\tST7735_BLUE);\n\t\t\t} else {\n\n\t\t\t\tif (ROM_address&#91;0] == 0x22) {\n\t\t\t\t\tST7735_WriteString(0, 12, \"DS1822 found\", Font_7x10,\n\t\t\t\t\tST7735_YELLOW,\n\t\t\t\t\tST7735_BLUE);\n\t\t\t\t} else {\n\t\t\t\t\tif (ROM_address&#91;0] == 0x28) {\n\t\t\t\t\t\tST7735_WriteString(0, 12, \"DS18B20 found\", Font_7x10,\n\t\t\t\t\t\tST7735_YELLOW,\n\t\t\t\t\t\tST7735_BLUE);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The datasheet says, that first byte will be 0x10 for DS18S20, 0x22 for DS1822 and 0x28 for DS18B20, so we check and write on the LCD what we found.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230329143259-scaled.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"459\" height=\"1024\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230329143259-459x1024.jpg\" alt=\"\" class=\"wp-image-5107\" style=\"width:268px;height:598px\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230329143259-459x1024.jpg 459w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230329143259-134x300.jpg 134w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230329143259-768x1715.jpg 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230329143259-688x1536.jpg 688w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230329143259-917x2048.jpg 917w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230329143259-scaled.jpg 1146w\" sizes=\"auto, (max-width: 459px) 100vw, 459px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">The PING : PONG on the top comes from TCP\/IP protocol, if simple, there if one PC want to check if another PC is connected it asks &#8211; PING, and the second PC must reply PONG, so in this case I am writing PING on the LCD when asking for presence pulse from sensor and PONG if the pulse is received. But the sensor is detected, thus LCD indicates what sensor it is. Now I would like to write the ROM address on the LCD, because we already have it. And we have to learn about thing called CASTING, because we need to cast the variable. In our case it is done like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const char *ROM_Address = (char*) ROM_address;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">What we do is changing the variable type from uint8_t to const char. Why ? Because that damn ST7735 LCD library accepts only const char* pointer (the asterisk * thing). Now if we would write something like that:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ST7735_WriteString(0, 36, ROM_Address, Font_7x10, ST7735_YELLOW, ST7735_BLUE);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The display should indicate ROM address. It should, but it does not &#8211; shows only nonsense characters, the first one is &#8222;(&#8222;. And this leads to the thought, that instead of showing 0x28, hexadecimal digit, LCD shows its ASCII meaning, the &#8222;(&#8222;. And we are sure the first byte is 0x28, because we already checked it when looked for DS18B20 first byte signature. So before printing we have to set the format of the data. It seems, that display controller takes the 0x28 HEX digit, and, instead of showing it, controller shows the ASCII character with 0x28 code and that is repeated with all bytes in the line, so we get nonsense on display. We need to send formatted data to the LCD&#8230; And this can be done using printf family functions, in this case used snprintf().<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t\t\tchar ROM_AD&#91;sizeof(ROM_address) * 2 + 1];\n\n\t\t\tsnprintf(ROM_AD, sizeof(ROM_AD), \"%02X %02X %02X %02X\", ROM_Address&#91;0], ROM_Address&#91;1], ROM_Address&#91;2], ROM_Address&#91;3]);\n\t\t\tST7735_WriteString(0, 36, ROM_AD, Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t\t\tsnprintf(ROM_AD, sizeof(ROM_AD), \"%02X %02X %02X %02X\", ROM_Address&#91;4], ROM_Address&#91;5], ROM_Address&#91;6], ROM_Address&#91;7]);\n\t\t\tST7735_WriteString(0, 48, ROM_AD, Font_7x10, ST7735_YELLOW, ST7735_BLUE);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">First made a new variable ROM_AD, to contain the formatted data, which has double the size, because byte 28 in hexadecimal will become two separate bytes, 2 and 8, plus C string must end with &#8222;\\0&#8221;. Strings are actually arrays of characters terminated by a&nbsp;null&nbsp;character &#8222;\\0&#8221;. Actually, there is no &#8222;\\0&#8221;&nbsp;character at the end of a string constant, but he C compiler automatically places the &#8222;&#8216;\\0&#8221; at the end of the string when it initializes the array, so, probably, it would be OK without the &#8222;+ 1&#8221;, but might cause some warnings during the compilation. So we call the snprintf, tell ir that new data should go to ROM_AD, which will have sizeof(ROM_AD), and next is the formatting &#8211; %02X means headecimal digit, with capital letters (x would be non capital letters) and two places, meaning it will write 08 instead of just 8. Repeat it 4 times and then telling the sprintf what data to take, so data from ROM_Address[at location X]. Why only four, instead of 8 ? Because 8 bytes are not fitting into the display, so first I write first 4 bytes, then next 4 bytes in the lower line. And now it looks like this:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230330094603-scaled.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"576\" height=\"1024\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230330094603-576x1024.jpg\" alt=\"\" class=\"wp-image-5111\" style=\"width:281px;height:499px\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230330094603-576x1024.jpg 576w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230330094603-169x300.jpg 169w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230330094603-768x1365.jpg 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230330094603-864x1536.jpg 864w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230330094603-1152x2048.jpg 1152w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/IMG20230330094603-scaled.jpg 1440w\" sizes=\"auto, (max-width: 576px) 100vw, 576px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">And now we have the address of the sensor &#8211; 28 3B 1B 1E 0D 00 00 3A. But is this code correct ? We need to check that. Datasheet says, the code consists of:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-26.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"153\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-26-1024x153.png\" alt=\"\" class=\"wp-image-5130\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-26-1024x153.png 1024w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-26-300x45.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-26-768x115.png 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/03\/image-26.png 1233w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">So the first byte is family code, that we already know, then 6 bytes serial number, then last byte is CRC! And the same datasheet says:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>CRC bytes are provided as part of the DS18B20\u2019s 64-bit ROM code and in the 9th byte of the scratchpad memory. The ROM code CRC is calculated from the first 56 bits of the ROM code and is contained in the most significant byte of the ROM.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So actually we can check if the ROM code is correctly received.<\/p>\n\n\n\n<p class=\"has-text-align-left wp-block-paragraph\"><em>The equivalent polynomial function of the CRC (ROM or scratchpad) is:<\/em><br><\/p>\n\n\n\n<div class=\"wp-block-mathml-mathmlblock\">\\[ CRC =  {X^8}+{X^5}+{X^4}+1\\]<\/div>\n\n\n\n<p class=\"has-text-align-left wp-block-paragraph\"><br><em>The bus master can re-calculate the CRC and compare it to the CRC values from the DS18B20 using the polynomial generator shown in Figure 11. This circuit consists of a shift register and XOR gates, and the shift register bits are initialized to 0. Starting with the least significant bit of the ROM code or the least significant bit of byte 0 in the scratchpad, one bit at a time should shifted into the shift register. After shifting in the 56th bit from the ROM or the most significant bit of byte 7 from the scratchpad, the polynomial generator will contain the recalculated CRC.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It seems smart and hard, but the function doing the CRC calculation is not that hard:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>uint8_t CRC_Calculator(uint8_t *String_to_be_CRCed, uint8_t Len) {\n\tuint8_t i, dat, fb, rom_bit;\n\trom_bit = 0;\n\tcrc = 0;\n\tdo {\n\t\tdat = String_to_be_CRCed&#91;rom_bit];\n\t\tfor (i = 0; i &lt; 8; i++) {\n\t\t\tfb = crc ^ dat;\n\t\t\tfb &amp;= 1;\n\t\t\tcrc &gt;&gt;= 1;\n\t\t\tdat &gt;&gt;= 1;\n\t\t\tif (fb == 1)\n\t\t\t\tcrc ^= 0x8c;\n\t\t}\n\t\trom_bit++;\n\t} while (rom_bit &lt; Len);\n\treturn crc;\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It is described in One Wire protocol and millions of websites, explaining, how to calculate OneWire data CRC. Now we can write some code for DS18B20_Read_ROM() function:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t\t\/\/ CRC check of ROM:\n\t\tCRC_Calculator(ROM_address, 7);\n\n\t\tif (crc == ROM_address&#91;7]) {\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ If calculated and received CRC are equal\n\n\t\t\tsnprintf(ROM_Address_to_print, sizeof(ROM_Address_to_print), \"%02X\", ROM_Address&#91;7]);\t\t\/\/ Convert data to printable\n\t\t\tST7735_WriteString(63, 48, ROM_Address_to_print, Font_7x10, ST7735_GREEN, ST7735_BLUE);\t\t\/\/ and print CRC byte in green\n\t\t\tST7735_WriteString(92, 37, \"OK\", Font_11x18, ST7735_WHITE, ST7735_BLACK);\t\t\t\t\t\/\/ and write \"OK\"\n\n\t\t}\n\n\t\telse {\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ If calculated and received CRC are not equal\n\n\t\t\tsnprintf(ROM_Address_to_print, sizeof(ROM_Address_to_print), \"%02X\", ROM_Address&#91;7]);\t\t\/\/ convert data to printable\n\t\t\tST7735_WriteString(63, 48, ROM_Address_to_print, Font_7x10, ST7735_RED, ST7735_BLUE);\t\t\/\/ and print CRC byte in red\n\n\t\t\tchar CRC_to_print&#91;sizeof(crc) * 2 + 1];\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ Convert calculated\n\t\t\tsnprintf(CRC_to_print, sizeof(CRC_to_print), \"%02X\", crc);\t\t\t\t\t\t\t\t\t\/\/ CRC byte to printable\n\t\t\tST7735_WriteString(92, 37, CRC_to_print, Font_11x18, ST7735_RED, ST7735_BLACK);\t\t\t\t\/\/ and write it in red\n\n\t\t}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This part of code will compare received CRC byte with calculated CRC and adjust the information on LCD if CRC matches or not. Next &#8211; lets get the sensor scratch pad. From datasheet:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>The scratchpad memory contains the 2-byte temperature register that stores the digital output from the temperature sensor. In addition, the scratchpad provides access to the 1-byte upper and lower alarm trigger registers (TH and TL) and the 1-byte configuration register. The configuration register allows the user to set the resolution of the temperature-to-digital conversion to 9, 10, 11, or 12 bits. The TH, TL, and configuration registers are nonvolatile (EEPROM), so they will retain data when the device is powered down.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So this scratchpad thing is the memory where all the information, data and settings are stored in the sensor. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"376\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-1024x376.png\" alt=\"\" class=\"wp-image-5136\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-1024x376.png 1024w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-300x110.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-768x282.png 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image.png 1234w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Scratchpad has 9 bytes, at each byte some useful information, except bytes 5, 6 and 7 &#8211; those are reserved for some DS18B20 reasons. Last byte is CRC, as if was in ROM data. Lets implement CRC checking for ROM, then read scratchpad, check its CRC and put it all on display.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void DS18B20_Read_ROM() {\n\n\tif (DS18B20_Sensor_present == 1) {\n\n\t\tWrite_Byte(0x33);\t\t\t\t\t\t\t\t\t\t\t\t\/\/ 0x33 = 0b 0011 0011 ; 0xF0 = 0b 1111 0000\n\n\t\tfor (int i = 0; i &lt; 8; i++) {\n\t\t\tROM_address&#91;i] = Read_Byte();\n\t\t}\n\n\t\tST7735_WriteString(0, 24, \"ROM Address\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\n\t\tconst char *ROM_Address = (char*) ROM_address;\n\n\t\tchar ROM_Address_to_print&#91;sizeof(ROM_address) * 2 + 1];\n\n\t\tsnprintf(ROM_Address_to_print, sizeof(ROM_Address_to_print), \"%02X %02X %02X %02X\", ROM_Address&#91;0], ROM_Address&#91;1], ROM_Address&#91;2], ROM_Address&#91;3]);\n\t\tST7735_WriteString(0, 36, ROM_Address_to_print, Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t\tsnprintf(ROM_Address_to_print, sizeof(ROM_Address_to_print), \"%02X %02X %02X\", ROM_Address&#91;4], ROM_Address&#91;5], ROM_Address&#91;6]);\n\t\tST7735_WriteString(0, 48, ROM_Address_to_print, Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\n\t\tST7735_FillRectangle(81, 24, 45, 32, ST7735_BLACK); \t\t\t\/\/ X, Y, Width, Height\n\t\tST7735_WriteString(82, 25, \"ROMCRC\", Font_7x10, ST7735_WHITE, ST7735_BLACK);\n\n\t\t\/\/ CRC check of ROM:\n\t\tCRC_Calculator(ROM_address, 7);\n\n\t\tif (crc == ROM_address&#91;7]) {\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ If calculated and received CRC are equal\n\n\t\t\tsnprintf(ROM_Address_to_print, sizeof(ROM_Address_to_print), \"%02X\", ROM_Address&#91;7]);\t\t\/\/ Convert data to printable\n\t\t\tST7735_WriteString(63, 48, ROM_Address_to_print, Font_7x10, ST7735_GREEN, ST7735_BLUE);\t\t\/\/ and print CRC byte in green\n\t\t\tST7735_WriteString(92, 37, \"OK\", Font_11x18, ST7735_WHITE, ST7735_BLACK);\t\t\t\t\t\/\/ and write \"OK\"\n\t\t\tROM_OK_Flag = 1;\n\t\t}\n\n\t\telse {\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ If calculated and received CRC are not equal\n\n\t\t\tsnprintf(ROM_Address_to_print, sizeof(ROM_Address_to_print), \"%02X\", ROM_Address&#91;7]);\t\t\/\/ convert data to printable\n\t\t\tST7735_WriteString(63, 48, ROM_Address_to_print, Font_7x10, ST7735_RED, ST7735_BLUE);\t\t\/\/ and print CRC byte in red\n\n\t\t\tchar CRC_to_print&#91;sizeof(crc) * 2 + 1];\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ Convert calculated\n\t\t\tsnprintf(CRC_to_print, sizeof(CRC_to_print), \"%02X\", crc);\t\t\t\t\t\t\t\t\t\/\/ CRC byte to printable\n\t\t\tST7735_WriteString(92, 37, CRC_to_print, Font_11x18, ST7735_RED, ST7735_BLACK);\t\t\t\t\/\/ and write it in red\n\t\t\tROM_OK_Flag = 0;\n\t\t}\n\n\t}\n\n\telse {\n\t\tST7735_WriteString(35, 0, \"ERROR1\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t}\n\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And for the scratchpad:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void DS18B20_Read_Scratchpad() {\n\n\tDS18B20_init();\n\n\tif (DS18B20_Sensor_present == 1) {\n\t\tif (ROM_OK_Flag == 1) {\n\t\t\tST7735_WriteString(35, 0, \"PONG\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\n\t\t\tWrite_Byte(0x55);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ Match ROM command &#91;0x55]\n\t\t\tfor (int i = 0; i &lt; 8; i++) {\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ Send previously detected\n\t\t\t\tWrite_Byte(ROM_address&#91;i]);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ ROM, all 8 bytes\n\t\t\t}\n\t\t\tWrite_Byte(0x44);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/Convert Temperature &#91;44h] to update the scratchpad\n\n\t\t\tDS18B20_init();\n\n\t\t\tif (DS18B20_Sensor_present == 1) {\n\t\t\t\tST7735_WriteString(35, 0, \"PONG\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\n\t\t\t\tWrite_Byte(0x55);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ Match ROM command &#91;0x55]\n\t\t\t\tfor (int i = 0; i &lt; 8; i++) {\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ Send previously detected\n\t\t\t\t\tWrite_Byte(ROM_address&#91;i]);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ ROM, all 8 bytes\n\t\t\t\t}\n\t\t\t\tWrite_Byte(0xBE);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ Read scratchpad command\n\n\t\t\t\tfor (uint8_t i = 0; i &lt; 9; i++) {\n\t\t\t\t\tScratchpad&#91;i] = Read_Byte();\n\t\t\t\t}\n\n\t\t\t\tST7735_WriteString(0, 60, \"Scratchpad:\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\n\t\t\t\tCfg_Reg = Scratchpad&#91;3];\n\n\t\t\t\tconst char *ScratchPad = (char*) Scratchpad;\n\n\t\t\t\tchar ScratchPad_to_print&#91;sizeof(Scratchpad) * 2 + 1];\n\n\t\t\t\tsnprintf(ScratchPad_to_print, sizeof(ScratchPad_to_print), \"%02X %02X\", ScratchPad&#91;0], ScratchPad&#91;1]);\n\t\t\t\tST7735_WriteString(0, 72, ScratchPad_to_print, Font_7x10, ST7735_RED, ST7735_BLUE);\n\n\t\t\t\tsnprintf(ScratchPad_to_print, sizeof(ScratchPad_to_print), \"%02X %02X\", ScratchPad&#91;2], ScratchPad&#91;3]);\n\t\t\t\tST7735_WriteString(41, 72, ScratchPad_to_print, Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\n\t\t\t\tsnprintf(ScratchPad_to_print, sizeof(ScratchPad_to_print), \"%02X\", ScratchPad&#91;4]);\n\t\t\t\tST7735_WriteString(0, 84, ScratchPad_to_print, Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\n\t\t\t\tsnprintf(ScratchPad_to_print, sizeof(ScratchPad_to_print), \"%02X %02X %02X\", ScratchPad&#91;5], ScratchPad&#91;6], ScratchPad&#91;7]);\n\t\t\t\tST7735_WriteString(21, 84, ScratchPad_to_print, Font_7x10, ST7735_BLACK, ST7735_BLUE);\n\n\t\t\t\tST7735_FillRectangle(81, 61, 45, 42, ST7735_BLACK); \t\t\t\t\t\t\t\t\t\t\t\t\/\/ X, Y, Width, Height\n\t\t\t\tST7735_WriteString(82, 62, \"SCRPAD\", Font_7x10, ST7735_WHITE, ST7735_BLACK);\n\t\t\t\tST7735_WriteString(92, 74, \"CRC\", Font_7x10, ST7735_WHITE, ST7735_BLACK);\n\n\t\t\t\tCRC_Calculator(Scratchpad, 8);\n\n\t\t\t\tif (crc == Scratchpad&#91;8]) {\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ If calculated and received CRC are equal\n\n\t\t\t\t\tsnprintf(ScratchPad_to_print, sizeof(ScratchPad_to_print), \"%02X\", Scratchpad&#91;8]);\t\t\t\/\/ Convert data to printable\n\t\t\t\t\tST7735_WriteString(0, 96, ScratchPad_to_print, Font_7x10, ST7735_GREEN, ST7735_BLUE);\t\t\/\/ and print CRC byte in green\n\t\t\t\t\tST7735_WriteString(92, 84, \"OK\", Font_11x18, ST7735_WHITE, ST7735_BLACK);\t\t\t\t\t\/\/ and write \"OK\"\n\n\t\t\t\t} else {\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ If calculated and received CRC are not equal\n\n\t\t\t\t\tsnprintf(ScratchPad_to_print, sizeof(ScratchPad_to_print), \"%02X\", Scratchpad&#91;8]);\t\t\t\/\/ convert data to printable\n\t\t\t\t\tST7735_WriteString(0, 96, ScratchPad_to_print, Font_7x10, ST7735_RED, ST7735_BLUE);\t\t\t\/\/ and print CRC byte in red\n\n\t\t\t\t\tchar CRC_to_print&#91;sizeof(crc) * 2 + 1];\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ Convert calculated\n\t\t\t\t\tsnprintf(CRC_to_print, sizeof(CRC_to_print), \"%02X\", crc);\t\t\t\t\t\t\t\t\t\/\/ CRC byte to printable\n\t\t\t\t\tST7735_WriteString(92, 84, CRC_to_print, Font_11x18, ST7735_RED, ST7735_BLACK);\t\t\t\t\/\/ and write it in red\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tST7735_WriteString(35, 0, \"ERROR4\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t\t\t}\n\n\t\t} else {\n\t\t\tST7735_WriteString(35, 0, \"ERROR3\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t\t}\n\n\t} else {\n\t\tST7735_WriteString(35, 0, \"ERROR2\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t}\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Notice, that I also made a small upgrade &#8211; writing byte 0x55, which asks the DS18B20 to respond only if its ROM address is a match. Its not required for one sensor on line, but we are learning to manage the sensors, right, so maybe in the future we will need to add more sensors and here were are &#8211; snippet already prepared <img decoding=\"async\" draggable=\"false\" class=\"eedee-emoji\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/12.0.0-1\/svg\/1f601.svg\" alt=\"\ud83d\ude01\">. Ok, now we have both ROM and scratchpad. ROM we already analyzed, but what can we get from the scratchpad ? <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Byte 0 and byte 1 of the scratchpad contain the LSB and the MSB of the temperature register, respectively. These bytes are read-only. Bytes 2 and 3 provide access to TH and TL registers. Byte 4 contains the configuration register data, which is explained in detail in the Configuration Register section. Bytes 5, 6, and 7 are reserved for internal use by the device and cannot be overwritten. Byte 8 of the scratchpad is read-only and contains the CRC code for bytes 0 through 7 of the scratchpad. The DS18B20 generates this CRC using the method described in the CRC Generation section.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So, byte 0 and byte 1 are clear &#8211; stored temperature, bytes 2 and 3 &#8211; register controls, not sure if I will do anything with them. Byte 4 &#8211; configuration register, this might be interesting. We already have it in the scratchpad reading function, lets just write it in binary form, to have all the bits and easy understanding of the settings there.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void DS18B20_Decode_Config_Register() {\n\n\tif (DS18B20_Sensor_present == 1) {\n\t\tif (ROM_OK_Flag == 1) {\n\n\t\t\tchar Config_Register_to_print&#91;sizeof(Cfg_Reg) * 2 + 1];\n\n\t\t\tsnprintf(Config_Register_to_print, sizeof(Config_Register_to_print), \"%02X\", Cfg_Reg);\n\n\t\t\tchar hex2bin&#91;8] = \"\";\n\n\t\t\tfor (int i = 0; i &lt; 2; i++) {\n\n\t\t\t\tswitch (Config_Register_to_print&#91;i]) {\n\t\t\t\tcase '0':\n\t\t\t\t\tstrcat(hex2bin, \"0000\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase '1':\n\t\t\t\t\tstrcat(hex2bin, \"0001\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase '2':\n\t\t\t\t\tstrcat(hex2bin, \"0010\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase '3':\n\t\t\t\t\tstrcat(hex2bin, \"0011\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase '4':\n\t\t\t\t\tstrcat(hex2bin, \"0100\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase '5':\n\t\t\t\t\tstrcat(hex2bin, \"0101\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase '6':\n\t\t\t\t\tstrcat(hex2bin, \"0110\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase '7':\n\t\t\t\t\tstrcat(hex2bin, \"0111\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase '8':\n\t\t\t\t\tstrcat(hex2bin, \"1000\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase '9':\n\t\t\t\t\tstrcat(hex2bin, \"1001\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'a':\n\t\t\t\tcase 'A':\n\t\t\t\t\tstrcat(hex2bin, \"1010\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'b':\n\t\t\t\tcase 'B':\n\t\t\t\t\tstrcat(hex2bin, \"1011\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'c':\n\t\t\t\tcase 'C':\n\t\t\t\t\tstrcat(hex2bin, \"1100\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'd':\n\t\t\t\tcase 'D':\n\t\t\t\t\tstrcat(hex2bin, \"1101\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'e':\n\t\t\t\tcase 'E':\n\t\t\t\t\tstrcat(hex2bin, \"1110\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'f':\n\t\t\t\tcase 'F':\n\t\t\t\t\tstrcat(hex2bin, \"1111\");\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tprintf(\"Invalid hexadecimal input.\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tST7735_WriteString(0, 108, \"CFG REG: \", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t\t\tST7735_WriteString(56, 108, hex2bin, Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t\t}\n\t}\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here we take the register byte, condition it with snprintf() and two times run the cycle to process both digits to binary form, strcat() function joins them together, so we get a row of bits and print them on LCD in hex2bin variable. At this point the LCD is almost full of information <img decoding=\"async\" draggable=\"false\" class=\"eedee-emoji\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/12.0.0-1\/svg\/1f974.svg\" alt=\"\ud83e\udd74\">.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230403110804.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"869\" height=\"1024\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230403110804-869x1024.jpg\" alt=\"\" class=\"wp-image-5140\" style=\"width:383px;height:450px\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230403110804-869x1024.jpg 869w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230403110804-254x300.jpg 254w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230403110804-768x905.jpg 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230403110804.jpg 905w\" sizes=\"auto, (max-width: 869px) 100vw, 869px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">All the lines explained:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The PING : PONG presence check<\/li>\n\n\n\n<li>Temperature sensor detection from ROM (can be DS18S20, DS1822 or DS18B20)<\/li>\n\n\n\n<li>On the left side ROM address in HEX (28 3B 1B 1E 0D 00 00 3A), on the right side ROM CRC check result. If CRC (3A) is OK, then last read byte is green, if not the same the read last byte (3A) will be marked red, and in the black CRC ROM area calculated CRC will be displayed, also in red, so we can visibly compare them.<\/li>\n\n\n\n<li>On the left scratchpad data in HEX (7D 01 4B 46 7F FF 03 10 24). Similarly, on the right side in black area scratchpad CRC check result. All the checking is the same as ROM, so read CRC byte is green if OK, and red if not OK and calculated CRC will be written instead of OK. <\/li>\n\n\n\n<li>Configuration register in binary form, 0x46 = 0100 0110.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Adjusted the code a bit, so it would indicate the fault in CRC (but CRC is good, so the digits are the same):<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230403111747.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"484\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230403111747-1024x484.jpg\" alt=\"\" class=\"wp-image-5142\" style=\"width:362px;height:171px\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230403111747-1024x484.jpg 1024w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230403111747-300x142.jpg 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230403111747-768x363.jpg 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230403111747.jpg 1180w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">PING also reports, that we have ERROR3. We might want to write some more text, instead of ERROR3, to have a nice error handler, but not necessary. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The configuration register in our case has 0100 0110, so what does it mean ? Lets look at the datasheet:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"131\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-1-1024x131.png\" alt=\"\" class=\"wp-image-5145\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-1-1024x131.png 1024w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-1-300x38.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-1-768x98.png 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-1.png 1234w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\"><em>Byte 4 of the scratchpad memory contains the configuration register, which is organized as illustrated in Figure 10. The user can set the conversion resolution of the DS18B20 using the R0 and R1 bits in this register as shown in Table. The power-up default of these bits is R0 = 1 and R1 = 1 (12-bit resolution). Note that there is a direct tradeoff between resolution and conversion time. Bit 7 and bits 0 to 4 in the configuration register are reserved for internal use by the device and cannot be overwritten.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So its clear, that bits 0, 1, 2, 3, 4, 7 are not used, only two bits, 5 and 6 are used, to set the conversion resolution = temperature measurement resolution. Lets quickly write the simple code to decode the resolution:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t\t\tuint8_t resolution_bits = Cfg_Reg &gt;&gt; 5; \t\t\t\t\t\t\t\t\t\t\/\/ Bitwise operation 01000110 &gt;&gt; 5 = 010\n\n\t\t\tswitch (resolution_bits) {\n\t\t\tcase 0b00:\n\t\t\t\tST7735_WriteString(0, 120, \"0b00 = 9 bit\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t\t\t\tbreak;\n\t\t\tcase 0b01:\n\t\t\t\tST7735_WriteString(0, 120, \"0b01 = 10 bit\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t\t\t\tbreak;\n\t\t\tcase 0b10:\n\t\t\t\tST7735_WriteString(0, 120, \"0b10 = 11 bit\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t\t\t\tbreak;\n\t\t\tcase 0b11:\n\t\t\t\tST7735_WriteString(0, 120, \"0b11 = 12 bit\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tST7735_WriteString(35, 0, \"ERROR6\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t\t\t\tbreak;\n\t\t\t}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Its really very simple, first we use bitwise operation on Cfg_Reg, which is our configuration register, with value 0100 0110. We make a bitwise right operation, so the bits are scrolled right by 5 places:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">010<mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">0 0110<\/mark> &gt;&gt; 5 = <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">0000 0<\/mark>010<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">All the bits are pushed to the right, dropping them (dropped bits in red), and new zeros added (the yellow zeros) from the left side. But 0000 0010 = 10, so we have filtered out the required bits from the byte. This will only work, because in DS18B20 the first bit will always be 0. Its its 1, for example 1100 0110, first we would do bitwise left 1, so the result would drop the first bit and add 0 on the end, 1000 1100, then we would just bitwise right 6 places, the result would be 10<mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">00 1100<\/mark>, red dropped, <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">0000 00<\/mark>10 = 10. And now its easy to find out the resolution:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"210\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-2-1024x210.png\" alt=\"\" class=\"wp-image-5149\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-2-1024x210.png 1024w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-2-300x62.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-2-768x158.png 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-2.png 1243w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">In our case its 10, so 11 bits resolution, conversion time 375 ms.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">At this point, I hope, you, like me, noticed, that configuration register cannot be 0100 0110. Because in the picture with register decoding bits are like this &#8211; <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">0<\/mark> R1 R0 <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">1 1 1 1 1<\/mark>. The red bits are mandatory and should be the same. And when I realized that &#8211; thought, something must be wrong with the code. Indeed, found an error &#8211; in the DS18B20_Read_Scratchpad() procedure incorrectly picked the configuration bit Cfg_Reg = Scratchpad[3], should be Cfg_Reg = Scratchpad[4]. With correct byte decoded, the view is a bit different:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230404160433.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"732\" height=\"885\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230404160433.jpg\" alt=\"\" class=\"wp-image-5156\" style=\"width:237px;height:287px\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230404160433.jpg 732w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230404160433-248x300.jpg 248w\" sizes=\"auto, (max-width: 732px) 100vw, 732px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">And now we have the correct CFG register, default after every power up &#8211; 0111 1111, 12 bits resolution. Lets try to write a new resolution setting. To do that, we must write to DS18B20 scratchpad:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void DS18B20_Write_Scratchpad() {\n\n\tif (DS18B20_Sensor_present == 1) {\n\t\tif (ROM_OK_Flag == 1) {\n\t\t\tDS18B20_init();\n\t\t\tST7735_WriteString(35, 0, \"PONG\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\n\t\t\tWrite_Byte(0x55);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ Match ROM command &#91;0x55]\n\t\t\tfor (int i = 0; i &lt; 8; i++) {\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ Send previously detected\n\t\t\t\tWrite_Byte(ROM_address&#91;i]);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ ROM, all 8 bytes\n\t\t\t}\n\n\t\t\tWrite_Byte(0x4E);    \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/Write Scratchpad command\n\t\t\tWrite_Byte(0xFF);    \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/Set TH alarm value 0xFF = +125\n\t\t\tWrite_Byte(0x7F);    \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/Set TL alarm value 0x7F = -55C\n\t\t\tWrite_Byte(0x7F);    \t\t\t\t\t\t\t\t\t\t\t\t\t\/\/Set resolution, 9 bit = 0x1F, 10 bit = 0x3F, 11 bit = 0x5F, 12 bit = 0x7F\n\n\t\t}\n\t}\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here, after checking that sensor is still connected we send a Match ROM command, so only the required sensor would respond (again, not necessary if only one sensor is on the network), then we send the ROM address. Next command Write Scratchpad (0x4E), set TH and TL values (it seems, that those must be present) and last command is to set the resolution. In the code there is no part, responding to hardware changes to set the resolution, for example, high level on input PC13 would turn on 12 bit resolution, on input PC14 would set 11 bit resolution, etc. &#8211; all this is changed only in the main program, so you would have to add some lines if hardware switching is required. After the configuration, last thing we can do it the main thing &#8211; decode the temperature:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void DS18B20_Decode_Temperature() {\n\n\tif (DS18B20_Sensor_present == 1) {\n\t\tif (ROM_OK_Flag == 1) {\n\n\t\t\tuint16_t Byte0_LSB = (Scratchpad&#91;0]);\n\t\t\tuint16_t Byte1_MSB = (Scratchpad&#91;1]);\n\t\t\tchar Byte0_LSB_ITOA&#91;16];\n\t\t\tchar Byte1_MSB_ITOA&#91;16];\n\t\t\titoa(Byte0_LSB, Byte0_LSB_ITOA, 16);\n\t\t\titoa(Byte1_MSB, Byte1_MSB_ITOA, 16);\n\t\t\tST7735_WriteString(0, 144, Byte1_MSB_ITOA, Font_7x10, ST7735_YELLOW, ST7735_BLACK);\n\t\t\tST7735_WriteString(14, 144, \":\", Font_7x10, ST7735_YELLOW, ST7735_BLACK);\n\t\t\tST7735_WriteString(21, 144, Byte0_LSB_ITOA, Font_7x10, ST7735_YELLOW, ST7735_BLACK);\n\n\t\t\tif ((Scratchpad&#91;1] &gt;&gt; 4) == 0b0000) {\n\n\t\t\t\tswitch (Cfg_Reg) {\n\t\t\t\tcase 0b01111111:;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ 12 bit resolution\n\n\t\t\t\t\tuint16_t Positive_temp = ((Scratchpad&#91;1]&lt;&lt;8) + Scratchpad&#91;0]);\t\t\t\t\t\/\/ Scratchpad&#91;1]&lt;&lt;8 makes from 0000 000X to X 0000 0000\n\t\t\t\t\tfloat Positive_temp_float = (Positive_temp\/16.0);\t\t\t\t\t\t\t\t\/\/ Calculating the temperature\n\t\t\t\t\tchar Positive_temp_FTOC&#91;16];\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ then + Scratchpad&#91;0] put bits into it X YYYY YYYY\n\t\t\t\t\tsprintf(Positive_temp_FTOC, \"T:+%.4fC\",Positive_temp_float);\t\t\t\t\t\t\/\/ thus making one complete binary number, which must be \/16 for 12 bit resolution\n\t\t\t\t\tST7735_WriteString(49, 144, Positive_temp_FTOC, Font_7x10, ST7735_YELLOW, ST7735_BLUE); \/\/ Writing the Positive Temperature Float TO Char value to LCD\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 0b01011111:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ 11 bit resolution\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 0b00111111:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ 10 bit resolution\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 0b00011111:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/ 9 bit resolution\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tST7735_WriteString(35, 0, \"ERROR7\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ((Scratchpad&#91;1] &gt;&gt; 4) == 0b1111) {\n\t\t\t\t\tST7735_WriteString(77, 144, \"-\", Font_7x10, ST7735_YELLOW, ST7735_BLUE);\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Again, first checking if the sensor is still present, then picking the required bytes from scratchpad (byte 0 and byte 1) and writing those two bytes on display. Here, to show a bit different technique I used itoa() function, instead of sprintf(). There are some advantages and disadvantages &#8211; itoa() is lightweight and fast, but compared to sprintf() it has no formatting and configuration capabilities. Next with if() statement we just check if the temperature is below 0 \u00b0C or above 0 \u00b0C. Let&#8217; look at the example temperatures table in datasheet:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"409\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-3-1024x409.png\" alt=\"\" class=\"wp-image-5166\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-3-1024x409.png 1024w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-3-300x120.png 300w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-3-768x307.png 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/image-3.png 1239w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">We can clearly see, that below 0 \u00b0C temperatures has ones in the first byte and first bit of the second byte: <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">-55 \u00b0C = <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">1111 1<\/mark>100 1001 0000<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">IT would be wise to do first &#8211; check if there are &#8222;1&#8221; or &#8222;0&#8221; and make two different calculations, because for above 0 \u00b0C its pretty straight forward, but for below 0 \u00b0C we will need to convert the value, but its also described in the datasheet. So there should be two conditions for the if() statement:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">(Scratchpad[1] &gt;&gt; 4) == 0b0000) and (Scratchpad[1] &gt;&gt; 4) == 0b1111), which makes right bitshift of the byte 1 of the scratchpad. What it does is it takes byte 1 of the scratch pad (-55 \u00b0C = <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">1111 1100<\/mark> 1001 0000) and shits it to the right by 4 places, so dropping the right 4 bits (1100) and leaves us with only left 4 bits (1111). And the logic is simple &#8211; if its 0000 then temperature is above zero degrees, if its 1111 &#8211; temperature is below zero. In the example we calculate only positive temperatures (negative temperature section is not yet coded). The calculation is done by this line:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>float Positive_temp_float = (Positive_temp\/16.0);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Different approaches can be used to have a floating variable, but because or processor supports floating point calculation (internal floating point unit &#8211; FPU), we just enable &#8222;-u _printf_float&#8221; in the &#8222;Project Properties &gt; C\/C++ Build &gt; Settings &gt; Tool Settings&#8221; and it does the job. Notice, that 16 has a zero (16.0) and to make it floating point variable. Next we configure the variable for the LCD:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sprintf(Positive_temp_FTOC, \"T:+%.4fC\",Positive_temp_float);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">T:+%.4fC is the formatting, meaning we write T:+ on display, then %f means that it will be floating point digit, C is just a letter C, to mark Celsius degrees. The .4 means that we format the floating point digit to have 4 digits after comma (.), otherwise we would have 6 digits and last two would always be 0.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But now we have this view on LCD:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230426164747.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"938\" src=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230426164747.jpg\" alt=\"\" class=\"wp-image-5174\" style=\"width:360px;height:440px\" srcset=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230426164747.jpg 768w, https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/IMG20230426164747-246x300.jpg 246w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Under the scratchpad data we have separate indication of TH and TL &#8211; high and low alarm setting (2 and 3 bytes of the scratch pad), which is not correct, by the way, need to finalize the decoding, for proper indication. Next we have configuration register (3 byte of the scratchpad) in binary format, just to see how bits are changed, when setting different resolutions (because its the only thing that can be changed\/configured). Then after checking the configuration register bits, we indicate the current setting 0b11, which means 12 bit resolution. Below, in black background, we have bytes 1 and 0 of the scratchpad, its where the temperature reading is saved and to the right of those two bytes we have decoded temperature, at the moment &#8211; positive only, still need to code two&#8217;s complement calculation or conversion for the negative temperatures.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The code is &#8222;dirty&#8221; and not yet completed, but that is done on purpose &#8211; dirty, not optimized code will give more insights and information about how it works, allowing to filter out unnecessary functions and making it easy to complete to the fully working program, at the same time trying different approaches to complete some task.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/DS18B20-with-LCD.zip\" data-type=\"URL\" data-id=\"https:\/\/www.dclabs.lt\/dainiaus\/wp-content\/uploads\/2023\/04\/DS18B20-with-LCD.zip\" target=\"_blank\" rel=\"noreferrer noopener\">Current files for the CubeIDE are here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This one is for my friend Nico and other readers who knows English. Some readers remember, that we already tested the work of DS18B20 with Atmega328P on Arduino board, that was easy, because of ready libraries. But lets put away toys and use STM32F466RE on Nucleo-F446RE development board. We already have LCD display outputting some&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,35],"tags":[],"class_list":["post-5000","post","type-post","status-publish","format-standard","hentry","category-elektronika","category-stm32"],"_links":{"self":[{"href":"https:\/\/www.dclabs.lt\/dainiaus\/wp-json\/wp\/v2\/posts\/5000","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dclabs.lt\/dainiaus\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dclabs.lt\/dainiaus\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dclabs.lt\/dainiaus\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dclabs.lt\/dainiaus\/wp-json\/wp\/v2\/comments?post=5000"}],"version-history":[{"count":131,"href":"https:\/\/www.dclabs.lt\/dainiaus\/wp-json\/wp\/v2\/posts\/5000\/revisions"}],"predecessor-version":[{"id":8755,"href":"https:\/\/www.dclabs.lt\/dainiaus\/wp-json\/wp\/v2\/posts\/5000\/revisions\/8755"}],"wp:attachment":[{"href":"https:\/\/www.dclabs.lt\/dainiaus\/wp-json\/wp\/v2\/media?parent=5000"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dclabs.lt\/dainiaus\/wp-json\/wp\/v2\/categories?post=5000"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dclabs.lt\/dainiaus\/wp-json\/wp\/v2\/tags?post=5000"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}