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

Kod w C dla DS18B20 i LCD na ATmega32 - odczyt temperatury -0.02

domelfm 14 Mar 2007 13:11 9296 37
Najlepsze odpowiedzi

Dlaczego mój program na ATmega32 z DS18B20 cały czas pokazuje -0,02°C i jak poprawnie odczytać temperaturę?

Najpierw upewnij się, że ATmega naprawdę pracuje z 8 MHz i że F_CPU oraz fusebity są z tym zgodne, bo w wątku wskazano przypadek, w którym kod miał ustawione 1000000UL zamiast 8000000UL i przez to czasy 1-Wire były rozjechane [#3681639] Procedury resetu, zapisu i odczytu bitów muszą mieć poprawne opóźnienia; jeśli zamieniasz _delay na własne dl, trzeba je ponownie skalibrować, bo błędne timingi dają złe dane z DS-a [#3682046][#3691414] Jeśli po resecie pojawia się 85.x°C, to zwykle znaczy, że czujnik nie zdążył wykonać konwersji albo sekwencja komend jest błędna: wyślij 0x44, odczekaj do 800 ms dla 12-bitowej rozdzielczości, potem dopiero wykonaj reset i odczyt scratchpada [#3705346][#3691414] Przy składaniu wyniku z bajtów użyj masek na przesuniętych wartościach, np. temp4=((temp2<<4)&0xF0), temp3=((temp1>>4)&0x0F), a potem t=temp4|temp3; dla temperatur ujemnych trzeba jeszcze osobno obsłużyć znak i typ zmiennej, bo w wątku zauważono problemy przy char [#4902504] W praktyce warto też sprawdzić samo podłączenie i stan czujnika, bo po wymianie uszkodzonego DS-a układ zaczął działać poprawnie [#3701259]
Podsumowanie wygenerowane przez AI na podstawie treści dyskusji.
REKLAMA
  • #1 3677296
    domelfm
    Poziom 16  
    Posty: 238
    Pomógł: 5
    Ocena: 28
    Witam urzytkowników...
    Programuje juz blisko 4 dni ten mikrokontroler i zero efektu.
    Odczyt zawsze -0.02....
    Dlatego mam prośbę czy ktoś byłby w stanie udostępnić swój działający program na atmege 32 który dobrze czyta temp z ds ?
    Jezeli znajdzie się taki chętny to odrazu zapytam się na jakiej czestotliwosci działa jego atmega ...
    Mam nadzieje że uda mi się to w końcu uruchomic..
  • REKLAMA
  • #2 3677396
    rsikon
    Poziom 26  
    Posty: 1075
    Pomógł: 24
    Ocena: 26
    Hi hi hi :)

    Kolega zaczyna jak i ja... też jakieś klika dni i ten sam problem :)

    https://www.elektroda.pl/rtvforum/topic713286.html

    Też jak narazie pomocy nie otrzmałem .

    Może napisz na gg do mnie 15179, jak bede mial chwile wolna to odpisze.

    Sai sobie poradzimy jak na nie chca pomoc ;) - mało prawdopodobne.

    Główny problem to odmierzanie mkro sekund . Tak mi się zdaje.

    Radzio
  • REKLAMA
  • #3 3677668
    domelfm
    Poziom 16  
    Posty: 238
    Pomógł: 5
    Ocena: 28
    dobrze Ci się zdaje ..
    Problemem jest czas !!!
    Einstein zaduzo kombinował i nam zakrzywił czasoprzestrzen to wszystko jego wina.... :)

    A tak naprawde to bede wdzięczny za dobre procedurki do i-wire oraz i2c wraz z dobrym odmierzaniem czasu... Co do i2c to najlepiej z wykrywaniem błędów magistrali.
    Niestety niemog obie poadzić pomimo iz znam mniejwiecej budowe avr i mniejwiecej wiem ile co teoretycznie powinno trwać ale po badaniu wychodzi ze trwa kilkakrotnie dłuzej...

    Pozdrawiam
  • REKLAMA
  • #4 3679136
    rsikon
    Poziom 26  
    Posty: 1075
    Pomógł: 24
    Ocena: 26
    operacja udana :P

    Lekko dopieszcze kod i moze si podziele ;)
  • #5 3681347
    domelfm
    Poziom 16  
    Posty: 238
    Pomógł: 5
    Ocena: 28
    * Program demonstrujacy dzialanie termometru DS1820; 
    This program measure a temperature from DS1820 and shows it at LCD. 
    Piny/Pins: 
    PD1 - RS 
    PD2 - E 
    PD3 - D4 
    PD4 - D5 
    PD5 - D6 
    PD6 - D7 
    */ 
    
      
    #include <avr/io.h> 
    #include <stdlib.h> 
    #include <util/delay.h> 
    
    #define _AVR_DELAY_H_ 1
    #define F_CPU 10000000UL
    
    #define DDR_DB4 DDRD 
    #define PORT_DB4 PORTD 
    #define DB4 PD3 
    
    #define DDR_DB5 DDRD 
    #define PORT_DB5 PORTD 
    #define DB5 PD4 
    
    #define DDR_DB6 DDRD 
    #define PORT_DB6 PORTD 
    #define DB6 PD5 
    
    #define DDR_DB7 DDRD 
    #define PORT_DB7 PORTD 
    #define DB7 PD6 
    
    
    #define DDR_RS DDRD 
    #define PORT_RS PORTD 
    #define RS PD1 
    
    #define DDR_E DDRD 
    #define PORT_E PORTD 
    #define E PD2 
    
    
    #define SET_B1 PORT_B1 |= _BV(B1) 
    #define CLR_B1 PORT_B1 &= ~_BV(B1) 
    
    #define SET_B2 PORT_B2 |= _BV(B2) 
    #define CLR_B2 PORT_B2 &= ~_BV(B2) 
    
    #define SET_B3 PORT_B3 |= _BV(B3) 
    #define CLR_B3 PORT_B3 &= ~_BV(B3) 
    
    #define SET_B4 PORT_B4 |= _BV(B4) 
    #define CLR_B4 PORT_B4 &= ~_BV(B4) 
    
    #define SET_DB4 PORT_DB4 |= _BV(DB4) 
    #define CLR_DB4 PORT_DB4 &= ~_BV(DB4) 
    
    #define SET_DB5 PORT_DB5 |= _BV(DB5) 
    #define CLR_DB5 PORT_DB5 &= ~_BV(DB5) 
    
    #define SET_DB6 PORT_DB6 |= _BV(DB6) 
    #define CLR_DB6 PORT_DB6 &= ~_BV(DB6) 
    
    #define SET_DB7 PORT_DB7 |= _BV(DB7) 
    #define CLR_DB7 PORT_DB7 &= ~_BV(DB7) 
    
    #define SET_E PORT_E |= _BV(E) 
    #define CLR_E PORT_E &= ~_BV(E) 
    
    #define SET_RS PORT_RS |= _BV(RS) 
    #define CLR_RS PORT_RS &= ~_BV(RS) 
    
    #define LCD_X 16 
    #define LCD_Y 2 
    
    unsigned char temperature; 
    unsigned char temperatura=1; 
    
    union { 
    int tds; 
    char nds[2]; 
    }ds; 
    
    char buf[6]; 
    
    void out_nibble(char x) 
    { 
       CLR_DB4; 
       CLR_DB5; 
       CLR_DB6; 
       CLR_DB7; 
       if(x & _BV(0)) SET_DB4; 
       if(x & _BV(1)) SET_DB5; 
       if(x & _BV(2)) SET_DB6; 
       if(x & _BV(3)) SET_DB7; 
    } 
    
    
    void write_to_lcd(char x) 
    { 
       SET_E; 
       out_nibble(x >> 4); 
       CLR_E; 
       SET_E; 
       out_nibble(x); 
       CLR_E; 
       _delay_ms(8); 
        
        
    } 
    
    void delay(int useconds) 
    { 
    int s; 
    useconds = useconds; 
    for (s=0; s<useconds;s++); 
    } 
    
    void write_command(char x) 
    { 
       CLR_RS; 
       write_to_lcd(x); 
    } 
    
    void write_char(char x) 
    { 
       SET_RS; 
       write_to_lcd(x); 
    } 
    
    void write_text(char * s) 
    { 
       while(*s) 
       { 
          write_char(*s); 
          s++; 
       } 
    } 
    
    void lcd_init(void) 
    { 
       DDR_DB4 |= _BV(DB4); 
       DDR_DB5 |= _BV(DB5); 
       DDR_DB6 |= _BV(DB6); 
       DDR_DB7 |= _BV(DB7); 
       DDR_E |= _BV(E); 
       DDR_RS |= _BV(RS); 
    
        
       _delay_ms(120); 
       CLR_E; 
       CLR_RS; 
       char i; 
       for(i = 0; i < 3; i++) 
       { 
          SET_E; 
          out_nibble(0x03); 
          CLR_E; 
       _delay_ms(5); 
    
       } 
       SET_E; 
       out_nibble(0x02); 
       CLR_E; 
       _delay_ms(8); 
       write_command(0x28); // interfejs 4-bity, 2-linie, znak 5x7 
       write_command(0x08); // wyłącz LCD, kursor i miganie 
       write_command(0x01); // czyść LCD 
       write_command(0x06); // bez przesuwania w prawo 
       write_command(0x0C); // włącz LCD, bez kursora i mrugania 
    } 
    
    
    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); 
    } 
    
    void lcdxy(uint8_t x, uint8_t y) 
    { 
       switch(y) 
       { 
          case 1: y=0x40; break; 
          case 2: y=0x14; break; 
       } 
       write_command(0x80+y+x); 
    } 
    void LCD_clr(void) 
    { 
       write_command(0x01); 
       _delay_ms(8); 
        
       LCD_xy(0,0); 
    } 
    //==========================================================================================// 
    
    void dl(char x)
    {
    TCCR0=0x02;
    OCR0=x;
    while(1)
    {
    if(TCNT0>=OCR0)
    break;
    }
    TCCR0=0;
    TCNT0=0; 
    }
    unsigned char ow_reset__(void) // reset lini one wire 
    { 
       unsigned char presence=1; 
       DDRA |= _BV(0); //DQ = 0; //pull DQ line 
       dl(240);
       dl(240); 
       DDRA &= ~_BV(0); //DQ = 1; // allow line to //powrót lini 1w do trybu wejścia 
    
       dl(60);// wait for presence pulse(pochodzący od DS-a) //czekamy na ustab. lini 
        
       if(bit_is_clear(PINA,0)) presence=0; //odczytujemy co wystawił na linię DS 
       dl(200);// wait for end 
       dl(100);  
       return(presence); // presence signal 
    } // 0=presence, 1 = no part 
    
    
    unsigned char test(void) // test na oecnosc DALLASA 
    { 
    //LCD_xy(0,0); write_text("   TESTUJEMY   "); 
    //_delay_ms(200); 
    //_delay_ms(200); 
    if (ow_reset__()==1) 
    { 
    LCD_xy(0,1); write_text("BRAK CZUJNIKA"); 
    _delay_ms(200); 
    _delay_ms(200); 
    
    } 
    _delay_ms(200); 
    _delay_ms(200);
    return 0; 
    } 
    
    
    //===========================================================================================// 
    //===========================================================================================// 
    
    
    
    unsigned char ow_reset(void) // reset lini one wire 
    { 
       unsigned char presence=1; 
       DDRA |= _BV(0); //DQ = 0; //pull DQ line 
       dl(240);
       dl(240); 
       DDRA &= ~_BV(0); //DQ = 1; //powrót lini 1w do trybu wejścia 
       dl(64);// wait for presence pulse(pochodzący od DS-a) //czekamy na ustab. lini 
       if(bit_is_clear(PINA,0)) presence=0; //odczytujemy co wystawił na linię DS 
       dl(255);// wait for end 
       return(presence); // presence signal 
    } // 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=0; 
       DDRA |= _BV(0);    //DQ = 0; // pull DQ low to start timeslot
       dl(2); 
       DDRA &= ~_BV(0);   //DQ = 1; // then return high 
       dl(14); // delay 15us from start of timeslot 
       if(bit_is_clear(PINA,0)) presence=0; 
       if(bit_is_set(PINA,0)) presence=1; 
       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. 
    { 
       DDRA |= _BV(0); //DQ = 0; // pull DQ low to start timeslot
       dl(2); 
       if(bitval==1) DDRA &= ~_BV(0); //DQ =1; // return DQ high if write 1 
       dl(104); // hold value for remainder of timeslot - delay 104us 
       DDRA &= ~_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 
          dl(120); // ??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 
       } 
       dl(104); 
    
    } 
    
    //--------------------------------------------------------- 
    
    
    
    void Read_Temperature(void) 
    { 
    //char tmp[10]; 
    char temp_lsbyte; //temp_msbyte; 
    //int k; 
    test(); 
    write_byte(0xCC); //Skip ROM 
    write_byte(0x44); // Start Conversion 
    dl(120); 
    ow_reset(); 
    write_byte(0xCC); // Skip ROM 
    write_byte(0xBE); // Read Scratch Pad 
    
    ds.nds[0]=read_byte(); 
    ds.nds[1]=read_byte(); 
    
          LCD_xy(0,1); 
    
             itoa(ds.tds/2,buf,10);//temper. całkowita 
             write_text("Temp: "); 
          write_text(buf); 
          write_text(".\0"); 
             itoa(abs((ds.tds*10/16)%10),buf,10);   //części dziesiętne 
             write_text(buf); 
          write_text(" C"); 
    
    /*void Read_Temperature(void)
    {
    char get[10];
    char temp_lsb,temp_msb;
    int k;
    char temp_f,temp_c;
    ow_reset();
    write_byte(0xCC); //Skip ROM
    write_byte(0x44); // Start Conversion
    delay(5);
    ow_reset();
    write_byte(0xCC); // Skip ROM
    write_byte(0xBE); // Read Scratch Pad
    for (k=0;k<9;k++){get[k]=read_byte();}
    printf("\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
    printf( "\nTempC= %d degrees C\n", (int)temp_lsb ); // print temp. C
    temp_c = temp_lsb; // ready for conversion to Fahrenheit
    temp_f = (((int)temp_c)* 9)/5 + 32;
    printf( "\nTempF= %d degrees F\n", (int)temp_f ); // print temp. F
    }*/
    /* 
    lcdxy(0,0); 
    
    
    // for (k=0;k<9;k++){tmp[k]=read_byte();} 
    
    read_byte(); 
    
    //printf("DAT=%X%X%X%X%X",tmp[8],tmp[7],tmp[6],tmp[5],tmp[4],tmp[3],tmp[2],tmp[1],tmp[0]); 
    itoa(tmp[8],buf,10);//temper. całkowita 
    LCD_xy(0,0); write_text(buf); 
    
    itoa(tmp[7],buf,10);//temper. całkowita 
    LCD_xy(2,0); write_text(buf); 
    
    itoa(tmp[6],buf,10);//temper. całkowita 
    LCD_xy(4,0); write_text(buf); 
    
    itoa(tmp[5],buf,10);//temper. całkowita 
    LCD_xy(6,0); write_text(buf); 
    
    itoa(tmp[4],buf,10);//temper. całkowita 
    LCD_xy(8,0); write_text(buf); 
    
    itoa(tmp[3],buf,10);//temper. całkowita 
    LCD_xy(10,0); write_text(buf); 
    
    itoa(tmp[2],buf,10);//temper. całkowita 
    LCD_xy(12,0); write_text(buf); 
    
    itoa(tmp[1],buf,10);//temper. całkowita 
    LCD_xy(14,0); write_text(buf); 
    
    itoa(tmp[0],buf,10);//temper. całkowita 
    LCD_xy(16,0); write_text(buf); 
    */ 
    
    
    
    
    
    /*
    temp_msbyte = tmp[1]; // Sign byte + lsbit 
    temp_lsbyte = tmp[0]; // Temp data plus lsb 
    if (temp_msbyte <= 0x80){temp_lsbyte = (temp_lsbyte/2);} // shift to tmp whole degree 
    temp_msbyte = temp_msbyte & 0x80; // mask all but the sign bit 
    if (temp_msbyte >= 0x80) {temp_lsbyte = (~temp_lsbyte)+1;} // twos complement 
    if (temp_msbyte >= 0x80) {temp_lsbyte = (temp_lsbyte/2);}// shift to tmp whole degree 
    if (temp_msbyte >= 0x80) {temp_lsbyte = ((-1)*temp_lsbyte);} // add sign bit 
    */
    
    //printf( "TempC=%d C", (int)temp_lsbyte ); // print temp. C 
    
    
    
    
    temperature=temp_lsbyte; 
    
    } 
    
      
    
    
    
    //===========================================================================================// 
    //===========================================================================================// 
    
    
    
    int main (void) 
    
    {  
       dl(64);
       dl(25);  
       lcd_init(); 
       LCD_clr(); 
       DDRB=0x00; 
       PORTB=0x00; 
    
    
    write_byte(0xCC); 
    
       while(1) 
       { 
    
    Read_Temperature(); 
    
    
    
    
       _delay_ms(155); 
          _delay_ms(155); 
          _delay_ms(155); 
               _delay_ms(155); 
       }      
    }
    


    Teraz tak wygląda kod...

    Niestety nadal nic....

    Jak widać delay zastąpiłem zliczaniem na liczniku.

    Układ taktuje 8Mhz
  • #6 3681639
    rsikon
    Poziom 26  
    Posty: 1075
    Pomógł: 24
    Ocena: 26
    "Kolo" ;)

    A może by i tak poinformować układ o prawdzie a nie kłamać??!!

    Piszesz, że taktujesz 8MHz a ja widze w kodzie na poczatku 1000000 a ne 8000000.

    A fuserbity zmieniłeś na 8MHz czy tylko wydaje Ci się że działa na 8MHz?

    Drąż temat... drąż... m się udało :)

    Przepraszam za zwrot Kolo ;) ale taki mam dziś dobry humor :)

    To kod termometru z mini bajera.... ;) Narazie nie mam czasu by doprwadzic go do ładu tak wec nie jest on zminimalizowany i pozbawiony zbednych smieci! Ale działa na 8MHz na Atmega16.


    Radzio
    Załączniki:
    • testLCDds18b20.c (10.47 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #8 3682046
    rsikon
    Poziom 26  
    Posty: 1075
    Pomógł: 24
    Ocena: 26
    W moim kofunkcja test...

    odpalic ja w petli... sprawdza czy dallas odpowiada... jesli nie odpowiada to moze cos nie tak podlaczone...

    jak odpowiada to tylko i wylacznie korekcja czasow zostaje...

    Najwyrazniej Twoje dokladniejsze odmierzanie jest cos nie tak albo zle wartosci odmierzasz.

    Tak przegladajac Twoj kod... pozamieniales funkcje dellay na swoje dl ale nie korygowales czasu! Ja powstawialem takie czy inne wartosci na podstawie symulacji a czy ty swoje sprawdzales ile tak naprawde odmierza w danym momencie??

    Moze pozniej sam to sprawdze bo zdaje mi sie ze wogolene zainteresowales sie protokolem 1wire dla tego czujnika i wogole nie wiesz ile gdzie powinno czasu byc odmierzone. Ale to bede wiedzial jak wrzuce pozniej Twoj kod na symulacje - narazie gdybam.

    Radzio

    I już po testach...

    Np., w dokumentacji DS18B20 mam coś takiego:
    "Odczyt wartości bitu przesyłanego przez układ podrzędny polega na generacji przez układ master impulsu o czasie trwania minimum 1 ms (zazwyczaj stosuje się impulsy 3 .. 5 ms), a następnie na zwolnieniu linii DQ i sprawdzeniu jej stanu logicznego przed upływem 15 ms od rozpoczęcia sekwencji odczytu ..."
    A symulator Twoje 15ms pokazuje mi jako 22 :)

    Niby nie wielka roznica ale... kto wie moze robi problem wlasne ona ;)
    Dopracuj czasy.

    Radzio
  • #9 3683015
    domelfm
    Poziom 16  
    Posty: 238
    Pomógł: 5
    Ocena: 28
    hymm :) ale wałek...
    Musze popatrzeć na te czasy... ale odmierzanie na dl jest dość dokładne..
    o ile generator RC jest dokładny..

    Dodano po 45 [minuty]:

    Podzielisz się tym symulatorem avr ?
    Kulka mi cały czas wychodzą jakieś ciekawe .... wyniki....
  • #10 3683169
    rsikon
    Poziom 26  
    Posty: 1075
    Pomógł: 24
    Ocena: 26
    Symulator jest czescia AVR Studio.

    Radzio
  • #12 3685981
    domelfm
    Poziom 16  
    Posty: 238
    Pomógł: 5
    Ocena: 28
    
     
    #include <avr/io.h> 
    #include <stdlib.h> 
    #include <util/delay.h> 
    
    #define F_CPU 80000000UL
    
    #define DQ 0
    
    #define SET_DQ DDRA &= ~_BV(DQ)
    #define CLR_DQ DDRA |= _BV(DQ)
    
    #define IN_DQ PINA & _BV(DQ)
    
    #define LCD  PORTA
    #define DLCD DDRA
    #define E  3
    #define RS  2
    //
    #define SET_E   LCD |= _BV(E)
    #define CLR_E   LCD &= ~_BV(E)
    //
    #define SET_RS  LCD |= _BV(RS)
    #define CLR_RS  LCD &= ~_BV(RS)
    
    char i,x,y;
    
    
    //==========================================LCD================================================== 
    
    void dl(char x) 
    { 
    TCCR0=0x02; 
    OCR0=x; 
    while(1) 
    { 
    if(TCNT0>=OCR0) 
    break; 
    } 
    TCCR0=0; 
    TCNT0=0; 
    
    } 
    // funkcja opóźniająca o x*1ms 
    void waitms(char x) 
    { 
    unsigned char a; // zmnienne licznikowe 
    for( ; x > 0; --x) // ta pętla zostanie wykonana x-razy 
    for(a = 5; a > 0; --a) 
    dl(200); 
    } 
    
    // pcodedura zapisu bajtu do wyświetlacza LCD 
    // bez rozróżnienia instrukcja/dana 
    void write_to_lcd(char x) 
    { 
    SET_E; // ustaw na E stan wysoki 
    LCD = ((LCD & 0x0F) | (x & 0xF0)); // zapis pierwszej połówki bajtu 
    CLR_E; // opadające zbocze na E -> zapis do wyświetlacza 
    SET_E; // ustaw na E stan wysoki 
    LCD = ((LCD & 0x0F) | ((x & 0x0F) << 4)); // zapis drugiej połowki bajtu 
    CLR_E; // opadające zbocze na E -> zapis do wyświetlacza 
    waitms(1); // czekaj 1ms 
    } 
    
    // procedura zapisu instrukcji do wyświetlacza LCD 
    void write_command(char x) 
    { 
    CLR_RS; // niski stan na RS -> zapis instrukcji 
    write_to_lcd(x); // zapis do LCD 
    } 
    
    // procedura zapisu danej do wyświetlacza LCD 
    void write_char(char x) 
    { 
    SET_RS; // wysoki stan na RS -> zapis danej 
    write_to_lcd(x); // zapis do LCD 
    } 
    
    // procedura zapisu tekstu do wyświetlacza LCD 
    void write_text(char * s) 
    { 
    while(*s) // do napotkania 0 
      { 
      write_char(*s); // zapisz znak wskazywany przez s na LCD 
      s++; // zwiększ s (przygotuj nastepny znak) 
      } 
    } 
    
    // procedura inicjalizacji wyświetlacza LCD 
    void lcd_init(void) 
    { 
    waitms(15); // czekaj 15ms na ustabilizowanie się napięcia zasilającego 
    CLR_E; // E = 0 
    CLR_RS; // RS = 0 
    char i; // zmianna licznikowa 
    for(i = 0; i < 3; i++) // trzykrotne powtórzenie bloku instrukcji 
      { 
      SET_E; // E = 1 
      LCD &= 0x3F; // 
      CLR_E; // E = 0 
      waitms(5); // czekaj 5ms 
      } 
    SET_E; // E = 1 
    LCD &= 0x2E; // 
    CLR_E; // E = 0 
    waitms(1); // czekaj 1ms 
    write_command(0x28); // interfejs 4-bity, 2-linie, znak 5x7 
    write_command(0x08); // wyłącz LCD, kursor i miganie 
    write_command(0x01); // czyść LCD 
    write_command(0x06); // bez przesuwania w prawo 
    write_command(0x0C); // włącz LCD, bez kursora i mrugania 
    } 
    
    
    void LCD_xy(char x, char y) 
    { 
       switch(y) 
       { 
          case 1: y=0x40; break; 
          case 2: y=0x14; break; 
       } 
       write_command(0x80+y+x); 
    } 
    
    
    void LCD_clr(void) 
    { 
       write_command(0x01); 
       waitms(1); 
        
       LCD_xy(0,0); 
    } 
    //==========================================================================================// 
    
    
    //---------------------------1-wire------------------------------ 
    
    
    //////////////////////////////////////////////////////////////////////////////////// 
    unsigned char ow_reset__(void) // reset lini one wire 
    { 
       unsigned char presence=1; 
       CLR_DQ; //DQ = 0; //pull DQ line 
      
     dl(250); 
     dl(200);//   450 us 
      
       SET_DQ; //DQ = 1; // allow line to //powrót lini 1w do trybu wejścia 
    
     dl(80);       //    31,88 us   wait for presence pulse(pochodzący od DS-a) //czekamy na ustab. lini 
        
       if(IN_DQ) presence=1;
       else presence=0; //odczytujemy co wystawił na linię DS 
    
      dl(200); 
      dl(200); 
       if(IN_DQ) presence=0;
       else presence=1; 
       return(presence); // presence signal 
    } // 0=presence, 1 = no part 
    
    
    void test(void) // test na oecnosc DALLASA 
    { 
    LCD_xy(0,0); write_text("   TESTUJEMY   "); 
    _delay_ms(200); 
    _delay_ms(200); 
    if (ow_reset__()==1) 
    { 
    LCD_xy(0,1); write_text("BRAK CZUJNKA"); 
    
    for(x=0;x<6;x++) 
    _delay_ms(200); 
    
    } else 
    { 
    LCD_xy(0,1); write_text("CZUJNIK OK!"); 
    
    for(x=0;x<6;x++) 
    _delay_ms(200); 
              
    } 
    for(x=0;x<10;x++) 
    _delay_ms(200); 
                LCD_clr(); 
              
    } 
    
    
    //===========================================================================================// 
    //===========================================================================================// 
    
    
    
    
      
     // 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=0; 
       CLR_DQ;    //DQ = 0; // pull DQ low to start timeslot 
       for(x=0;x<1;x++); 
       asm ("nop"); 
        
       SET_DQ;   //DQ = 1; // then return high 
       dl(5);; // delay 15us from start of timeslot 
        
       if(IN_DQ) presence=1;
       else presence=0; 
       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. 
    { 
       CLR_DQ;    //DQ = 0; // pull DQ low to start timeslot
       for(x=0;x<1;x++); 
       asm ("nop");  
       if(bitval==1) 
       SET_DQ; //DQ =1; // return DQ high if write 1 
       dl(60); // hold value for remainder of timeslot - delay 104us 
       SET_DQ;//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 
          dl(75);    // ??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 
       } 
    dl(50); 
    
    } 
      
    
    
    
    ////////////////////////////////////////////////////////////////////////////////// 
    
    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(1000); 
      _delay_ms(1000);
      _delay_ms(1000);
    ow_reset__(); 
    write_byte(0xCC); // Skip ROM 
    write_byte(0xBE); // Read Scratch Pad 
    
    
    
    temp1=read_byte(); 
    temp2=read_byte(); 
    
    ow_reset__();
    
    t = abs(((temp2 << 8) | temp1) * 10 / 16) ; //+ ((temp2 & 0x80) ? 0x00 : 600) 
    
    dtostrf((float)t/10,5,1,tmp); 
    LCD_xy(1,0); 
    write_text(tmp); 
    
    } 
      
    
    
    
    //===========================================================================================// 
    //===========================================================================================// 
    
    
    
    int main (void) 
    
    { 
    
    // konfiguracja portów we/wy 
    DLCD = 0xFC; 
     LCD = 0xFC; 
    DDRD=0xFC;
    PORTD=0xFC;  
       lcd_init(); 
       LCD_clr(); 
       //DDRB=0x00; 
       //PORTB=0x00; 
    
    
    //write_byte(0xCC); 
    test(); 
    
    
       while(1) 
       { 
        
    Read_Temperature(); 
    for(i=0;i<30;i++){         //Tworzy opóźnienie do odświeżania temp 
          _delay_loop_2(65535); 
    
       } 
      
        } 
        
    }    
     


    Wydaje mi się że kod jest ok, ale jest jeden problem temp odczytana, cały czas ma wartość 85.2 st i wogle się nie zmienia niewiem dlaczego.
    Ta temperatura to jest temp która jest na starcie wpisana do ds po resecie zasilania (wyczytałem to w nocie katalogowej ds-a).
  • #13 3688271
    rsikon
    Poziom 26  
    Posty: 1075
    Pomógł: 24
    Ocena: 26
    Owszem pierwszy pomir taki mi pokazuje... ale kolejny juz jest ok.


    Radzio
  • #14 3688419
    domelfm
    Poziom 16  
    Posty: 238
    Pomógł: 5
    Ocena: 28
    Niestety chyba mój czujnik jest do d...
    Albo ktoś może dojrzy ten maluśki błąd...
    JA niestety nie moge dojrzeć...

    Pozdrawiam.

    P.S

    Taka dobra rada co do tych czasów to jak macie jakąś funkcje podobną do mojego testu. To musicie tak dobierać czasy żeby czujnik cały czas był wykrywany(nagrzewajcie go zapalniczka wtedy mu się rozjeżdżają czasy).
  • #15 3691414
    szakamason
    Poziom 13  
    Posty: 123
    Pomógł: 3
    Ocena: 4
    wreszcie odpaliłem mojego ds, w symulatorku działał zawsze ok, a w realu nie, przypomniałem sobie że w książce "uK AVR w praktyce" był kod źródłowy dla pastylki dallasa, i było to właśnie na 8MHz, tak więc skopiowałem bezczelnie funkcję opóźnienia w [us], wkleiłem do swojego programu i zaczęło działać, wyświetla cały zakres temperatur od -55 do 128oC. Wniosek, symulacja ds18"x"20 w proteusie przebiegała poprawnie dla teoretycznych-idealnych czasów ds'a, czasy te mierzone na wirtualnym analizatorze stanów logicznych były takie,jakie powinny wynikać z zastosowanej funkcji opóźnienia dla uK. W rzeczywistości jednak czasy odpowiedzi ds'a widocznie różniły się nieznacznie od katalogowych na tyle, by uniemożliwić poprawny odczyt z ds'a.
  • #16 3691792
    domelfm
    Poziom 16  
    Posty: 238
    Pomógł: 5
    Ocena: 28
    Powiedz w jakim symulatorku odpaliłes tego dsa ?
    Jezeli mozesz to podziel się tym odkryciem.. :)

    Dodano po 11 [minuty]:

    HYmm własnie sprawdziłem... Ds nierozumie wysyłanych do niego komend..
    JEDYNIE RESET ROZUMIE...

    Czyli musze pokombinować.. Ale niewiem dlaczego tak jest..
  • #17 3692075
    rsikon
    Poziom 26  
    Posty: 1075
    Pomógł: 24
    Ocena: 26
    Proste :)

    czasy w wysyłaniu / odbieraniu bitów bajtów.

    Tam sa male i male tolerancje panuja.

    Radzio
  • REKLAMA
  • #20 3701259
    domelfm
    Poziom 16  
    Posty: 238
    Pomógł: 5
    Ocena: 28
    Hymm.
    Czasy były dobre..
    Wymieniłem czujniki i działa wszystko jak nalezy.
    Kupiłem 2 nowe ale jeden znowu uwaliłem przez złe podłączenie polaryzacji i znowu wyswietla tylko 85st.

    Powiedzcie czy to jest mozliwe zeby przez sec spalić tego dallasa ?
    Zaledwie tylko dotknąłem i juz było po nim.
    Moze trafiłem na jakies trefne ?
  • #25 3705188
    smelektroda
    Poziom 13  
    Posty: 66
    Pomógł: 5
    Witam
    Gdzieś czytałem, że zasilanie poprzez linie stosuję się do pracy z układami, które charakteryzuja się małym poborem prądu.

    Natomiast, gdy chcemy mieć chwilowy dostęp do pełnego napięcia zasilania, podobno można zastosować taki układ z tranzystorem jak w załączniku.
    Załączniki:
    • Kod w C dla DS18B20 i LCD na ATmega32 - odczyt temperatury -0.02 1-wire.JPG (8.93 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #27 3705259
    smelektroda
    Poziom 13  
    Posty: 66
    Pomógł: 5
    Tez jestem ciekaw jak ma sie to w praktyce.
    A ja mam takie pytanko, bo się męcze troche z ds18b20:
    jeżeli w kodzie w funkcji ow_reset:

    unsigned char ow_reset__(void) // reset lini one wire
    {
    unsigned char presence=1;
    DDRA |= _BV(0); //DQ = 0; //pull DQ line
    dl(240);
    dl(240);
    DDRA &= ~_BV(0); //DQ = 1; // allow line to //powrót lini 1w do trybu wejścia

    dl(60);// wait for presence pulse(pochodzący od DS-a) //czekamy na ustab. lini

    if(bit_is_clear(PINA,0)) presence=0; //odczytujemy co wystawił na linię DS
    dl(200);// wait for end
    dl(100);
    return(presence); // presence signal
    } // 0=presence, 1 = no part

    mam źle dobrane czasy opóźnienia to wtedy presenence będzie 1 czyli no part, tak? Bo cały czas na lcd wyświetla mi się "cisza" (czyli nie ma czujnika) lub temp 0.0. Bo dobrze podłączam czujnik, ale cały czas nie wykrywa mi go. A czytając inne posty mimo złych czasów czasami wykrywa czujnik i wyswietla sie np. temp. 80 iles tam stopni C.

    Pozdrawiam
  • #28 3705346
    domelfm
    Poziom 16  
    Posty: 238
    Pomógł: 5
    Ocena: 28
    Podrzucam programik po modyfikacjach.
    Działa dobrze.
    Jedyna jego wada że po kompilacji waży jakies 4,5 kb A to dość duzo tym bardziej ze słyszałem iż ludzie mieszczą się w 2- 2,5 kb.
    Przy okazji jeżeli ktoś miałby ochote podpowiedzieć mi jak zoptymalizować kod bede wdzieczny.

    Teraz odpowiedz na problem..
    Ta procedurę wykrywa tylko obecność ds. I czasy w niej sa poprawne.
    Odczyt ds zalezy od procedury odczytującej (nic nowego).
    A to co odczytamy zalezy od wczesniej wysłanych komend i sygnałów reset . Zobacz procedurę odczytującą ds. Jezeli mamy poprawną procedurę odczytu to na pewno odczytamy jakąś temp. 0 albo 85 zaleznie od wysyłanych sygnałów reset. A żeby odczytać włsciwą temperaturę ds musi mieć czas na przeliczenie jej oraz musi rozumieć wysyłane komendy do niego.
    Załączniki:
    • DS.c (7.49 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #29 3705867
    Balu
    Poziom 38  
    Posty: 4397
    Pomógł: 323
    Ocena: 48
    Szczerze mówiąc, to nie używam żadnego tranzystora:)
    do 100m działało bez problemu:)
    Po prostu zwierasz dwie zewnętrzne nóżki:)
    Jedyny wymóg to minimum 800ms przed konwersją linii w stanie wysokim (jakiś silny pull-up). No i afair wtedy nie masz max rozdzielczości... Co w wypadku tych czujek i tak jest zbyteczne bo one dość "interesująco" działają:P
    (dwie potrafią mieć rozrzut +-3*C)
  • #30 4055656
    CBR-MAR
    Poziom 10  
    Posty: 37
    witam
    Zarzucilem kod do DS'a od uzytkownika domelfm do AVRStudio 4.12 wersja beta + WINAVR 2005-11-i niestety wyskakuje mi błąd:(

    AllocationBase 0x0, BaseAddress 0x71590000, RegionSize 0x170000, State 0x10000
    C:\WinAVR\utils\bin\sh.exe: *** Couldn't reserve space for cygwin's heap, Win32 error 487
    avr-gcc.exe -mmcu=atmega32 -Wall -gdwarf-2 -O0 -MD -MP -MT Mtemp.o -MF dep/Mtemp.o.d -c ../Mtemp.c
    ../Mtemp.c:402: fatal error: opening dependency file dep/Mtemp.o.d: No such file or directory
    compilation terminated.
    make: *** [Mtemp.o] Error 1
    Build failed with 1 errors and 0 warnings...


    Moze mi ktos podpowie co z tym zrobic???
    Bardzo prosze o pomoc...

Podsumowanie tematu

✨ Dyskusja dotyczy problemów z odczytem temperatury z czujnika DS18B20 podłączonego do mikrokontrolera ATmega32 z wyświetlaczem LCD. Głównym problemem jest niepoprawne odmierzanie czasu w protokole 1-Wire, co skutkuje stałym odczytem wartości -0.02 lub błędnymi wynikami, np. 85°C. Użytkownicy wskazują na konieczność precyzyjnego odmierzania impulsów czasowych, zgodnych z dokumentacją DS18B20, oraz poprawnej konfiguracji częstotliwości taktowania mikrokontrolera (często 8 MHz). Wskazano, że symulacje w AVR Studio mogą nie odzwierciedlać rzeczywistych czasów, co wymaga korekty opóźnień w kodzie. Dyskutowano także o sposobach zasilania czujnika (zasilanie stałe vs. pasożytnicze) oraz o możliwych uszkodzeniach czujnika przez nieprawidłowe podłączenie. Przykładowe fragmenty kodu w C dla ATmega32 i ATmega16 z obsługą LCD i DS18B20 zostały udostępnione, wraz z uwagami dotyczącymi optymalizacji i poprawnego przesuwania bitów podczas konwersji temperatury. Wskazano również na gotowe biblioteki, takie jak RKlibAVR, które ułatwiają implementację. Ostatecznie rozwiązaniem jest dokładne dostosowanie czasów opóźnień, poprawne podłączenie czujnika oraz stosowanie sprawdzonych procedur resetu i odczytu w protokole 1-Wire.
Podsumowanie wygenerowane przez AI na podstawie treści dyskusji.
REKLAMA