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 po raz n-ty. Odczyt temperatury. Działa tylko do 23,9 stopni.

Fantomen 25 Mar 2007 14:24 2841 14
REKLAMA
  • #1 3717463
    Fantomen
    Poziom 20  
    Posty: 482
    Pomógł: 3
    Ocena: 19
    Wiem ze bylo juz mase postow na forum o ds18b20, przeczytalem chyba wszystkie i nawet zarzekalem sie ze nie napisze kolejnego, ale po kilku dniach walki rece mi opadaja. Chce zczytac temp. atmega8 z tego ukladu. Zczytuje ladnie ale tylko do 23,9 stopni jezeli bardziej ogrzeje czujnik wyswietlacz wskazuje mi temperature -7, -6 cos kolo tego. Oto moj kod, prosze pomozcie:cry:


    #include <avr/io.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <util/delay.h>
    #include "D:\AVR\Project Proteus\header\lcd.h"
    #include "D:\AVR\Project Proteus\header\twi.h"
    #include "D:\AVR\Project Proteus\header\rs232.h"
    
    
    unsigned long long int tmp2, p ;
    //int cos;
    unsigned int pomiar1, tmp, tmp1, o, cisn, srednia, srednia1,srednia2;
    char bufor1[5],bufor2[5],bufor3[50], bufor4[5], cos, lcd_buf[50];
    
    unsigned char temperature;
    unsigned char temperatura=1;
    short int x; 
    #define F_CPU       1000000UL            
    #define CYCLES_PER_US ((F_CPU+500000)/1000000) // cpu cykli na mikrosekunde
    
    
    void LCD_xy(uint8_t x, uint8_t y)
    {
       switch(y)
       {
          case 1: y=0x40; break;
          case 2: y=0x14; break;
       }
       write_command(0x80+y+x);
    }
    
    
    
    unsigned char ow_reset__(void) // reset lini one wire
    {
       unsigned char presence=1;
       DDRC |= _BV(0); //DQ = 0; //pull DQ line
       _delay_us(480);
       DDRC &= ~_BV(0); //DQ = 1; // allow line to //powrót lini 1w do trybu wejścia
    
       _delay_us(70);// wait for presence pulse(pochodzący od DS-a) //czekamy na ustab. lini
       
       if(bit_is_clear(PINC,0)) presence=0; //odczytujemy co wystawił na linię DS
       _delay_us(410);// wait for end
     if(bit_is_clear(PINC,0)) presence=1; //odczytujemy co wystawił na linię DS
       return(presence); // presence signal
    } // 0=presence, 1 = no part
    
    
    unsigned char test(void) // test na oecnosc DALLASA
    {
    
    if (ow_reset__()==1)
    {
    write_text("BRAK CZUJNIKA");
    _delay_ms(200);
    _delay_ms(200);
       while(1)
       {
       asm ("NOP");
       } 
    }
    _delay_ms(200);
    _delay_ms(200);
    }
    
    
    unsigned char read_bit(void)
    {
       unsigned char presence=0;
       DDRC |= _BV(0);    //DQ = 0; // pull DQ low to start timeslot
       _delay_us(6);
       DDRC &= ~_BV(0);   //DQ = 1; // then return high
       _delay_us(9); // delay 15us from start of timeslot
       if(bit_is_clear(PINC,0)) presence=0;
       if(bit_is_set(PINC,0)) presence=1;
       _delay_us(55);
       return(presence); // return value of DQ line
    }
    ///---------------------------------------------------------
    
    void write_bit(char bitval) //WRITE_BIT - writes a bit to the one-wire bus, passed in bitval.
    {
       DDRC |= _BV(0); //DQ = 0; // pull DQ low to start timeslot
       _delay_us(6);
       if(bitval==1) DDRC &= ~_BV(0); //DQ =1; // return DQ high if write 1
       _delay_us(64); // hold value for remainder of timeslot - delay 104us
       DDRC &= ~_BV(0);//DQ = 1;
    }
    
    ///---------------------------------------------------------
    
    unsigned char read_byte(void) // READ_BYTE - reads a byte from the one-wire bus
    {
       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
          _delay_us(80); // ??shifts it left wait for rest of timeslot 120us
       }
       return(value);
    }
    
    ///---------------------------------------------------------
    
    void write_byte(char val) // WRITE_BYTE - writes a byte to the one-wire bus.
    {
       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
       }
       _delay_us(80);
    
    }
    
    void Read_Temperature(void)
    {
    char tmp[10];
    char temp1, temp2;
    unsigned short int t;
    if (ow_reset__()==1)
    test();
    write_byte(0xCC); //Skip ROM
    write_byte(0x44); // Start Conversion
     _delay_ms(950);
    
    ow_reset__();
    write_byte(0xCC); // Skip ROM
    write_byte(0xBE); // Read Scratch Pad
    
    
    
    temp1=read_byte();
    temp2=read_byte();
    
    ow_reset__();
    
    
    
    
    dtostrf((float)((temp2<<8)|temp1)*10/16/10,5,1,tmp); 
    
    LCD_xy(1,0);
    write_text(tmp);
    } 
    
    
    
    int main(void)
    {
    DDRB=0xFF;
    PORTB =0xFF;
      
    write_command(0x01); 
       DDRC=0x00;
       PORTC=0x00;
    
    
    write_byte(0xCC);
    lcd_init();
    USART_Init();
    
        while(1)
        {
    
    
    Read_Temperature();
    	
    waitms(40);
    
    write_command(0x01); 
        }	
    return (0);
    }
    
  • REKLAMA
  • #2 3717799
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Po raz N-ty powtarzam :(
    W dokumentacji jest takie zdanie:
    Figure 15 illustrates that the sum of Tinit, Trc , and Tsample must be less than 15 µs for a read time slot.
    A u Ciebie co , czy naprawdę "less" :?: Zakładam , że delay_us() dokładnie "odmierza" zadany czas.
    
    //...
    unsigned char read_bit(void)
    {
       unsigned char presence=0;
       DDRC |= _BV(0);    //DQ = 0; // pull DQ low to start timeslot
       _delay_us(6);
       DDRC &= ~_BV(0);   //DQ = 1; // then return high
       _delay_us(9); // delay 15us from start of timeslot
       if(bit_is_clear(PINC,0)) presence=0;
       if(bit_is_set(PINC,0)) presence=1;
       _delay_us(55);
       return(presence); // return value of DQ line
    }
    ///---------------------------------------------------------
    

    Przemyśl to ponownie :D

    Piotrek
  • #3 3718128
    Fantomen
    Poziom 20  
    Posty: 482
    Pomógł: 3
    Ocena: 19
    Wiedziałem, że ty odpowiesz :D
    Zmieniłem to ale dalej to samo sie dzieje
    unsigned char read_bit(void)
    {
       unsigned char presence=0;
       DDRC |= _BV(0);    //DQ = 0; // pull DQ low to start timeslot
       _delay_us(1);
       DDRC &= ~_BV(0);   //DQ = 1; // then return high
       _delay_us(11); // delay 15us from start of timeslot
       if(bit_is_clear(PINC,0)) presence=0;
       if(bit_is_set(PINC,0)) presence=1;
       _delay_us(55);
       return(presence); // return value of DQ line
    }


    Co do dokladnosci funkcji delay, to standardowa:
    _delay_us(double __us)
    {
    	uint8_t __ticks;
    	double __tmp = ((F_CPU) / 3e6) * __us;
    	if (__tmp < 1.0)
    		__ticks = 1;
    	else if (__tmp > 255)
    		__ticks = 0;	/* i.e. 256 */
    	else
    		__ticks = (uint8_t)__tmp;
    	_delay_loop_1(__ticks);
    }
    


    zadeklarowany wewnetrzny 1MHz wiec powinno byc ok, nie jest.
  • REKLAMA
  • #4 3718190
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Nie pytaj dlaczego , tylko podnieś F_CPU do >1 MHz(w procu oczywiście też) (np. 4MHz) i sprawdź ponownie.Przy 1 MHz ja też miałem kłopoty , ale juz od 2 do 16 wszystko działało :D Dobrym sposobem jest też , kilkakrotne próbkowanie magistrali 1wire - teraz tak zawsze robię ;).

    Piotrek
  • #5 3718254
    Fantomen
    Poziom 20  
    Posty: 482
    Pomógł: 3
    Ocena: 19
    A czy istnieje jakakolwiek mozliwosc odpalenia tego na 1MHz? Zalezy mi zeby procek wlasnie tak byl taktowany.
  • #6 3718285
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Fantomen napisał:
    A czy istnieje jakakolwiek mozliwosc odpalenia tego na 1MHz? Zalezy mi zeby procesor wlasnie tak byl taktowany.

    Hmmm... napisałbym to(zapis/odczyt bitu) raczej w assemblerze.

    Piotrek
  • #7 3718779
    Fantomen
    Poziom 20  
    Posty: 482
    Pomógł: 3
    Ocena: 19
    Z dwojga zlego wole zegar 4MHz... Zmienilem wewnetrzny oscylator na 4MHz i zmienielem w deklaracji:
    #define F_CPU       4000000UL           
    #define CYCLES_PER_US ((F_CPU+500000)/1000000) // cpu cykli na mikrosekunde 


    ...teraz w ogole nie wykrywa mi czujnika. Zumek ratuj, Ty umiesz nawet z fusów wróżyc. :D O czym zapomnialem?

    ------------------------------------------------------------------------------------
    Dobra zmienilem na 2MHz i wykrywa czujnik ale dalej to samo co przedtem tzn. przy wzroscie temp. powyzej 23,9 stopnia jakby sie resetowal i pokazuje -7,-6....itd. Moze to cos z konwersja w funkcji ReadTemperature?
  • #8 3718869
    johny_w
    Poziom 24  
    Posty: 671
    Pomógł: 80
    Ocena: 63
    Albo odmierzanie czasu na timerze.

    Bądź też sprawdzenie w debugerze ile czasu na prawdę zajmuje funkcja delay i eksperymentalne dobranie wartości. Jeśli przy wyższych częstotliwościach funkcja ta prawie spełnia swoje zadanie to przy 1Mhz czas jej wykonania zwiększa się znacząco od podanej wartości. Również bardzo duży wpływ na jej działanie ma wybrany stopień optymalizacji.

    pozdrawiam, JnS
  • REKLAMA
  • #9 3719043
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Powiem tak - firmowy delay.h mocno mi nie pasuje.Dołączam delay.h w wersji , której używam i działa z 1wire na każdej F_CPU z wjątkiem 1MHz ,ale nie chciało mi się dociekać(narazie) dlaczego.Firmowy delay.h przy optymalizacji -oS daje:
    
    _delay_ms(1); //1 us                     - nowy 1.5 us
    _delay_ms(11); //10.5 us               - nowy 11us
    _delay_ms(480); // 192 us !!!!!!!!!   - nowy 480 us
    

    Narazie tyle .

    Piotrek
    Załączniki:
    • delay.txt (873 Bajtów) Musisz być zalogowany, aby pobrać ten załącznik.
  • REKLAMA
  • #10 3719826
    Fantomen
    Poziom 20  
    Posty: 482
    Pomógł: 3
    Ocena: 19
    Ehhh... uparta bestia. Powiem tak: dalej to samo, nawet na tej biblotece delay'a. Co prawda mialem optymalizacje o2 i na niej zachowuje sie jak mowilem powyzej. Zmienilem na oS i teraz caly czas wskazuje -0.1. Cos sie nieźle rozjeżdża. Może coś w czasach zamotałem. Jak sie sprawdza te czasy w symulatorze AVRStudio ?
  • #11 3721485
    Fantomen
    Poziom 20  
    Posty: 482
    Pomógł: 3
    Ocena: 19
    Zloliwosc rzeczy martwych, chcialem przetestowac te petle czasowe w avr_studio ale nie moge zmienic czestoliwosci procka w ustawieniach programu. Zmieniam w project>>configuration options na 2000 000Hz a dalej uparcie wyswietla mi 4MHz w panelu procesora. Trzeba jeszcze cos w tym programie zmienic czy to blad programu?
  • #12 3722036
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    Fantomen napisał:
    Zloliwosc rzeczy martwych, chcialem przetestowac te petle czasowe w avr_studio ale nie moge zmienic czestoliwosci procka w ustawieniach programu. Zmieniam w project>>configuration options na 2000 000Hz a dalej uparcie wyswietla mi 4MHz w panelu procesora. Trzeba jeszcze cos w tym programie zmienic czy to blad programu?

    To co Ty zmieniasz , to informacja dla kompilatora , a debbuger/symulator nic o tym nie wie ;) Po bezbłędnym skompilowaniu projektu z F_CPU = 2000000 , uruchom debbuger i jak załaduje dane , to wciśnij ALT+O i w opcja debbugera wybierz właściwą częstotliwość w - uwaga - MHz i sprawdź również czy uC też jest ustawiony na właściwy.
    To tyle.
    Piotrek
  • #13 3723575
    ptero
    Poziom 24  
    Posty: 621
    Pomógł: 68
    Ocena: 171
    A sprawdź jakie dane scz... zcz... tfu. odczytujesz z czujnika. Czy to błąd komunikacji czy konwersji. Ja zawsze tak sprawdzam przy problemach. Wyświetlam na LCD-ku obok siebie dane "surowe" i przekonwertowane. I przeważnie to pomaga.
  • #14 3724299
    Fantomen
    Poziom 20  
    Posty: 482
    Pomógł: 3
    Ocena: 19
    Sprawdzałem nawet wcześniej, ale to nie to. Zgłupiałem fuse bity ustawione:
    Fuse Low Byte      = 0xe2
    Fuse High Byte     = 0xd9
    Fuse Extended Byte = 0xff
    Calibration Byte   = 0xd5  --  Read Only
    Lock Bits          = 0xff
        BLB12 -> 1
        BLB11 -> 1
        BLB02 -> 1
        BLB01 -> 1
          LB2 -> 1
          LB1 -> 1

    W delayu zadeklarowane na 2 000 000. A wskazuje cały czas teraz -0.1. Sprawdzalem funkcje delaya od zumka, ale tak jak mowil jest ok. Przy konwersji -Os delay nawet ladnie chodzi. Braklo mi pomyslow.
  • #15 3858091
    astony
    Poziom 14  
    Posty: 272
    Pomógł: 4
    Ocena: 23
    wątek stary .. ale moze...
    ja czasy w resecie 1wire mam na ok.380 us.
    powyzej nie działa mimo ze w datasheet jest min.480us
    moze to że mam sample. temperatura tez mnie oszukuje o jakieś 2-3 stopnie
    powodzenia

Podsumowanie tematu

✨ Dyskusja dotyczy problemu z odczytem temperatury z czujnika DS18B20 podłączonego do mikrokontrolera Atmega8. Odczyt działa poprawnie do temperatury około 23,9°C, powyżej której wyświetlane są błędne wartości (np. -7, -6). Przyczyną problemu może być nieprawidłowe odmierzanie czasów w protokole 1-Wire, szczególnie w funkcji odczytu bitu, gdzie wymagany jest precyzyjny czas trwania sygnałów (mniej niż 15 µs na slot odczytu). Dyskutowano o wpływie częstotliwości taktowania mikrokontrolera (F_CPU) na poprawność działania – przy 1 MHz pojawiają się problemy, natomiast przy 2 MHz i wyżej odczyt jest stabilniejszy. Sugerowano także wielokrotne próbkowanie magistrali 1-Wire oraz ewentualne napisanie krytycznych fragmentów kodu w asemblerze dla lepszej precyzji czasowej. Problemy z funkcją delay i jej dokładnością pod różnymi ustawieniami optymalizacji kompilatora również zostały poruszone. Wskazano, że symulator AVR Studio wymaga osobnej konfiguracji częstotliwości taktowania mikrokontrolera niezależnie od ustawień kompilatora. Ostatecznie problem może leżeć w nieodpowiednim odmierzaniu czasów i konwersji danych z czujnika, a także w ustawieniach fuse bitów mikrokontrolera. Wątek podsumowano uwagą, że czas resetu magistrali 1-Wire poniżej 480 µs może powodować błędy, a dokładność pomiaru temperatury DS18B20 może być zaniżona o kilka stopni.
Wygenerowane przez model językowy.
REKLAMA