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

[ATmega8] [C] DS18B20 i problem z 1-wire

18 Lip 2009 22:58 3228 2
  • Poziom 1  
    Mam problem z prawidłowym ustawieniem protokołu 1-Wire dla czujnika DS18B20. Ustawiałem i zmieniałem już wiele razy ale dalej otrzymuje -1028,06 st C . Pracuje na ATmega8 z wew. kwarcem 1Mhz.

    Code:

    /* Szkielet prostego programu dla avr-gcc */

    #define F_CPU       1000000                     // 1MHz zegar procesora -> częstotliwość kwarcu



    #include <avr/io.h>
    #include <stdlib.h>
    #include <util/delay.h>
    #include <avr/pgmspace.h>
    #include "lcd_lib.h"


    //makra
    #define WE 0
    #define PORT1_WIRE PINB
    #define SET_1WIRE DDRB &=~_BV(WE)
    #define CLEAR_1WIRE DDRB |=_BV(WE)


    char buffer[8];

    //resetujemy magistrale
    unsigned char RESET_PULSE(void)
    {
       unsigned char PRESENCE;
       CLEAR_1WIRE;
       _delay_us(500);
       SET_1WIRE;
       _delay_us(30);

       if( bit_is_clear(PORT1_WIRE , WE ) )
       {
          PRESENCE = 1;
       }
       else
       {
          PRESENCE = 0;
       }
       
       _delay_us(470);

       if( bit_is_set( PORT1_WIRE , WE ) )
       {
          PRESENCE = 1;
       }
       else
       {
          PRESENCE = 0;
       }
       return PRESENCE;
    }

    void send(char value)
    {
       CLEAR_1WIRE;
       _delay_us(5);

       if( value == 1)
       {
          SET_1WIRE;
       }
       _delay_us(65);
       SET_1WIRE;
    }

    unsigned char read(void)
    {
       unsigned char PRESENCE;
       CLEAR_1WIRE;
       _delay_us(1);
       SET_1WIRE;
       _delay_us(10);

       if( bit_is_set(PORT1_WIRE , WE ) )
       {
          PRESENCE = 1;
       }
       else
       {
          PRESENCE = 0;
       }
       _delay_us(55);
       
       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);
    }

    void send_temp( char wartosc )
    {
       unsigned char i;
       unsigned char pom;

       for( i=0; i < 8; i++ )
       {
          pom = wartosc>>i;
          pom &= 0x01;
          
          if( pom == 1)
             LCDsendChar('1');
          else
             LCDsendChar('0');
       }

    }

    unsigned read_byte(void)
    {
       unsigned char wartosc;
       unsigned char i;

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




    int main(void)
    {
       char temp1 = 0, temp2 = 0;
       unsigned char sprawdz;



         LCDinit();
         LCDclr();
       LCDsendChar('a');
       LCDsendChar('b');

       _delay_ms(200);
         
       while(1)
       {
          sprawdz = RESET_PULSE();
          if( sprawdz == 1 )
          {
             send_byte(0xCC);
             send_byte(0x44);
             _delay_ms(750);

             sprawdz = RESET_PULSE();

             if( sprawdz == 1 )
             {
                LCDGotoXY(10,1);
                LCDsendChar('o');
                LCDsendChar('k');
             }   
             send_byte(0xCC);
             send_byte(0xBE);

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

             sprawdz = RESET_PULSE();
             LCDGotoXY(0,0);
             send_temp(temp2);
             send_temp(temp1);

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

             LCDGotoXY(0,1);
             LCDsendChar(buffer[0]);
             LCDsendChar(buffer[1]);
             LCDsendChar(buffer[2]);
             LCDsendChar(buffer[3]);
             LCDsendChar(buffer[4]);
             LCDsendChar(buffer[5]);
             LCDsendChar(buffer[6]);
             LCDsendChar(buffer[7]);

             _delay_ms(300);
          }
          else
          {
             LCDGotoXY(0,0);
             LCDsendChar('l');
             LCDsendChar('o');
             LCDsendChar('l');
          }
             
       }
    }
  • Poziom 25  
    Na szybko przeglądając kod, to nigdzie nie stosujesz podciągania portów. Np tutaj
    Code:
    void send(char value)
    
    {
       CLEAR_1WIRE;
       _delay_us(5);

       if( value == 1)
       {
          SET_1WIRE;
       }
       _delay_us(65);
       SET_1WIRE;
    }


    Robisz tylko SET_1WIRE, a więc ustawiasz kierunek na wyjściowy i nic więcej. Musisz też ustawić port w stan wysoki (albo nisko, w zależności od tego co chcesz wysłać). Poczytaj dokładnie specyfikację protokołu 1 wire.

    Ewentualnie tu masz moje jakieś stare funkcje do 1wire. Powinny działać. Ale nie gwarantuję. ;)

    Code:
    /* PORT & PIN CONFIGURATION*/
    
    #define OW_PIN      2
    #define OW_DIR      DDRB
    #define OW_OUT      PORTB
    #define OW_IN      PINB

    #define OW_WRITE   OW_DIR |= (1<<OW_PIN)
    #define OW_READ      OW_DIR &= ~(1<<OW_PIN)

    #define OW_WRITE_1   OW_OUT |= (1<<OW_PIN)
    #define OW_WRITE_0   OW_OUT &= ~(1<<OW_PIN)

    #define OW_IS_SET   (OW_IN & (1<<OW_PIN))
    #define OW_IS_CLEAR   (!(OW_IN & (1<<OW_PIN)))

    /*1 wire reset */
    uint8_t reset_1w(void)
    {
       uint8_t presence;   // zmienna obecnosci
       OW_WRITE;         // port w trybie wyjscia
       OW_WRITE_0;         // wyprowadzenie w stanie niskim
       _delay_us(480);      // czekaj 480us
       OW_READ;         // port w stanie wejscia
       _delay_us(20);      // czekaj 20us
       if(OW_IS_CLEAR)      // jeśli wyprowadznie w stanie niskim, to urzadzenie obecne
          presence=1;      // ustaw zmienna obecnosci
       else
          presence=0;
       _delay_us(480);      // czekaj 480us
       
       return presence;   // zwroc wartosc zmiennej obecnosci
    }

    uint8_t read_byte_1w(void)
    {
       uint8_t byte=0, i;   // zmienne pomocnicze
       for(i=0;i<8;i++)   // petla 8 razy
       {
          byte>>=1;      // przesun wynik o jeden bit w prawo
          OW_WRITE;      // port w trybie wyjscia
          OW_WRITE_0;      // wyprowadzenie w stanie 0
          _delay_us(1);   // czekaj 1us
          OW_READ;      // port w trybie wejscia
          _delay_us(1);   // czekaj 1us
          if(OW_IS_SET)   // sprawdz czy bit = 1
             byte |= (1<<7);   // jesli tak, to dodaj na koncu 1
          _delay_us(60);   // czekaj 60us
       }
       
       return byte;
    }

    void write_byte_1w(uint8_t byte)
    {
       uint8_t i;            // zmienna pomocnicza
       for(i=0;i<8;i++)      // petla 8 razy
       {
          if(byte & 0x01)      // sprawdz czy ostatni bit = 1
          {   
             /* write 1 */
             OW_WRITE;      
             OW_WRITE_0;
             _delay_us(10);
             OW_READ;
             _delay_us(70);
          }
          else
          {
             /* write 0 */
             OW_WRITE;
             OW_WRITE_0;
             _delay_us(70);
             OW_READ;
             _delay_us(10);
          }
          byte>>=1;
       }
    }
  • Poziom 15  
    Załączam sprawdzoną, działającą bibliotekę do 1-Wire. Opóźnienia są policzone dla kwarcu 16MHz. Skoro Ty wykorzystujesz kwarc 1MHz to wystarczy, że podzielisz przez 16 argumenty funkcji opóźniających. Jakbyś miał z tym problem to napisz. Gratis dorzucam też sprawdzoną i działającą funkcję do odczytu i konwersji temperatury z czujnika DS18B20.

    Code:
    // odczytanie temperatury na czujniku
    
    void odczytaj_temperature()
    {
       unsigned char lsb = 0;         // młodsze bity odczytane z czujnika temperatury      
       unsigned char msb = 0;         // starsze bity odczytane z czujnika temperatury
       unsigned char znak_temperatury;
       unsigned char zp99;
       owire_reset();               // sekwencja inicjalizująca
       owire_write_byte(0xCC);         // rozkaz pomiń ROM
       owire_write_byte(0x44);         // rozkaz konwertuj temperaturę
       owire_reset();
       owire_write_byte(0xCC);         // rozkaz pomiń ROM
       owire_write_byte(0xBE);         // rozkaz umożliwiający odczytanie temperatury
       lsb = owire_read_byte();      // odczytanie młodszych bitów temperatury
       msb = owire_read_byte();      // odczytanie starszych bitów temperatury
       znak_temperatury = 1;         // do określenia znaku temperatury
       // konwersja odczytanych z czujnika danych na temperaturę
       if(msb & 0x80)               // sprawdzenie znaku temperatury   
       {
          lsb ^= lsb;               // konwersja ujemnej temperatury
          msb ^= lsb;
          if(lsb == 0xFF)
             msb = msb + 1;
          else
             lsb = lsb + 1;   
          znak_temperatury = 0;      // określa ujemny znak temperatury
       }
       zp1 = lsb & 0x0F;            // pozbycie się 4 najstarszych bitów(pozostała liczba wskazuje na wartości dzięsiętne temperatury)
       lsb  = lsb >> 4;            // pozbycie się 4 najmłodszych bitów
       msb  = msb << 4;            // pozbycie się 4 najstarszych bitów
       if(znak_temperatury == 0 && (lsb + msb) > 0)// ujemna temperatura
       {
          w_temperatura[0] = '-';
          zp99 = dBCD(lsb+msb) >> 4;;   // konwersja temperatury do kodu BCD i pozbycie się 4 najmodszych bitów
          if(zp99 != 0)            // temperatura <= -10
          {
             w_temperatura[1] = 48 + zp99;
             zp99 = dBCD(lsb+msb) & 0x0F;;// maska pozostawiająca 4 najmłodsze bity
             w_temperatura[2] = 48 + zp99;
             w_temperatura[3] = ',';
             zp1 = (zp1*625)/1000;   // wartości po ,
             w_temperatura[4] = 48 + zp1;
             w_temperatura[5] = 'º';     // stopień
             w_temperatura[6] = 'C';         
          }
          else                  // temperatura > -10, < 0
          {
             zp99 = dBCD(lsb+msb) & 0x0F;
             w_temperatura[1] = 48 + zp99;
             w_temperatura[2] = ',';
             zp1 = (zp1*625)/1000;   // wartość po ,
             w_temperatura[3] = 48 + zp1;
             w_temperatura[4] = 'º';// stopień
             w_temperatura[5] = 'C';
          }
       }
       else                     // dodatnia temperatura
       {
          zp99 = dBCD(lsb+msb) >> 4;
          if(zp99 != 0)            // temperatura >= 10
          {
             w_temperatura[0] = 48 + zp99;
             zp99 = dBCD(lsb+msb) & 0x0F;// maska pozostawiająca 4 najmłodsze bity
             w_temperatura[1] = 48 + zp99;
             w_temperatura[2] = ',';
             zp1 = (zp1*625)/1000;   // wartość po ,
             w_temperatura[3] = 48 + zp1;
             w_temperatura[4] = 'º';// stopień
             w_temperatura[5] = 'C';
          }
          else                  // temperatura >= 0, < 10
          {
             zp99 = dBCD(lsb+msb) & 0x0F;
             w_temperatura[0] = 48 + zp99;
             w_temperatura[1] = ',';
             zp1 = (zp1*625)/1000;   // wartosć po ,
             w_temperatura[2] = 48 + zp1;
             w_temperatura[3] = 'º';
             w_temperatura[4] = 'C';
          }
       }
    }

    Otrzymana temperatura jest zapisywana do tablicy w kodzie ASCII. Przerobisz sobie do postaci jaka będzie Ci odpowiadała.

    Tak jak pisałem wcześniej wszystko jest sprawdzone. Jedyna rzecz, do której ktoś bardziej dociekliwy może się przyczepić jest to, że w funkcji odczytującej temperaturę z czujnika nie ma opóźnienia 750ms, które potrzebne jest czujnikowi na konwersję temperatury. Nie umieściłem tego opóźnienia świadomie bo zatrzymanie programu na tak długi okres czasu w przypadku mojego programu robiło dużą różnicę. Nie wstawiając opóźnienia nie miałem wyniku pomiaru z danej chwili a z wcześniejszego pomiaru ale nie traciłem czasu na czekanie na konwersję temperatury. Nie potrzebowałem takiej dokładności więc jeżeli będziesz potrzebował to wstawisz sobie te opóźnienie.