1

I am implementing my own SW for getting data from DS18B20, but I've been stuck on decoding address for a while - "receiving" only zeros as a result. Here is my code:

#include <avr/io.h>
#include "DS18B20_driver.h"
#include <util/delay.h>
#include "debug_uart.h" //delete
#include <stdio.h>     //delete

//High_level_funcitons
void dallas_get_address(uint8_t* address){
    reset_pulse();
    _delay_ms(2);
    write_byte(0x33); //READ ROM command;
    read_rom(address);

    uart_send_string("Dallas address is:  \n");
    
    for(int j = 0; j < 8; j++){
        char buffer[3];
        sprintf(buffer, "%02X", address[j]);
        uart_send_string(buffer);                   
    }
    uart_send_string(" \n");            
}

//Mid_high_level_functions
void read_rom(uint8_t* address){
    for(int j = 0; j < 8; j++){
        address[j] = read_byte();
    } 
}

//Mid_low_level_functions
void write_byte(uint8_t byte_value){
    for(int j = 0; j < 8; j++){
        _delay_us(1);               //1 us between write cycles 
        if(byte_value & 0x01){       //if bit is high in first position
            write_bit_high();           
        }
        
        else{
            write_bit_low();
        }
        byte_value >>= 1;             //shifting byte by one position
    }
}

uint8_t read_byte(){
    uint8_t received_byte = 0;      //Clearing variables
    uint8_t received_bit = 0;
    for(int j = 0; j < 8; j++){
        received_bit = read_bit();
        received_byte |= (received_bit << j);
    }
    return received_byte;
}

//Low_level_functions
void write_bit_high(){
    DDRX |= (1 << PXX);
    PORTX &= ~(1 << PXX);
    _delay_us(10);
    PORTX |= (1 << PXX);
    _delay_us(55); // 45us + 3us recovery, then it stays in 5V state
    DDRX &= ~(1 << PXX);
}

void write_bit_low(){
    DDRX |= (1 << PXX);
    PORTX &= ~(1 << PXX);
    _delay_us(65);
    PORTX |= (1 << PXX);
    _delay_us(5); //3us recovery, then it stays in 5V state
    DDRX &= ~(1 << PXX);
}

uint8_t read_bit(){
    DDRX |= (1 << PXX);
    PORTX &= ~(1 << PXX);
    _delay_us(3);
    DDRX &= ~(1 << PXX);
    //PORTX &= ~(1 << PXX); 
    //PORTX |= (1 << PXX);
    _delay_us(10);          //15us recovery
    if(PINX & (1 << PXX)){
        _delay_us(53);      //rest of transmission interval
        return 1;           //returns 0b00000001
    }
    else{
        _delay_us(53);
        return 0;           //returns 0b00000000
    }
}

int reset_pulse(){
    DDRX |= (1 << PXX);
    PORTX &= ~(1 << PXX); //Master transmitts reset pulse, by pulling low
    _delay_us(480);     //480-720us
    PORTX |= (1 << PXX);

    DDRX &= ~(1 << PXX);
    _delay_us(70);              
    if(!(PINX & (1 << PXX))){  
        uart_send_string("Response was successfull!\n");    
        return 1;
    }
    else{
        _delay_us(100);         
        if(!(PINX & (1 << PXX))){
            uart_send_string("Response was successfull!\n");    
            return 1;
        }
        else{
            uart_send_string("Sensor/s is/are not responding!\n");    
            return 0;
        }
    }
}

What've done:

different pulses timing different Dallas sensors disconnecting/connecting sensor - reset pulse/presence pulse works fine.

Output I get:

Response was successfull! Dallas address is:
0000000000000000

when Dallas is connected

Sensor/s is/are not responding! Dallas address is:
0000000000000000

when Dallas is disconnected

Mybe I'm doing some dumb mistake I can't see because I am fairly new selftougth embedded developer.

Thank you in advance for your replies and advices.

14
  • 1
    You should get rid of all busy-delays since those will sooner or later screw up timing or CPU load for you. Commented Sep 18 at 12:30
  • 4
    @David, post how dallas_get_address() is called, a minimal reproducible example. Commented Sep 18 at 12:35
  • 3
    Did you check with oscilloscope or logic analizer whether your output meets requirements for 1-Wire timings? Is uart_send_string() blocking or non-blocking? Even if it is non-blocking, copying data to buffer introduces delays. If your firmware uses interrupts, they also may introduce delays. Commented Sep 18 at 14:03
  • All the uart output in dallas_get_address would from a design point of view be better performed by the caller of dallas_get_address, which should return a status. Similarly for reset_pulse, use the return status to test, and exit from dallas_get_address with a failure status. Wit respect to your problem, are you certain this code is producing accurate timing? Without knowing what processor this is running on, and at what speed, and how the delay functions are implemented, it is not possible to tell from the code. I would not attempt my own 1-Wire code without a scope to verify it. Commented Sep 19 at 6:55
  • 1
    @chux Here is part how dallas_get_addres is called: c uint8_t address_1[8]; dallas_get_address(address_1); _delay_ms(1000); Commented Sep 23 at 12:37

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.