Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

atmega128 + ds18b20 zly odczyt temperatury

lordadam 14 Paź 2009 22:27 2563 15
  • #1 14 Paź 2009 22:27
    lordadam
    Poziom 9  

    Witam!

    Pierwsze co chciałbym powiedzieć to wiem, że informacji o tym czujniku jest pełno na forum, ale ja już stosowałem wiele sposobów i nic. Otóż mój problem jest taki, że czujnik cały czas podaje mi temperaturę -0.1 . Czujnik jest podłączony w trybie z zewnętrznym zasilaniem (trzy przewody) . Do szyny danych podciągnięty jest plus przez rezystor 4,7k . Szyna danych podłączona do PIND0 . Zegar 16MHz .

    Oto kod:

    Code:

    #define F_CPU 16E6

    #include <avr\io.h>
    #include <util/delay.h>
    #include <stdlib.h>

    #include "lcd.h"

    #define WE 0
    #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(500);
       SET_1wire;
       _delay_us(30);
       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(5);
       if (bit==1)
       {
          SET_1wire;
          _delay_us(80);
          SET_1wire;
       }
    }

    unsigned char read()
    {
       unsigned char PRESENCE;
       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(100);
    }

    unsigned char read_byte()
    {
       unsigned char i;
       unsigned char wartosc=0;

       for(i=0;i<8;i++)
       {
          if(read()) wartosc|=0x01<<i;
          _delay_us(15);




       }
       return wartosc;
    }







    int main()
    {
       static char tekst[128]="OK";
       static char tekst2[128]="NO";
       unsigned char sprawdz;
       char temp1=0 , temp2=0;


             LCD_init();
              LCD_control(ON, BLINK, SHOW);
             

       for(;;)
       {
          sprawdz=RESET_PULSE();
          if(sprawdz==1)
          {
             send_byte(0xCC);
             send_byte(0x44);
             _delay_ms(800);
             
             sprawdz=RESET_PULSE();
             send_byte(0xCC);
             send_byte(0xBE);

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

             sprawdz=RESET_PULSE();

             float temp=0;
             temp=(float)(temp1+(temp2*256))/16;
                
             
             dtostrf(temp,1,1,buf);

             LCD_clear();
             LCD_setpos(0);
             LCD_putstring(buf);
          }
          else if (sprawdz==0)
          {
             LCD_clear();
             LCD_setpos(0);
             LCD_putstring(tekst2);
          }
       }
       for(;;)
       return 0;
    }



    Siedzę już nad tym dość długo i nie mogę nic wymyślić , może to jest jakiś głupi błąd którego nie mogę znaleźć. Dzięki za pomoc.

    0 15
  • #2 14 Paź 2009 22:56
    dawid512
    Poziom 32  

    Nie pasuje mi ten zapis

    Code:
    #define F_CPU 16E6 
    Wg niego masz kwarc 5862MHz. Spróbuj wpisać
    Code:
    #define F_CPU 16000000L

    0
  • #3 14 Paź 2009 23:30
    lordadam
    Poziom 9  

    Zmieniłem, niestety nie pomogło .

    0
  • #4 15 Paź 2009 00:06
    atom1477
    Poziom 43  

    Preskaler zegara wyłączony?

    0
  • #5 15 Paź 2009 00:51
    lordadam
    Poziom 9  

    Może głupie pytanie ale jak go wyłączyć ??

    Zrobiłem coś takiego ale nie wiem czy o to chodzi:

    Code:
    XDIV&=~_BV(7);


    W każdym razie nie pomogło

    0
  • #6 15 Paź 2009 01:17
    atom1477
    Poziom 43  

    Cofam to co powiedziałem. ATMega128 nie ma preskalera.
    Ale ma JTAG i tryb zgodności z ATMega103. Tutaj nie powinno to specjalnie przeszkadzać, ale masz to powyłączane?

    0
  • #7 15 Paź 2009 01:22
    lordadam
    Poziom 9  

    W fuse bits mam ustawione na

    Cytat:
    Ext. Crystal/Resonator High Freq.; Start-up time: 16K CK + 64 ms

    Więc chodzi na zewnętrznym kwarcu 16Mhz

    JTAG i tryb zgodności z 103 wyłączony.

    Nasuwa mi się już tylko myśl, że ds jest popsuty:(

    0
  • #8 15 Paź 2009 01:49
    atom1477
    Poziom 43  

    Ale sprawdziłeś czy na pinie jest jakikolwiekprzegieg?

    0
  • #9 15 Paź 2009 02:05
    lordadam
    Poziom 9  

    Układ odpowiada na Reset Pulse więc jako tako jeszcze działa ale potem coś jest nie tak.

    0
  • #10 15 Paź 2009 06:39
    zumek
    Poziom 39  

    lordadam napisał:
    ... ale potem coś jest nie tak.

    Zastanów się, co w tej funkcji jest ..."popsute" :-P
    Code:

    void send(char bit)
    {
       CLEAR_1wire;
       _delay_us(5);
       if (bit==1)
       {
          SET_1wire;
          _delay_us(80);
          SET_1wire;
       }
    }

    0
  • #11 15 Paź 2009 14:21
    lordadam
    Poziom 9  

    Według mnie ta funkcja jest ok, ponieważ Wysłanie bitu polega na ustawieniu magistrali w stan niski, następnie jeśli po czasie min. 1μszostanie ona ustawiona w stan wysoki, równoznaczne jest to z wysłaniem jedynki. Jeśli z kolei po wyczyszczeniu magistrali nie nastąpi w określonym czasie podciągnięcie jej do jedynki to
    uznaje się to za wysłanie zera logicznego.

    Ale, żeby nie być zadufanym w swoim kodzie zastosowałem taki przykład z kodu zamieszczonego w jednym watku:

    Code:

    void send(char bit)
    {
       CLEAR_1wire;
       _delay_us(15);
       if (bit==0)
       {
          _delay_us(60);
          SET_1wire;
          _delay_us(2);
       }

       else
       {
          SET_1wire;
          _delay_us(80);
       }
    }


    Niestety czujnik nadal pokazuje -0.1

    0
  • #12 15 Paź 2009 15:12
    tmf
    Moderator Mikrokontrolery Projektowanie

    Masz skopane RESET_PULSE, zobacz koncowke i twoje badanie czy jest ok. Masz skopane send (to oryginalne), to powyzej tez - za dlugi jest impuls ujemny, masz skopane send_byte - zobacz jakie sa timingi pomiedzy bitami, a jakie ty masz. read_byte moze jest ok, ale tez nie jest idealne.

    0
  • #13 16 Paź 2009 12:16
    lordadam
    Poziom 9  

    Witam, zmieniłem trochę program oraz czujnik w tryb parasite power . Sytuacja trochę się poprawiła ale niewiele . Czujnik cały czas pokazuje temperaturę 128.0 stopni . Na początku jak dałem mu za mały czas po komendzie konwersji (0x44) to podawał 85.1 stopnia czyli jak to było gdzieś już powiedziane na forum to nie wyrabiał się z konwersją . Po zwiększeniu czasu pokazuje 128.0 . Oto program:

    Code:


    # define F_CPU 1000000UL
    #include <avr\io.h>
    #include <util/delay.h>
    #include <stdlib.h>

    #include "lcd.h"


    #define WE 0
    #define PORT_1Wire PIND
    #define SET_1Wire DDRD&=~_BV(WE)
    #define CLEAR_1Wire DDRD|=_BV(WE)



    unsigned char RESET_PULSE(void)
    {
       unsigned char PRESENCE=0;
       int i;
       CLEAR_1Wire;
       _delay_us(480);
       SET_1Wire;
       _delay_us(15);
       for(i=0;i<55;i++)
       {
          if(bit_is_clear(PORT_1Wire,WE)) PRESENCE=1;
          _delay_us(1);
       }
       _delay_us(600);
       return PRESENCE;
    }


    void send(char bit)
    {
       CLEAR_1Wire;
       _delay_us(2);
       if(bit==1) SET_1Wire;
       _delay_us(80);
       SET_1Wire;

    }

    unsigned char read(void)
    {
       unsigned char i, PRESENCE=0;
       CLEAR_1Wire;
       _delay_us(6);
       SET_1Wire;
       _delay_us(7);
       for(i=0;i<50;i++)
       {
          if(bit_is_clear(PORT_1Wire,WE)) PRESENCE=1;
          _delay_us(1);
       }
       _delay_us(50);
       return(PRESENCE);
    }

    void send_byte(char wartosc)
    {
       int i;
       unsigned char pom;
       for(i=0;i<8;i++)
       {
          pom=wartosc>>i;
          pom&=0x01;
          send(pom);
       }
       _delay_us(20);
    }

    unsigned char read_byte(void)
    {
       uint8_t i;
       unsigned char wartosc=0;
       for(i=0;i<8;i++)
       {
          if(read()) wartosc|=0x01<<i;
       }
       return(wartosc);
    }

    float getTemp(void)
    {
    unsigned char PRESENCE;
    char temp1=0, temp2=0;
    PRESENCE=RESET_PULSE();
     if(PRESENCE==1)
     {
      send_byte(0xCC);
      send_byte(0x44);
      _delay_ms(800);
      PRESENCE=RESET_PULSE();
      send_byte(0xCC);
      send_byte(0xBE);
      temp1=read_byte();
      temp2=read_byte();
      PRESENCE=RESET_PULSE();
      float temp=0;
      temp=(float)(temp1+(temp2*256))/16*(-1);
      return temp;
     }
     else
     {
      return 0;
     }
    }


    int main()
    {
       float temperatura;
       char tekst[]="128";
       char bufor[8];
       LCD_init();
       LCD_control(ON, BLINK, SHOW);

       for(;;)
       {
          temperatura=getTemp();

          dtostrf(temperatura,1,1,bufor);
          LCD_clear();
          LCD_setpos(0);
          LCD_putstring(bufor);
          _delay_ms(1000);
       }
    }



    Dodam, że zmieniłem też zegar na 1Mhz wewnętrzny. Siedzę już nad tym kilka dni więc jeśli ktoś mógłby mi pomóc to będę bardzo wdzięczny.

    0
  • #14 16 Paź 2009 14:36
    tmf
    Moderator Mikrokontrolery Projektowanie

    Tym razem read jest zle napisane - zauwaz, ze petla + wczesniejsze opoznienia trwa co najmniej 63us, czyli czasami moze czytac 0 jako 1. Poza tym po co w petli to czytasz? Juz bym zrozumial gdybys zrobil jakies odszumianie, ale tak zwracasz ostatnia przeczytana wartosc. Odstepy pomiedzy bitami sa ciagle za krotkie - czemu nie probkujesz kiedy linia wroci do "1"? I najwazniejsze - zle wstawiasz bity w procedurze read_byte, ma byc >> a nie <<. Dla porownania rzuc okiem na moje dzialajace procedury:
    http://idom.svn.sourceforge.net/viewvc/idom/I2C/src/1wire.c?revision=63&view=markup

    0
  • #15 19 Paź 2009 14:48
    lordadam
    Poziom 9  

    Zmiany poczynione jednak efekt ciągle ten sam :(

    Code:

    unsigned char RESET_PULSE(void)
    {
       unsigned char PRESENCE;
       
       CLEAR_1wire;
       _delay_us(500);
       SET_1wire;
       _delay_us(30);
       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(3);
       if (bit==1)SET_1wire;
          _delay_us(60);
          SET_1wire;
    }

    unsigned char read()
    {
       unsigned char PRESENCE;
       CLEAR_1wire;
       _delay_us(3);
       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(100);
       }

    }

    unsigned char read_byte()
    {
       unsigned char i;
       unsigned char wartosc=0;

       for(i=0;i<8;i++)
       {
             wartosc>>=1;   
          if(read()) wartosc|=0x80;
          _delay_us(150);
       }
       return wartosc;
    }









    int main()
    {
       static char tekst[128]="OK";
       static char tekst2[128]="NO";
       unsigned char sprawdz;
       char temp1=0 , temp2=0;


             LCD_init();
              LCD_control(ON, BLINK, SHOW);
             

       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);

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

             sprawdz=RESET_PULSE();

             float temp=0;
             temp=(float)(temp1+(temp2*256))/16;
               
             
             dtostrf(temp,1,1,buf);

             LCD_clear();
             LCD_setpos(0);
             LCD_putstring(buf);
          }
          else if (sprawdz==0)
          {
             LCD_clear();
             LCD_setpos(0);
             LCD_putstring(tekst2);
          }
       }
       
       return 0;
    }

    0
  • #16 21 Paź 2009 23:51
    beznazwie
    Poziom 10  

    Oryginalny kod, który napisałeś - wbrew temu, co piszą niektórzy - działa, pomimo pozornie błędnych opóźnień (pomijając tą dziwną wartość F_CPU). Dziś właśnie użyłem identycznego kodu (czyżby z pewnego pdf'a? :) ) i udało mi się wreszcie uruchomić swój termostat cyfrowy.

    Nie widzę w Twoim kodzie konfiguracji pinów. Pin, pod który masz podłączoną linię danych, ustaw w DDRD jako wyjście ze stanem początkowym 0 (w PORTD).

    0
  Szukaj w 5mln produktów