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

[ATmega32][C] DS18B20-błedne odczyty temperatury

Cored 14 Mar 2009 14:54 2393 6
REKLAMA
  • #1 6280456
    Cored
    Poziom 10  
    Witam!
    Zacznę od tego, że jestem mocno początkujący w programowaniu uC w C (no i w ogóle w programowaniu). Chciałem zrobić termometr na atmega32, wyświetlaczu lcd przy wykorzystaniu DS18B20. Przewertowałem podobnych tematów na forum multum, przerobiłem datasheet'y i inne takie. Siedzę już nie wiem ile czasu nad tym i nie mogę dojść co jest nie tak więc proszę o pomoc.
    DS podłączony jak należy, tj:
    1 - GND, 2 - DQ (do PIND4), 3 - Vcc oraz dodatkowo linia danych podciągnięta jest przez rezystor 3,3kΩ (próbowałem i dla 4.7kΩ) do zasilania. Procesor taktowany jest wewnętrznym oscylatorem 4MHz.

     #ifndef _delay_h_
    #define _delay_h_
    #include <inttypes.h>
    #include <avr/io.h>
    #include <stdlib.h>
    #define F_CPU 4000000UL
    static inline void delayloop16(uint16_t count)
    {
       asm volatile (    "cp  %A0,__zero_reg__ \n\t"  \
                         "cpc %B0,__zero_reg__ \n\t"  \
                         "breq L_Exit_%=       \n\t"  \
                         "L_LOOP_%=:           \n\t"  \
                         "sbiw %0,1            \n\t"  \
                         "brne L_LOOP_%=       \n\t"  \
                         "L_Exit_%=:           \n\t"  \
                          : "=w" (count)
                          : "0"  (count)
                     );                           
    }
    #define DELAY_US_CONV(us) ((uint16_t)(((((us)*1000L)/(1000000000/F_CPU))-1)/4))
    #define delay_us(us)     delayloop16(DELAY_US_CONV(us))
    
    static void delayms(int cnt)
    {
    while(cnt--) delay_us(995);
    }
    #define delay_ms(ms)  delayms(ms)
    #endif 
    
    #define WE 4
    #define PORT_1wire PIND
    #define SET_1wire DDRD&=~_BV(WE)
    #define CLEAR_1wire DDRD|=_BV(WE)
    
    char buf[8]; 
    
    unsigned char RESET_PULSE(void)
    {
    unsigned char PRESENCE;
    
    CLEAR_1wire;
    delay_us(600);
    SET_1wire;
    delay_us(50);
    
    if (bit_is_clear(PORT_1wire, WE)){PRESENCE=1;} else {PRESENCE=0;}
    delay_us(470);
    if (bit_is_set(PORT_1wire, WE)){PRESENCE=1;} else {PRESENCE=0;}
    return (PRESENCE);
    }
    
    void send(char bit)
    {
    CLEAR_1wire;
    delay_us(10);
             if(bit==1)
                SET_1wire;
                delay_us(80);
                SET_1wire;
    }
    
    unsigned char read(void)
    {
       unsigned char PRESENCE=0;
       CLEAR_1wire;
       delay_us(2);
       SET_1wire;
       delay_us(15);
       if(bit_is_set(PORT_1wire, WE)) PRESENCE=1; else PRESENCE=0;
       return (PRESENCE);
    }
    
    
    void send_byte(char wartosc)
    {
       unsigned char i;
       unsigned char pom;
       for (i=0; i<8; i++)
       {
       pom=wartosc>>i;
       pom&=0x01;
       send(pom);
       }
    delay_us(102);
    }
    
    unsigned char read_byte(void)
    {
       unsigned char i;
       unsigned char wartosc=0;
       for (i=0; i<8; i++)
       {
       if(read()) wartosc|=0x01<<i;
       delay_us(120);
       }
    return(wartosc);
    }
    .
    .
    .//obsługa LCD
    .
    .
    .
    union {
    int tds;
    char nds[2];
    }ds;
    
    int main(void)
    {
    unsigned char sprawdz;
    char temp1=0, temp2=0;
    .
    .
    .//inicjalizacja LCD
    .
    LCDxy(0,0);
    tekst("DS18B20");
    delay_ms(1000);
    
    for(;; ){
          sprawdz=RESET_PULSE();
             if (sprawdz==1)
                {
                send_byte(0xCC);
                send_byte(0x44);
                delay_ms(1000);
    		
                sprawdz=RESET_PULSE();
    
                send_byte(0xCC);
                send_byte(0xBE);
    
                ds.nds[0]=read_byte();
                ds.nds[1]=read_byte();	
                RESET_PULSE();
    
                itoa(ds.tds/2,buf,10);
    	    LCDxy(0,0);
    	    tekst("T=");
    	    tekst(buf); 
    	    tekst(".\0");
                itoa(abs((ds.tds*10/8 )%10),buf,10);
                tekst(buf);
    	    tekst("C");
    	    delay_ms(500);
                }
                else
                {
                LCDxy(0,0);
    	    tekst("cisza");
                }
    }
    } 
    


    Jak widać użyłem poleceń i funkcji jakie już pojawiały się na forum w podobnych tematach, z góry dzięki!
    Problem polega na tym, że LCD wyświetla mi temperaturę T=0.1 C. Jeśli pominę fragment kodu dotyczący tego co za przecinkiem to oczywiście mam same 0. Czasy wydają się być OK, próbowałem przy różnych częstotliwościach taktowania jest to samo:/. Po odłączeniu linii danych wyświetla się "cisza" - czyli niby prawidłowo. Jak dla mnie to jeśli konwersja się odbywa to tak jakby nie zczytywał danych z DSa ale bardzo możliwe że się mylę. Wymieniałem DSa na drugiego i to samo...
    Proszę o pomoc :cry:

    Regulamin p.11 - poprawiłem tytuł.
    [zumek]
  • REKLAMA
  • #2 6280533
    SnowBizz
    Poziom 15  
    
    {
    send_byte(0xCC);
    send_byte(0x44);
    delay_ms(1000);
    
    sprawdz=RESET_PULSE();
    
    send_byte(0xCC);
    send_byte(0xBE);
    
    ds.nds[0]=read_byte();
    ds.nds[1]=read_byte();
    RESET_PULSE();
    
    itoa(ds.tds/2,buf,10);
    LCDxy(0,0);
    tekst("T=");
    tekst(buf);
    tekst(".\0");
    itoa(abs((ds.tds*10/8 )%10),buf,10);
    tekst(buf);
    tekst("C");
    delay_ms(500);
    } 


    Zmień narazie na takie coś:
    
    {
    unsigned char b1, b2;
    
    send_byte(0xCC);
    send_byte(0x44);
    delay_ms(1000);
    
    sprawdz=RESET_PULSE();
    
    send_byte(0xCC);
    send_byte(0xBE);
    
    b1=read_byte();
    b2=read_byte();
    RESET_PULSE();
    
    itoa(b1,buf,10);
    LCDxy(0,0);
    tekst(buf);
    itoa(b2,buf,10);
    tekst(buf);
    }


    I powiedz jakie wartości wyświetla na LCD
  • REKLAMA
  • #3 6280614
    Cored
    Poziom 10  
    Teraz wyświetla:

    255255

    cokolwiek miałoby to znaczyć...
  • #4 6280747
    dawid512
    Poziom 32  
    Nie wgłębiając się w kod znowu kolejna osoba korzystająca z jakiś "cudownych" funkcji opóźniających a przecież są gotowe (util/delay.h). Kolejne pytanie to czy jesteś na 100% pewny tych 4MHz.
  • REKLAMA
  • #5 6281161
    Cored
    Poziom 10  
    Ta opóźniająca funkcja była już w którymś z tematów mocno polecana natomiast odradzali niektórzy użytkownicy forum te standardowe z <util/delay.h>. No ale sprawdziłem je też, podłączyłem uC pod oscyloskop i poustawiałem czasy jeszcze raz...w końcu coś ruszyło:-)
    Z tym że używam teraz takiego kodu do przetworzenia wyniku:

    Cytat:

    temp1=read_byte();
    temp2=read_byte();

    sprawdz=RESET_PULSE();

    float temp=0;

    temp=(float)(temp1+(temp2*256))/16;

    dtostrf(temp,1,1,buf);
    instrukcja(0x01);
    instrukcja(0x80);
    tekst(buf);


    i wszystko jest ok w zakresie 16 do 24 stopni, poniżej 16 spada od razu na ujemne wartości, a idąc powyżej 24 wskakuje na 8 i dalej do góry liczy...

    Poprzedni kod generował mi wynik w okolicach 180 C...walczę dalej w każdym razie.
    Dzięki za wszystkie sugestie!
  • REKLAMA
  • Pomocny post
    #6 6282811
    kaktus_c++
    Poziom 18  
    nie wiem czy coś ze mną nie tak czy z tym forum, ale piszę tą odpowiedź drugi raz, albo odpowiedziałem w innym temacie ...
    użyj tej funkcji, u mnie działa

    to jest dla DS18S20 (niepotrzebnie wkleiłem , ale niech już zostanie)
    float zamien_temp(unsigned char MSB,unsigned char LSB)
    {
    	float ftmp;
            if(MSB==0x00)//dodatnia,lub 0
    	{
    		ftmp=LSB/2;
    		if(((LSB%2)*5)==5)
    			return ftmp+0.5;
    		else
    			return ftmp;
    	}
    	else//ujemna
    	{
    		ftmp=-(0xff-LSB+1)/2;
    		if((((0xff-LSB+1)%2)*5)==5)
    			return ftmp-0.5;
    		else
    			return ftmp;
    	}
    }
    

    A to jest dla DS18B20 - domyślnie 12 bitowy odczyt
    
    float zamien_temp(unsigned char MSB,unsigned char LSB)
    {
            unsigned int suma;
    		if(MSB&0x80)//!=0 to ujemna temp
            {
                LSB=~LSB +1;
                MSB=~MSB;
                suma = LSB + (((unsigned int)MSB)<<8);
                return  ((float)suma) * -0.0625;
            }
            else//dodatnia temp
            {
                suma = LSB + (((unsigned int)MSB)<<8);
                return  ((float)suma) * 0.0625;
            }
    }
    

    używasz tak : temp = zamien_temp(temp2,temp1);
  • #7 6284427
    Cored
    Poziom 10  
    Wielkie dzięki kaktus_c++, układ ruszył i działa jak należy:-)
    Nie pozostaje mi nic innego jak kontynuacja studiów nad językami;-)
REKLAMA