Hello everyone,
I am experiencing issues to get temperature from DS18B20 sensor with a nRF5340 board.
The probleme I have is that the only values my code reads is 0xFF.
I am using nRF Connect SDK v2.0.0. and here is my code :
Im am using two different sources I found on internet :
I have copied this code in a file named ds18b20.c and only replaces the
nrf_delay_us(timeout);functions by
k_sleep(K_USEC(timeout));functions.
/**
* Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <hal/nrf_gpio.h>
#include <kernel.h>
#include "ds18b20.h"
// #define DS_PIN 26
#define DS_PIN 10
// Commands
#define STARTCONVO 0x44
#define READSCRATCH 0xBE
#define WRITESCRATCH 0x4E
// Scratchpad locations
#define TEMP_LSB 0
#define TEMP_MSB 1
// Device resolution
#define TEMP_9_BIT 0x1F // 9 bit
#define TEMP_10_BIT 0x3F // 10 bit
#define TEMP_11_BIT 0x5F // 11 bit
#define TEMP_12_BIT 0x7F // 12 bit
typedef uint8_t ScratchPad[9];
/**@brief Function for sending one bit to bus.
*/
void ds18b20_send(char bit)
{
nrf_gpio_cfg_output(DS_PIN);
nrf_gpio_pin_clear(DS_PIN);
k_sleep(K_USEC(5));
if(bit==1)
{
nrf_gpio_pin_set(DS_PIN);
}
k_sleep(K_USEC(80));
nrf_gpio_pin_set(DS_PIN);
}
/**@brief Function for reading one bit from bus.
*/
unsigned char ds18b20_read(void)
{
unsigned char presence=0;
nrf_gpio_cfg_output(DS_PIN);
nrf_gpio_pin_clear(DS_PIN);
k_sleep(K_USEC(2));
nrf_gpio_pin_set(DS_PIN);;
k_sleep(K_USEC(15));
nrf_gpio_cfg_input(DS_PIN,NRF_GPIO_PIN_NOPULL);
if(nrf_gpio_pin_read(DS_PIN))
{
presence = 1;
}
else
{
presence = 0;
}
return presence;
}
/**@brief Function for sending one byte to bus.
*/
void ds18b20_send_byte(char data)
{
unsigned char i;
unsigned char x;
for(i=0;i<8;i++)
{
x = data>>i;
x &= 0x01;
ds18b20_send(x);
}
k_sleep(K_USEC(100));
}
/**@brief Function for reading one byte from bus.
*/
unsigned char ds18b20_read_byte(void)
{
unsigned char i;
unsigned char data = 0;
for (i=0;i<8;i++)
{
if(ds18b20_read()) data|=0x01<<i;
k_sleep(K_USEC(15));
}
return(data);
}
/**@brief Function for sending reset pulse.
*/
unsigned char ds18b20_reset(void)
{
unsigned char presence;
nrf_gpio_cfg_output(DS_PIN);
nrf_gpio_pin_clear(DS_PIN);
k_sleep(K_USEC(500));
nrf_gpio_pin_set(DS_PIN);
nrf_gpio_cfg_input(DS_PIN,NRF_GPIO_PIN_NOPULL); // usikkert p� pull her. m� sjekkes
k_sleep(K_USEC(30));
if(nrf_gpio_pin_read(DS_PIN) == 0)
presence = 1;
else
presence = 0;
k_sleep(K_USEC(470));
if(nrf_gpio_pin_read(DS_PIN) == 1)
presence = 1;
else
presence = 0;
return presence;
}
/**@brief Function for reading temperature.
*/
float ds18b20_get_temp(void)
{
unsigned char check;
char temp1=0, temp2=0;
check=ds18b20_reset();
if(check)
{
ds18b20_send_byte(0xCC);
ds18b20_send_byte(0x44);
k_sleep(K_MSEC(600UL));
check=ds18b20_reset();
ds18b20_send_byte(0xCC);
ds18b20_send_byte(0xBE);
temp1=ds18b20_read_byte();
temp2=ds18b20_read_byte();
check=ds18b20_reset();
float temp=0;
temp=(float)(temp1+(temp2*256))/16;
return temp;
}
return 0;
}
/**@brief Function for reading bit.
*/
uint8_t OneWire_read_bit(void)
{
uint8_t r;
nrf_gpio_cfg_output(DS_PIN);
nrf_gpio_pin_clear(DS_PIN);
k_sleep(K_USEC(3));
nrf_gpio_cfg_input(DS_PIN,NRF_GPIO_PIN_NOPULL);
k_sleep(K_USEC(10));
r =nrf_gpio_pin_read(DS_PIN);
k_sleep(K_USEC(53));
return r;
}
/**@brief Function for reading.
*/
uint8_t OneWire_read()
{
uint8_t bitMask;
uint8_t r = 0;
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
if ( OneWire_read_bit()) r |= bitMask;
}
return r;
}
/**@brief Function for reading scratchpad value
*/
void ds18b20_readScratchPad(uint8_t *scratchPad, uint8_t fields)
{
ds18b20_reset();
ds18b20_send_byte(0xCC);
ds18b20_send_byte(READSCRATCH);
for(uint8_t i=0; i < fields; i++)
{
scratchPad[i] = OneWire_read();
}
ds18b20_reset();
}
/**@brief Function for request temperature reading
*/
void ds18b20_requestTemperatures(void)
{
ds18b20_reset();
ds18b20_send_byte(0xCC);
ds18b20_send_byte(STARTCONVO);
}
/**@brief Function for reading temperature method 2
*/
float ds18b20_get_temp_method_2(void)
{
ds18b20_requestTemperatures();
ScratchPad scratchPad;
ds18b20_readScratchPad(scratchPad, 2);
int16_t rawTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB];
float temp = 0.0625 * rawTemperature;
return temp;
}
/**@brief Function for setting temperature resolution
*/
void ds18b20_setResolution(uint8_t resolution)
{
ds18b20_reset();
ds18b20_send_byte(0xCC);
ds18b20_send_byte(WRITESCRATCH);
// two dummy values for LOW & HIGH ALARM
ds18b20_send_byte(0);
ds18b20_send_byte(100);
switch (resolution)
{
case 12:
ds18b20_send_byte(TEMP_12_BIT);
break;
case 11:
ds18b20_send_byte(TEMP_11_BIT);
break;
case 10:
ds18b20_send_byte(TEMP_10_BIT);
break;
case 9:
default:
ds18b20_send_byte(TEMP_9_BIT);
break;
}
ds18b20_reset();
}
I have rewritten this code in a file named sensor.c and changed the delay and the pin control functions.
#include <kernel.h>
#include <devicetree.h>
#include <device.h>
#include <drivers/gpio.h>
#include "ds18b20.h"
#define DQ 10
const struct device * gpio_dev;
//////////////////////////////////////////////////////////////////////////////
// OW_RESET - performs a reset on the one-wire bus and
// returns the presence detect. Reset is 480us. Presence checked
// another 70us later.
//
unsigned char ow_reset(void)
{
unsigned char presence;
gpio_dev = device_get_binding("GPIO_0");
gpio_pin_configure(gpio_dev, DQ, GPIO_OUTPUT_INACTIVE); //pull DQ line low
k_sleep(K_USEC(480)); // leave it low for 480us
gpio_pin_set(gpio_dev, DQ, 1); // allow line to return high
k_sleep(K_USEC(70)); // wait for presence
gpio_pin_configure(gpio_dev, DQ, GPIO_INPUT);
if(gpio_pin_get(gpio_dev, DQ)) // get presence signal
presence = 1;
else
presence = 0;
k_sleep(K_USEC(410)); // wait for end of timeslot
return(presence); // presence signal returned
} // 0=presence, 1 = no part
//////////////////////////////////////////////////////////////////////////////
// READ_BIT - reads a bit from the one-wire bus. The delay
// required for a read is 15us, so the DELAY routine won't work.
// We put our own delay function in this routine in the form of a
// for() loop.
//
unsigned char read_bit(void)
{
unsigned char presence;
gpio_dev = device_get_binding("GPIO_0");
gpio_pin_configure(gpio_dev, DQ, GPIO_OUTPUT_INACTIVE); // pull DQ low to start timeslot
k_sleep(K_USEC(2));
gpio_pin_configure(gpio_dev, DQ, GPIO_INPUT); // then return high
k_sleep(K_USEC(15)); // delay 15us from start of timeslot
if(gpio_pin_get(gpio_dev, DQ)) // get presence signal
presence = 1;
else
presence = 0;
return(presence); // return value of DQ line
}
//////////////////////////////////////////////////////////////////////////////
// WRITE_BIT - writes a bit to the one-wire bus, passed in bitval.
//
void write_bit(char bitval)
{
gpio_dev = device_get_binding("GPIO_0");
gpio_pin_configure(gpio_dev, DQ, GPIO_OUTPUT_INACTIVE); // pull DQ low to start timeslot
k_sleep(K_USEC(5));
if(bitval==1) gpio_pin_set(gpio_dev, DQ, 1); // return DQ high if write 1
k_sleep(K_USEC(115)); // hold value for remainder of timeslot
gpio_pin_set(gpio_dev, DQ, 1);
}
//////////////////////////////////////////////////////////////////////////////
// READ_BYTE - reads a byte from the one-wire bus.
//
unsigned char read_byte(void)
{
unsigned char i;
unsigned char value = 0;
for (i=0;i<8;i++)
{
if(read_bit()) value|=0x01<<i; // reads byte in, one byte at a time and then shifts it left
k_sleep(K_USEC(103)); // wait for rest of timeslot
}
return(value);
}
//////////////////////////////////////////////////////////////////////////////
// WRITE_BYTE - writes a byte to the one-wire bus.
//
void write_byte(char val)
{
unsigned char i;
unsigned char temp;
for (i=0; i<8; i++) // writes byte, one bit at a time
{
temp = val>>i; // shifts val right 'i' spaces
temp &= 0x01; // copy that bit to temp
write_bit(temp); // write bit in temp into
}
k_sleep(K_USEC(104));
}
int read_temperature(void)
{
char get[10];
char temp_lsb,temp_msb;
int k;
int temp_c;
ow_reset();
write_byte(0xCC); //Skip ROM
write_byte(0x44); // Start Conversion
k_sleep(K_USEC(600));
ow_reset();
write_byte(0xCC); // Skip ROM
write_byte(0xBE); // Read Scratch Pad
for (k=0;k<9;k++){get[k]=read_byte();}
// printk("\n ScratchPAD DATA = %X%X%X%X%X\n",get[8],get[7],get[6],get[5],get[4],get[3],get[2],get[1],get[0]);
temp_msb = get[1]; // Sign byte + lsbit
temp_lsb = get[0]; // Temp data plus lsb
if (temp_msb <= 0x80){temp_lsb = (temp_lsb/2);} // shift to get whole degree
temp_msb = temp_msb & 0x80; // mask all but the sign bit
if (temp_msb >= 0x80) {temp_lsb = (~temp_lsb)+1;} // twos complement
if (temp_msb >= 0x80) {temp_lsb = (temp_lsb/2);}// shift to get whole degree
if (temp_msb >= 0x80) {temp_lsb = ((-1)*temp_lsb);} // add sign bit
temp_c = (int)temp_lsb;
printk( "TempC= %d degrees C\n", temp_c ); // print temp. C
return temp_c;
}
Here is my main.c :
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include "ds18b20.h"
#include "sensor.h"
void main(void)
{
float fTemp1, fTemp2;
int iTemp;
ds18b20_setResolution(12);
fTemp1 = ds18b20_get_temp(); // Method 1 (from sd18b20.c)
k_sleep(K_SECONDS(1));
fTemp2 = ds18b20_get_temp_method_2(); // Method 2 (from sd18b20.c)
k_sleep(K_SECONDS(1));
iTemp = read_temperature(); // Metohd 3 (from sensor.c)
k_sleep(K_SECONDS(1));
printk("Hello World! %s\nTemperature is :\n%d from method 1\n%d from method 2\n%d from method 3\n\n", CONFIG_BOARD, (int)fTemp1, (int)fTemp2, iTemp);
while (1)
{
k_sleep(K_SECONDS(60));
fTemp1 = ds18b20_get_temp();
fTemp2 = ds18b20_get_temp();
iTemp = read_temperature();
printk("The temperature is now : \n%d from method 1\n%d from method 2\n%d from method 3\n\n", (int)fTemp1, (int)fTemp2, iTemp);
}
}
Also, pics of my connections :


The problem is the same for the three methods.
What I observe is that, during the reading part, it only reads high state values (=0xFF).
I thought the problem was from the time slots of my functions. But I tried dfiferent configurations and none of them worked.
I also tried with different flags for the pin configuration (in sensor.c) : GPIO_OUTPUT, GPIO_OUTPUT_INIT_LOW, GPIO_OUTPUT_INACTIVE. With no effects.
I am strating thinking the issue comes from the hard but I can't see what I am doing wrong.
For now, I'm still thinking the problem comes from one of thoses :
- The hard (my connections aren't correct)
- The pin configuration (but ds18b20.c should work as I didn't touch the pin configuration in this one).
- Maybe the k_sleep function but I woudn't understand why.
Do anyone have an idea ?
Thanks in advance for you help !
Regards,
Sulian
