Embedded System Design 2 - Project
DS18B20.c File Reference

All code for the DS18B20 temperature sensor. More...

#include <stdint.h>
#include <stdbool.h>
#include "em_cmu.h"
#include "em_gpio.h"
#include "DS18B20.h"
#include "pin_mapping.h"
#include "debug_dbprint.h"
#include "delay.h"
#include "util.h"
#include "ustimer.h"

Go to the source code of this file.

Macros

#define DBPRINT_TIMEOUT   0
 
#define TIMEOUT_INIT   20
 
#define TIMEOUT_CONVERSION   500 /* 12 bit resolution (reset default) = 750 ms max resolving time */
 

Functions

static void powerDS18B20 (bool enabled)
 Enable or disable the power to the temperature sensor. More...
 
static bool init_DS18B20 (void)
 Initialize communication to the DS18B20. More...
 
static void writeByteToDS18B20 (uint8_t data)
 Write a byte (uint8_t) to the DS18B20. More...
 
static uint8_t readByteFromDS18B20 (void)
 Read a byte (uint8_t) from the DS18B20. More...
 
static int32_t convertTempData (uint8_t tempLS, uint8_t tempMS)
 Convert temperature data. More...
 
int32_t readTempDS18B20 (void)
 Get a temperature value from the DS18B20. More...
 

Variables

bool DS18B20_VDD_initialized = false
 

Detailed Description

All code for the DS18B20 temperature sensor.

Version
3.1
Author
Alec Vanderhaegen & Sarah Goossens
Modified by Brecht Van Eeckhoudt

Versions

  • v1.0: Reformatted existing methods to use pin_mapping.h, changed unsigned char to uint8_t values, added comments and cleaned up includes.
  • v1.1: Added documentation, removed unnecessary GPIO statements regarding DOUT values of VDD pin.
  • v1.2: Removed some unnecessary GPIO lines and added comments about out (DOUT) argument.
  • v1.3: Changed some methods to be static (~hidden).
  • v1.4: Cleaned up includes.
  • v1.5: Made more methods static.
  • v1.6: Updated documentation.
  • v1.7: Started using new delay functionality.
  • v1.8: Added line to disable DATA pin after a measurement, this breaks the code but fixes the sleep current.
  • v1.9: Enabled and disabled timer each time a measurement is taken.
  • v2.0: Updated documentation.
  • v2.1: Changed method to return uint32_t instead of float.
  • v2.2: Changed error numbering, moved definition from header to source file and updated header file include.
  • v2.3: Changed timeout variable and changed types to int32_t.
  • v2.4: Fixed temperature measurement and refined timeout functionality.
  • v2.5: Updated documentation.
  • v2.6: Updated code to don't execute code further if the first initialization failed.
  • v3.0: Disabled initialized functionality before entering an error function, added functionality to exit methods after error call and updated version number.
  • v3.1: Removed static before the local variable (not necessary).

License

Copyright (C) 2019 - Brecht Van Eeckhoudt

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

A copy of the GNU General Public License can be found in the LICENSE file along with this source code.


Some methods also use code obtained from examples from Silicon Labs' GitHub. These sections are licensed under the Silabs License Agreement. See the file "Silabs_License_Agreement.txt" for details. Before using this software for any purpose, you must agree to the terms of that agreement.

Definition in file DS18B20.c.

Macro Definition Documentation

◆ DBPRINT_TIMEOUT

#define DBPRINT_TIMEOUT   0

Enable (1) or disable (0) printing the timeout counter value using DBPRINT

Definition at line 80 of file DS18B20.c.

◆ TIMEOUT_CONVERSION

#define TIMEOUT_CONVERSION   500 /* 12 bit resolution (reset default) = 750 ms max resolving time */

Definition at line 84 of file DS18B20.c.

◆ TIMEOUT_INIT

#define TIMEOUT_INIT   20

Definition at line 83 of file DS18B20.c.

Function Documentation

◆ convertTempData()

static int32_t convertTempData ( uint8_t  tempLS,
uint8_t  tempMS 
)
static

Convert temperature data.

Note
This is a static method because it's only internally used in this file and called by other methods if necessary.
Parameters
[in]tempLSLeast significant byte.
[in]tempMSMost significant byte.
Returns
The converted temperature data.

Definition at line 423 of file DS18B20.c.

424 {
425  uint16_t rawDataMerge;
426  uint16_t reverseRawDataMerge;
427 
428  int32_t finalTemperature;
429 
430  /* Check if it is a negative temperature value
431  * 0xF8 = 0b1111 1000 */
432  if (tempMS & 0xF8)
433  {
434  rawDataMerge = tempMS;
435 
436  /* Left shift 8 times */
437  rawDataMerge <<= 8;
438 
439  /* Add the second part */
440  rawDataMerge += tempLS;
441 
442  /* Invert the value since we have a negative temperature */
443  reverseRawDataMerge = ~rawDataMerge;
444 
445  /* Calculate the final temperature */
446  finalTemperature = -(reverseRawDataMerge + 1) * 62.5;
447  }
448  /* We're dealing with a positive temperature */
449  else
450  {
451  rawDataMerge = tempMS;
452 
453  /* Left shift 8 times */
454  rawDataMerge <<= 8;
455 
456  /* Add the second part */
457  rawDataMerge += tempLS;
458 
459  /* Calculate the final temperature */
460  finalTemperature = rawDataMerge * 62.5;
461  }
462 
463  return (finalTemperature);
464 }

◆ init_DS18B20()

static bool init_DS18B20 ( void  )
static

Initialize communication to the DS18B20.

Note
This is a static method because it's only internally used in this file and called by other methods if necessary.
Returns
  • true - Presence pulse detected in time.
  • false - No presence pulse detected.

Definition at line 271 of file DS18B20.c.

272 {
273  /* Timeout counter */
274  uint32_t counter = 0;
275 
276  /* MASTER RESET: Pull data line LOW for at least 480 µs (Master TX) */
277  GPIO_PinModeSet(TEMP_DATA_PORT, TEMP_DATA_PIN, gpioModePushPull, 0); /* gpioModePushPull: Last argument directly sets the pin state */
278  USTIMER_DelayIntSafe(480);
279 
280  /* Change pin-mode to input - External pull-up resistor pulls data line back HIGH */
281  GPIO_PinModeSet(TEMP_DATA_PORT, TEMP_DATA_PIN, gpioModeInput, 0);
282 
283  /* Check if the line becomes LOW (~ wait while it stays high) during the maximum waiting time
284  * The DS18B20 should detect the data line rising due to the pull-up resistor, waits 15 - 50 µs
285  * and then pulls the line back LOW (for 60 - 240 µs) to indicate it's PRESENCE */
286  while ((counter < TIMEOUT_INIT) && (GPIO_PinInGet(TEMP_DATA_PORT, TEMP_DATA_PIN) == 1)) counter++;
287 
288  /* Exit the function if the maximum waiting time was reached */
289  if (counter == TIMEOUT_INIT)
290  {
291 
292 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
293  dbcrit("No DS18B20 presence pulse detected in time!");
294 #endif /* DEBUG_DBPRINT */
295 
296  error(28);
297 
298  return (false);
299  }
300 #if DBPRINT_TIMEOUT == 1 /* DBPRINT_TIMEOUT */
301  else
302  {
303 
304 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
305  dbwarnInt("DS18B20 INIT (", counter, ")");
306 #endif /* DEBUG_DBPRINT */
307 
308  }
309 #endif /* DBPRINT_TIMEOUT */
310 
311  /* Master RX should be at least 480 µs */
312  USTIMER_DelayIntSafe(480);
313 
314  return (true);
315 }
void dbwarnInt(char *message1, int32_t value, char *message2)
Print a warning value surrounded by two strings (char array) to USARTx.
Definition: dbprint.c:598
void error(uint8_t number)
Error method.
Definition: util.c:131
#define TEMP_DATA_PIN
Definition: pin_mapping.h:104
#define TEMP_DATA_PORT
Definition: pin_mapping.h:103
#define TIMEOUT_INIT
Definition: DS18B20.c:83
void dbcrit(char *message)
Print a critical error string (char array) in red to USARTx and go to the next line.
Definition: dbprint.c:539

◆ powerDS18B20()

static void powerDS18B20 ( bool  enabled)
static

Enable or disable the power to the temperature sensor.

This method also initializes the pin-mode if necessary.

Note
This is a static method because it's only internally used in this file and called by other methods if necessary.
Parameters
[in]enabled
  • true - Enable the GPIO pin connected to the VDD pin of the temperature sensor.
  • talse - Disable the GPIO pin connected to the VDD pin of the temperature sensor.

Definition at line 237 of file DS18B20.c.

238 {
239  /* Enable necessary clocks (just in case) */
240  CMU_ClockEnable(cmuClock_HFPER, true); /* GPIO is a High Frequency Peripheral */
241  CMU_ClockEnable(cmuClock_GPIO, true);
242 
243  /* Initialize VDD pin if not already the case */
245  {
246  /* In the case of gpioModePushPull", the last argument directly sets the pin state */
247  GPIO_PinModeSet(TEMP_VDD_PORT, TEMP_VDD_PIN, gpioModePushPull, enabled);
248 
250  }
251  else
252  {
253  if (enabled) GPIO_PinOutSet(TEMP_VDD_PORT, TEMP_VDD_PIN); /* Enable VDD pin */
254  else GPIO_PinOutClear(TEMP_VDD_PORT, TEMP_VDD_PIN); /* Disable VDD pin */
255  }
256 }
bool DS18B20_VDD_initialized
Definition: DS18B20.c:88
#define TEMP_VDD_PIN
Definition: pin_mapping.h:106
#define TEMP_VDD_PORT
Definition: pin_mapping.h:105

◆ readByteFromDS18B20()

static uint8_t readByteFromDS18B20 ( void  )
static

Read a byte (uint8_t) from the DS18B20.

Note
This is a static method because it's only internally used in this file and called by other methods if necessary.
Returns
The byte read from the DS18B20.

Definition at line 378 of file DS18B20.c.

379 {
380  /* Data to eventually return */
381  uint8_t data = 0x0;
382 
383  /* Read the byte, bit by bit */
384  for (uint8_t i = 0; i < 8; i++)
385  {
386  /* Change pin-mode to input */
387  GPIO_PinModeSet(TEMP_DATA_PORT, TEMP_DATA_PIN, gpioModeInput, 0);
388 
389  /* Right shift bits once */
390  data >>= 1;
391 
392  /* If the line is high, OR the first bit of the data:
393  * 0x80 = 1000 0000 */
394  if (GPIO_PinInGet(TEMP_DATA_PORT, TEMP_DATA_PIN)) data |= 0x80;
395 
396  /* In the case of gpioModePushPull", the last argument directly sets the pin state */
397  GPIO_PinModeSet(TEMP_DATA_PORT, TEMP_DATA_PIN, gpioModePushPull, 1);
398 
399  /* Wait some time before going into next loop */
400  USTIMER_DelayIntSafe(70);
401  }
402  return (data);
403 }
MeasurementData_t data
Definition: main.c:189
#define TEMP_DATA_PIN
Definition: pin_mapping.h:104
#define TEMP_DATA_PORT
Definition: pin_mapping.h:103

◆ readTempDS18B20()

int32_t readTempDS18B20 ( void  )

Get a temperature value from the DS18B20.

USTimer gets initialized, the sensor gets powered, the data-transmission takes place, the timer gets de-initialized to disable the clocks and interrupts, the data and power pin get disabled and finally the read values are converted to an int32_t value.
Negative temperatures work fine.

Returns
The read temperature data.

Definition at line 113 of file DS18B20.c.

114 {
115  /* Timeout counter */
116  uint16_t counter = 0;
117 
118  /* Variable to indicate if a conversion has been completed */
119  bool conversionCompleted = false;
120 
121  /* Variable to hold raw data bytes */
122  uint8_t rawDataFromDS18B20Arr[9] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
123 
124  /* Initialize timer
125  * Initializing and disabling the timer again adds about 40 µs active time but should conserve sleep energy... */
126  USTIMER_Init();
127 
128  /* Initialize and power VDD pin */
129  powerDS18B20(true);
130 
131  /* Power-up delay of 5 ms */
132  delay(5);
133 
134  /* Initialize communication and only continue if successful */
135  if (init_DS18B20())
136  {
137  writeByteToDS18B20(0xCC); /* 0xCC = "Skip Rom" (address all devices on the bus simultaneously without sending out any ROM code information) */
138  writeByteToDS18B20(0x44); /* 0x44 = "Convert T" */
139 
140  /* MASTER now generates "read time slots", the DS18B20 will write HIGH to the bus if the conversion is completed
141  * The datasheet gives the following directions for time slots, but reading bytes also seems to work...
142  * - Read time slots have a 60 µs duration and 1 µs recovery between slots
143  * - After the master pulls the line low for 1 µs, the data is valid for up to 15 µs */
144  while ((counter < TIMEOUT_CONVERSION) && !conversionCompleted)
145  {
146  uint8_t testByte = readByteFromDS18B20();
147  if (testByte > 0) conversionCompleted = true;
148 
149  counter++;
150  }
151 
152  /* Exit the function if the maximum waiting time was reached */
153  if (counter == TIMEOUT_CONVERSION)
154  {
155 
156 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
157  dbcrit("Waiting time for DS18B20 conversion reached!");
158 #endif /* DEBUG_DBPRINT */
159 
160  /* Disable interrupts and turn off the clock to the underlying hardware timer. */
161  USTIMER_DeInit();
162 
163  /* Disable data pin (otherwise we got a "sleep" current of about 330 µA due to the on-board 10k pull-up) */
164  GPIO_PinModeSet(TEMP_DATA_PORT, TEMP_DATA_PIN, gpioModeDisabled, 0);
165 
166  /* Disable the VDD pin */
167  powerDS18B20(false);
168 
169  error(29);
170 
171  /* Exit function */
172  return (0);
173 
174  }
175 #if DBPRINT_TIMEOUT == 1 /* DBPRINT_TIMEOUT */
176  else
177  {
178 
179 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
180  dbwarnInt("DS18B20 conversion (", counter, ")");
181 #endif /* DEBUG_DBPRINT */
182 
183  }
184 #endif /* DBPRINT_TIMEOUT */
185 
186  init_DS18B20(); /* Initialize communication */
187  writeByteToDS18B20(0xCC); /* 0xCC = "Skip Rom" */
188  writeByteToDS18B20(0xBE); /* 0xCC = "Read Scratchpad" */
189 
190  /* Read the bytes */
191  for (uint8_t i = 0; i < 9; i++) rawDataFromDS18B20Arr[i] = readByteFromDS18B20();
192 
193  /* Disable interrupts and turn off the clock to the underlying hardware timer. */
194  USTIMER_DeInit();
195 
196  /* Disable data pin (otherwise we got a "sleep" current of about 330 µA due to the on-board 10k pull-up) */
197  GPIO_PinModeSet(TEMP_DATA_PORT, TEMP_DATA_PIN, gpioModeDisabled, 0);
198 
199  /* Disable the VDD pin */
200  powerDS18B20(false);
201 
202  /* Return the converted byte */
203  return (convertTempData(rawDataFromDS18B20Arr[0], rawDataFromDS18B20Arr[1]));
204  }
205  else
206  {
207  /* Disable interrupts and turn off the clock to the underlying hardware timer. */
208  USTIMER_DeInit();
209 
210  /* Disable data pin (otherwise we got a "sleep" current of about 330 µA due to the on-board 10k pull-up) */
211  GPIO_PinModeSet(TEMP_DATA_PORT, TEMP_DATA_PIN, gpioModeDisabled, 0);
212 
213  /* Disable the VDD pin */
214  powerDS18B20(false);
215 
216  /* Exit function */
217  return (0);
218  }
219 }
static void writeByteToDS18B20(uint8_t data)
Write a byte (uint8_t) to the DS18B20.
Definition: DS18B20.c:329
void dbwarnInt(char *message1, int32_t value, char *message2)
Print a warning value surrounded by two strings (char array) to USARTx.
Definition: dbprint.c:598
static void powerDS18B20(bool enabled)
Enable or disable the power to the temperature sensor.
Definition: DS18B20.c:237
#define TIMEOUT_CONVERSION
Definition: DS18B20.c:84
void error(uint8_t number)
Error method.
Definition: util.c:131
static uint8_t readByteFromDS18B20(void)
Read a byte (uint8_t) from the DS18B20.
Definition: DS18B20.c:378
static int32_t convertTempData(uint8_t tempLS, uint8_t tempMS)
Convert temperature data.
Definition: DS18B20.c:423
void delay(uint32_t msDelay)
Wait for a certain amount of milliseconds in EM2/3.
Definition: delay.c:124
#define TEMP_DATA_PIN
Definition: pin_mapping.h:104
#define TEMP_DATA_PORT
Definition: pin_mapping.h:103
static bool init_DS18B20(void)
Initialize communication to the DS18B20.
Definition: DS18B20.c:271
void dbcrit(char *message)
Print a critical error string (char array) in red to USARTx and go to the next line.
Definition: dbprint.c:539

◆ writeByteToDS18B20()

static void writeByteToDS18B20 ( uint8_t  data)
static

Write a byte (uint8_t) to the DS18B20.

Note
This is a static method because it's only internally used in this file and called by other methods if necessary.
Parameters
[in]dataThe data to write to the DS18B20.

Definition at line 329 of file DS18B20.c.

330 {
331  /* In the case of gpioModePushPull", the last argument directly sets the pin state */
332  GPIO_PinModeSet(TEMP_DATA_PORT, TEMP_DATA_PIN, gpioModePushPull, 0);
333 
334  /* Write the byte, bit by bit */
335  for (uint8_t i = 0; i < 8; i++)
336  {
337  /* Check if we need to write a "1" */
338  if (data & 0x01)
339  {
340  GPIO_PinOutClear(TEMP_DATA_PORT, TEMP_DATA_PIN);
341 
342  /* 5 µs delay should be called here but this loop works fine too... */
343  for (uint8_t i=0; i<5; i++);
344 
345  GPIO_PinOutSet(TEMP_DATA_PORT, TEMP_DATA_PIN);
346  USTIMER_DelayIntSafe(60);
347  }
348  /* If not, write a "0" */
349  else
350  {
351  GPIO_PinOutClear(TEMP_DATA_PORT, TEMP_DATA_PIN);
352  USTIMER_DelayIntSafe(60);
353  GPIO_PinOutSet(TEMP_DATA_PORT, TEMP_DATA_PIN);
354 
355  /* 5 µs delay should be called here but this loop works fine too... */
356  for (uint8_t i=0; i<5; i++);
357  }
358  /* Right shift bits once */
359  data >>= 1;
360  }
361 
362  /* Set data line high */
363  GPIO_PinOutSet(TEMP_DATA_PORT, TEMP_DATA_PIN);
364 }
MeasurementData_t data
Definition: main.c:189
#define TEMP_DATA_PIN
Definition: pin_mapping.h:104
#define TEMP_DATA_PORT
Definition: pin_mapping.h:103

Variable Documentation

◆ DS18B20_VDD_initialized

bool DS18B20_VDD_initialized = false

Definition at line 88 of file DS18B20.c.