logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

DS18B20 – błędny odczyt temperatury (-0.1°C), analiza kodu AVR, co sprawdzić?

shady79 09 Gru 2013 13:01 3018 15
REKLAMA
  • #1 13041768
    shady79
    Poziom 13  
    Posty: 221
    Ocena: 1
    Witam,

    Zgodnie z lekturą http://www./ja/elektronika/ds18b20.pdf
    próbuję odczytać temperaturę. Przepisałem wszystko tak jak jest w dokumencie, sprawdziłem kilka razy - wydaje mi się że błędu nie popełniłem. Mimo to odczyt temp. nie działa. Otrzymuję wynik -0.1

    Oto kod:

    
    /*
     * ds18s20.h
     *
     */
    #include <avr/io.h>
    #include <stdlib.h>
    #include <util/delay.h>
    // makra
    #define WE 0
    #define PORT_1wire PINB
    #define SET_1wire DDRB&=~_BV(WE)
    #define CLEAR_1wire DDRB|=_BV(WE)
    
    char buf[8]; // zmienna potrzebna przy konwersji temp.
    
    // resetujemy magistralę -  czekamy na impuls PRESENCE
    unsigned char RESET_PULSE(void)
    {
    	unsigned char PRESENCE;
    	CLEAR_1wire; // ustawiamy magistralę w stan niski
    	_delay_us(480);
    	SET_1wire;
    	_delay_us(30);
    
    	// sprawdzamy poziom lini ( czy w stanie niskim )
    	if (bit_is_clear(PORT_1wire, WE)) {
    		PRESENCE=1;
    	}else{
    		PRESENCE=0;
    	}
    	 _delay_us(480); //czekanie przez mastera
    
    	if (bit_is_set(PORT_1wire, WE))
    	{
    		PRESENCE=1;
    	}else{
    		PRESENCE=0;
    	}
    	return PRESENCE;
    }
    
    
    
    // wysyła do ukaładu pojedynczy bit.
    void send(char bit) {
    	CLEAR_1wire; // ustawienie magistrali w stan niski
    	_delay_us(10);
    		if (bit)
    		{
    			SET_1wire; // zwolnienie magistrali - wysłanie jedynki
    			_delay_us(100); // przetrzymanie
    			SET_1wire; // wyslanie zera
    		}
    }
    
    
    // zaczytuje bit z magistrali
    unsigned char read(void)
    {
    	unsigned char PRESENCE=0;
    
    	CLEAR_1wire; //ustawienie w stan niski
    	_delay_us(2); // oczekiwanie 2us
    	SET_1wire; // zwolnienie magistrali
    	_delay_us(12);
    	//odbiór jedynki lub zera
    	if (bit_is_set(PORT_1wire,WE)) {
    		PRESENCE=1;
    	}else{
    		PRESENCE=0;
    	}
    	return (PRESENCE);
    }
    
    // wysyła cały bajt do układu
    void send_byte(char wartosc)
    {
    	unsigned char i;
    	unsigned char pom;
    
    	for (i=0;i<8;i++)
    	{
    		pom = wartosc>>i;
    		pom &=0x01; // skopiowanie bitu do zmiennej pomocniczej
    		send(pom); // wysłanie bitu na magistrale
    	}
    	_delay_us(100); // odczekanie 100us
    }
    
    // zaczytuje cały bajt z układu.
    unsigned char read_byte(void)
    {
    	unsigned char i;
    	unsigned char wartosc = 0;
    
    	for (i=0;i<8;i++)
    	{
    		if (read()) wartosc|=0x01<<i; // zaczytuje po jednym bicie
    		_delay_us(15);
    	}
    	return(wartosc); //zwrot wartosci do funcji
    }
    
    


    main.c

    
    #include <avr/io.h>
    #include <stdlib.h>
    #include <util/delay.h>
    #include "HD44780.h"
    #include "ds18s20.h"
    
        int main(void)
        {
    
        	unsigned char sprawdz;
        	char temp1=0, temp2=0;
        	float celcius;
    
    		LCD_Initalize();
    	    LCD_Clear();
    	    LCD_WriteText("1-wire");
    	    _delay_ms(2000);
    	    LCD_Clear();
    
    	while(1) {
    		sprawdz = RESET_PULSE();
    		if (sprawdz==1){
    			send_byte(0xCC); // SKIP ROM
    			send_byte(0x44); // CONVERT_T
    			_delay_ms(750); // czas konwersji
    
    			sprawdz = RESET_PULSE(); // wysłanie impulsu reset
    			send_byte(0xCC); // SKIP ROM
    			send_byte(0xBE); // READ SCRATCHPAD
    
    			temp1=read_byte(); // LSB
    			temp2=read_byte(); // MSB
    
    			sprawdz = RESET_PULSE(); // zwolnienie magistrali
    			float temp=0; // zmienna do obliczen
    			temp = (float) (temp1+(temp2*256))/16; // obl. temp
    			dtostrf(temp,1,1,buf); // konwersja float do stringa
    
    			LCD_GoTo(0,0);
    			LCD_WriteText(buf);
    			_delay_ms(200);
    
    	}else{
    			LCD_GoTo(0,0);
    			LCD_WriteText("cisza");
    
    	}
    
    
    }
    	return 0;
        }
    
    


    Ściągnąłem jakąś inną bibliotekę obsługującą ten czujnik i działa.. ale ciekaw jestem dlaczego w tym przypadku nie działa prawidłowo.
  • REKLAMA
  • #2 13041816
    androot
    VIP Zasłużony dla elektroda
    Posty: 1801
    Pomógł: 54
    Ocena: 635
    A do tych delay ustawiłeś gdzieś jaka jest f CPU?
  • #4 13041910
    androot
    VIP Zasłużony dla elektroda
    Posty: 1801
    Pomógł: 54
    Ocena: 635
    Czytałeś w ogóle PDF do tego układu?

    Kiedy czytasz scratch pad to powinieneś wyłuskać z niego odpowiedniej bajty. W kodzie tego nie widzę.
  • REKLAMA
  • #5 13041931
    shady79
    Poziom 13  
    Posty: 221
    Ocena: 1
    send_byte(0xBE); // READ SCRATCHPAD

    temp1=read_byte(); // LSB
    temp2=read_byte(); // MSB


    przecież są czytane, tak samo mam w tej wersji w której odczyt działa:

            	ow_reset();
            	ow_write_byte(0xCC);
            	ow_write_byte(0x44);
            	for (uint8_t a = 0; a < 25; a++)
                	_delay_ms(30); // (30) =750ms (40) =1000ms
           		ow_reset();
            	ow_write_byte(0xCC);
            	
            	ow_write_byte(0xBE);
        		lsb = ow_read_byte();
           		msb = ow_read_byte();
            	celcius =  msb << 8 | lsb ;
            	celcius/=16;
            	temp = msb << 4| lsb >> 4;
    
            	LCD_Clear();
            	LCD_GoTo(0,0);
            	LCD_WriteText("Temp: ");
            	LCD_WriteText(dtostrf(celcius, 2, 1 , tab));
    


    Dodano po 24 [minuty]:

    problemem jest to że zmienne temp1 oraz temp2 cały czas mają wartość 255
  • #6 13042010
    androot
    VIP Zasłużony dla elektroda
    Posty: 1801
    Pomógł: 54
    Ocena: 635
    OK, mój błąd. To są 2 pierwsze bajty. Pomyliłem z rejestrami Th i Tl. Powinieneś czytać też CRC i sprawdzać czy są odczytane poprawne dane.
  • REKLAMA
  • #7 13042015
    excray
    Poziom 41  
    Posty: 5502
    Pomógł: 739
    Ocena: 657
    Procedura RESET_PULSE() jest bez sensu. Czasy byle jak dobrane. Po co wyłaczyłeś jako oddzielne funkcje read() i send()? Procedura send() jest na dodatek skopana. Jak bit=0 to nigdy nie zostanie podniesiona magistrala.
  • #8 13042028
    shady79
    Poziom 13  
    Posty: 221
    Ocena: 1
    zmieniłem funkcję reset na

    void RESET_PULSE(void)
    {
    CLEAR_1wire; // ustawiamy magistralę w stan niski
    _delay_us(480);
    SET_1wire;
    _delay_us(480);
    }

    nadal lipa

    Dodano po 2 [minuty]:

    zastanawiam się nad

    unsigned char read(void)
    {
    unsigned char PRESENCE=0;

    CLEAR_1wire; //ustawienie w stan niski
    _delay_us(2); // oczekiwanie 2us
    SET_1wire; // zwolnienie magistrali
    _delay_us(12);

    //odbiór jedynki lub zera
    if (bit_is_set(PORT_1wire,WE)) {
    PRESENCE=1;
    }else{
    PRESENCE=0;
    }
    return (PRESENCE);
    }

    a dokładniej czy to: if (bit_is_set(PORT_1wire,WE)) działa poprawnie.
  • #9 13042037
    excray
    Poziom 41  
    Posty: 5502
    Pomógł: 739
    Ocena: 657
    Przeczytaj to co napisałem o procedurze send(). Popraw umiejscowienie ostatniego SET_1wire - poza warunek i usuń pierwszy SET_1wire a warunek zmień na if(!bit)...
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • #10 13042075
    shady79
    Poziom 13  
    Posty: 221
    Ocena: 1
    niestety cały czas to samo... -0.1

    Dodano po 3 [minuty]:

    zmieniłem trochę jeszcze funkcje read

    unsigned char read(void)
    {
    CLEAR_1wire;
    _delay_us(2);
    SET_1wire;
    _delay_us(12);
    if (bit_is_set(PORT_1wire,WE)) return 1; else return 0;
    }

    ale nie jestem pewien czy bit_is_set działa poprawnie.
  • #11 13042097
    excray
    Poziom 41  
    Posty: 5502
    Pomógł: 739
    Ocena: 657
    Załącz cały kod po poprawkach.
  • #13 13042194
    excray
    Poziom 41  
    Posty: 5502
    Pomógł: 739
    Ocena: 657
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #14 13042469
    shady79
    Poziom 13  
    Posty: 221
    Ocena: 1
    No dobra, teraz działa. W związku z tym, że mam odczyt z jednego czujnika, chciałbym tak zmodyfikować kod aby odpytywać np. dwa. Teoretycznie wiem, że można sobie pobrać numery identyfikacyjne czujników, na sztywno przypisać je do jakiś zmiennych a następnie po kolei zczytywać temp. z konkretnych czujników. W teorii wydaje się proste ale jak to teraz zrealizować w praktyce?? Myślałem aby podłączyć pierwszy czujnik, następnie zczytać numer identyfikacyjny, wyświetlić go sobie na wyświetlaczu, następnie użyć go adresując w programie czujnik(i). Może jest gdzieś to dobrze opiane??

    Według noty katalogowej wynika, że gdy wyślemy polecenie READ ROM [33h] to układ odpowie 64 bitowym numerem. Więc napisałem coś takiego - niestety padł mi programator i nie mogę dziś tego sprawdzić.. Według mojego zamysłu powinno na wyświetlaczu pokazać się 8 kolejnych bajtów odczytanego numeru z czujnika..

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #15 13049143
    Smashing
    Poziom 20  
    Posty: 513
    Pomógł: 18
    Ocena: 12
    Witam
    sprawa nie jest taka prosta funkcja wygląda tak,
    ale musisz sam sobie zrobić funkcje ow_read_bit i ow_write_bit
    bo ja używam do odczytu RS232 i moje funkcje ci nie pomogą ale zobacz jak działa samo ow_search_addresses :
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    ow_search_addresses wywołujesz na początku i zwraca ci ile jest urządzeń (tu max 20)
    w onew_dev_list masz adresy
    Jak chesz odczytać temperaturę to dajesz:
    -OneWire_Reset
    -OneWire_skipRom_ConvertT
    To w pętli zależnej ile masz urządzeń
    -OneWire_Reset
    -OneWire_match_rom
    - OneWire_send_adress (ten co odczytałeś)
    -OneWire_read_scratch
    - OneWire_read_temperature

    Ja do odczytu używam RS232 +DMA

    Pozdrawiam

Podsumowanie tematu

LABEL_AI_GENERATED
Użytkownik próbował odczytać temperaturę z czujnika DS18B20, jednak napotkał problem, ponieważ wynikiem był -0.1°C. Po kilku interakcjach z innymi uczestnikami forum, zidentyfikowano kilka potencjalnych problemów, takich jak brak definicji częstotliwości CPU oraz błędy w procedurach resetowania magistrali i odczytu bitów. Użytkownik poprawił kod, w tym funkcje RESET_PULSE, send i read, co ostatecznie doprowadziło do poprawnego działania odczytu temperatury. Następnie użytkownik zadał pytanie o możliwość odczytu temperatury z dwóch czujników, co wymagało zaimplementowania funkcji do odczytu numerów identyfikacyjnych czujników.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA