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