DS18B20 and STM32

Description

I have covered few temperature sensors in the past eg- LM35, DHT11, DHT22 and also the internal temperature sensor of the STm itself. Today in this tutorial I am going to interface DS18B20 temperature sensor with STM32.

The DS18B20 digital thermometer provides 9-bit to 12-bit Celsius temperature measurements and has an alarm function with non-volatile user-programmable upper and lower trigger points. Like DHT11 and DHT22, DS18B20 also communicates over a 1-Wire bus that by definition requires only one data line (and ground) for communication with the microcontroller. Let’s see how to program a ds18b20 temperature sensor using STM32.

How to

I am going to skip the Cubemx setup process as it’s usual one only. I am using pin PA1 as the data pin for the sensor and controller is running at it’s maximum frequency. Also I am using DWT library for the delay in microseconds. It will be included in the code when you download it below. We need to write few functions for the sensor. They are as follows..

In order for the sensor to work, we need to initialise it everytime. According to the datasheet, the initialisation is done by pulling the data pin LOW for 480 us and than reading the pin for the presence pulse sent by sensor. Here is the function for that



uint8_t ds18b20_init (void)
{
	gpio_set_output ();   // set the pin as output
	HAL_GPIO_WritePin (GPIOA, GPIO_PIN_1, 0);  // pull the pin low
	DWT_Delay_us (480);   // delay according to datasheet

	gpio_set_input ();    // set the pin as input
	DWT_Delay_us (80);    // delay according to datasheet

	if (!(HAL_GPIO_ReadPin (GPIOA, GPIO_PIN_1)))    // if the pin is low i.e the presence pulse is there
	{
		DWT_Delay_us (400); // wait for 400 us
		return 0;
	}

	else
	{
		DWT_Delay_us (400);  // wait for 400 us
		return 1;
	}
}

To write a BIT to the sensor, we need to perform some operation on the data line. To generate a Write 1, after pulling the 1-Wire bus low, the master must release the 1-Wire bus within 15µs. When the bus is released, the 5kΩ pullup resistor will pull the bus high.

To generate a Write 0 time slot, after pulling the 1-Wire bus low, the master must continue to hold the bus low for the duration of the time slot (at least 60µs).

void write (uint8_t data)
{
	gpio_set_output ();  // set as output
	for (int i=0; i<8; i++)
	{
		if ((data & (1<<i))!=0)  // LSB first
		{
			// write 1 sequence

			gpio_set_output ();  // set as output
			HAL_GPIO_WritePin (GPIOA, GPIO_PIN_1, 0); // Pull the Pin LOW
			DWT_Delay_us (1);  // wait for 1us
			gpio_set_input (); // set the pin as input
			DWT_Delay_us (60);  // wait for 60us
		}

		else
		{
			// write 0
			gpio_set_output ();
			HAL_GPIO_WritePin (GPIOA, GPIO_PIN_1, 0);
			DWT_Delay_us (60);
			gpio_set_input ();
		}
	}
}



A read time slot is initiated by the master device pulling the 1-Wire bus low for a minimum of 1µs and then releasing the bus. After the master initiates the read time slot, the DS18B20 will begin transmitting a 1 or 0 on bus. It transmits a 1 by leaving the bus high and transmits a 0 by pulling the bus low. When transmitting a 0, the sensor will release the bus by the end of the time slot, and the bus will be pulled back to its high idle state by the pullup resister.

uint8_t read (void)
{
	uint8_t value=0;
	gpio_set_input ();  // set the pin as input

	for (int i=0;i<8;i++)
	{
              // Initiate READ 

		gpio_set_output ();  // set as output  
		HAL_GPIO_WritePin (GPIOA, GPIO_PIN_1,0);  // pull the pin LOW
		DWT_Delay_us (2); // wait for 2 us

		gpio_set_input ();  // set as input
		if (HAL_GPIO_ReadPin (GPIOA, GPIO_PIN_1))  // if the pin is high
		{
			value |= 1<<i;  // write 1
		}
		DWT_Delay_us (60);  // wait for 60 us

	}
	return value;
}

The following is the sequence for reading temperature from the ds18b20


		check = reset ();
		write (0xCC);  // skip ROM
		write (0x44);  // convert t

		HAL_Delay (800);

		reset ();
		write (0xCC);  // skip ROM
		write (0xBE);  // Read Scratchpad

		temp_l = read();
		temp_h = read();

		temp = (temp_h<<8)|temp_l;
                temperature = (float)temp/16;

CODE

GPIO_InitTypeDef GPIO_InitStruct;

void gpio_set_input (void)
{
  GPIO_InitStruct.Pin = GPIO_PIN_1;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}


void gpio_set_output (void)
{
  GPIO_InitStruct.Pin = GPIO_PIN_1;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

uint8_t check =2, temp_l, temp_h;
uint16_t temp;
float temperature;


uint8_t ds18b20_init (void)
{
	gpio_set_output ();   // set the pin as output
	HAL_GPIO_WritePin (GPIOA, GPIO_PIN_1, 0);  // pull the pin low
	DWT_Delay_us (480);   // delay according to datasheet

	gpio_set_input ();    // set the pin as input
	DWT_Delay_us (80);    // delay according to datasheet

	if (!(HAL_GPIO_ReadPin (GPIOA, GPIO_PIN_1)))    // if the pin is low i.e the presence pulse is there
	{
		DWT_Delay_us (400);  // wait for 400 us
		return 0;
	}

	else
	{
		DWT_Delay_us (400);
		return 1;
	}
}

void write (uint8_t data)
{
	gpio_set_output ();   // set as output

	for (int i=0; i<8; i++)
	{

		if ((data & (1<<i))!=0)  // if the bit is high
		{
			// write 1

			gpio_set_output ();  // set as output
			HAL_GPIO_WritePin (GPIOA, GPIO_PIN_1, 0);  // pull the pin LOW
			DWT_Delay_us (1);  // wait for  us

			gpio_set_input ();  // set as input
			DWT_Delay_us (60);  // wait for 60 us
		}

		else  // if the bit is low
		{
			// write 0

			gpio_set_output ();
			HAL_GPIO_WritePin (GPIOA, GPIO_PIN_1, 0);  // pull the pin LOW
			DWT_Delay_us (60);  // wait for 60 us

			gpio_set_input ();
		}
	}
}


uint8_t read (void)
{
	uint8_t value=0;
	gpio_set_input ();

	for (int i=0;i<8;i++)
	{
		gpio_set_output ();   // set as output

		HAL_GPIO_WritePin (GPIOA, GPIO_PIN_1, 0);  // pull the data pin LOW
		DWT_Delay_us (2);  // wait for 2 us

		gpio_set_input ();  // set as input
		if (HAL_GPIO_ReadPin (GPIOA, GPIO_PIN_1))  // if the pin is HIGH
		{
			value |= 1<<i;  // read = 1
		}
		DWT_Delay_us (60);  // wait for 60 us
	}
	return value;
}


/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */
	
	lcd_init ();
	DWT_Delay_Init();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		
		check = ds18b20_init ();
		write (0xCC);  // skip ROM
		write (0x44);  // convert t

		HAL_Delay (800);

		ds18b20_init ();
		write (0xCC);  // skip ROM
		write (0xBE);  // Read Scratchpad

		temp_l = read();
		temp_h = read();
		temp = (temp_h<<8)|temp_l;
		temperature = (float)temp/16;
		
		// display on LCD
		
		lcd_send_string ("TEMP : ");
		
		lcd_send_cmd (0x87);
		lcd_send_data ((temperature/10) + 48);
		lcd_send_data (((int )temperature%10) + 48);
		lcd_send_data ('.');
		temperature = temperature*10;
		lcd_send_data (((int )temperature%10) + 48);
		temperature = temperature*10;
		lcd_send_data (((int )temperature%10) + 48);
		
		lcd_send_cmd (0x80);
  }
  /* USER CODE END 3 */
}
.......

static void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */

}

Connections

Result

Video

You can buy me a coffee sensor 🙂

To Download the code click below

Share this POST

, , , , ,

10
Leave a Reply

avatar
6 Comment threads
4 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
6 Comment authors
MOJTABASamiraBrunoadminLuiz Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
Ilya
Guest
Ilya

Hi!
This description very good, need attention read all material.
Simple code and algorithm usability peripheries, me like this site 🙂
Good Luck!

Luiz
Guest
Luiz

Hi!! I like very very much your tutorials, thank you very much!!
It would be nice to have the correct source files for the ds18b20, as they are for i2c lcd. Could you, please, provide the files accordingly?
Many thanks and best regards!!
Luiz

Bruno
Guest
Bruno

very good the text. I would like to know how to read more than one sensor on the same pin? That is possible with this code ?

Bruno
Guest
Bruno

I would like to know how do I use more than one sensor on the same pin with these functions?

Samira
Guest
Samira

Hi, thx for good projekt. Can you say me , how does work read function by Value? I have Problem with value |= 1<<i.
Value must be OR with (1<< i) and i must schift 1 bit to Right ?
THX

MOJTABA
Guest
MOJTABA

I really appreciate what you are doing ..when I’m watching youtube tutorial and hear background music which is exclusive for your tutorial ..it makes me cheerfull ..because I am sure that it is going to work out..thanks for that, keep it on I learn a lot from you.

Menu