Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

Atmega8 + termometr cyfrowy ds1820

adams03 18 Aug 2007 22:28 5131 12
  • #1
    adams03
    Level 12  
    Witam serdecznie. Mam problem z ds1820. Mianowicie po zaprogramowaniu procka "ustawieniu wewnętrznego oscylatora na 8Mhz" programem przedstawionym poniżej wyświetla mi cały czas że "t1=+85.0`C". Proszę o pomoc. Z góry serdecznie dziękuje.

    Quote:

    #include <mega8.h>

    // 1 Wire Bus functions
    #asm
    .equ __w1_port=0x12 ;PORTD
    .equ __w1_bit=3
    #endasm
    #include <1wire.h>
    #include <ds1820.h>
    #include <delay.h>
    #include <stdio.h>

    char lcd_buffer[33];
    // DS1820 Temperature Sensor functions
    #include <ds1820.h>

    // maximum number of DS1820 devices
    // connected to the 1 Wire bus
    #define MAX_DS1820 8
    // number of DS1820 devices
    // connected to the 1 Wire bus
    unsigned char ds1820_devices;
    // DS1820 devices ROM code storage area,
    // 9 bytes are used for each device
    // (see the w1_search function description in the help)
    unsigned char ds1820_rom_codes[MAX_DS1820,9];
    unsigned char rom_code[MAX_DS1820,9];
    // Alphanumeric LCD Module functions
    #asm
    .equ __lcd_port=0x12 ;PORTD
    #endasm
    #include <lcd.h>

    // Declare your global variables here

    void main(void)
    {

    unsigned char i,j,devices;
    int temp;
    // Declare your local variables here

    // Input/Output Ports initialization
    // Port B initialization
    // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
    // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
    PORTB=0x00;
    DDRB=0x00;

    // Port C initialization
    // Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
    // State6=T State5=T State4=T State3=T State2=T State1=T State0=T
    PORTC=0x00;
    DDRC=0x00;



    // Port D initialization
    // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
    // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
    PORTD=0x00;
    DDRD=0x00;

    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: Timer 0 Stopped
    TCCR0=0x00;
    TCNT0=0x00;

    // Timer/Counter 1 initialization
    // Clock source: System Clock
    // Clock value: Timer 1 Stopped
    // Mode: Normal top=FFFFh
    // OC1A output: Discon.
    // OC1B output: Discon.
    // Noise Canceler: Off
    // Input Capture on Falling Edge
    TCCR1A=0x00;
    TCCR1B=0x00;
    TCNT1H=0x00;
    TCNT1L=0x00;
    ICR1H=0x00;
    ICR1L=0x00;
    OCR1AH=0x00;
    OCR1AL=0x00;
    OCR1BH=0x00;
    OCR1BL=0x00;

    // Timer/Counter 2 initialization
    // Clock source: System Clock
    // Clock value: Timer 2 Stopped
    // Mode: Normal top=FFh
    // OC2 output: Disconnected
    ASSR=0x00;
    TCCR2=0x00;
    TCNT2=0x00;
    OCR2=0x00;

    // External Interrupt(s) initialization
    // INT0: Off
    // INT1: Off
    MCUCR=0x00;

    // Timer(s)/Counter(s) Interrupt(s) initialization
    TIMSK=0x00;

    // Analog Comparator initialization
    // Analog Comparator: Off
    // Analog Comparator Input Capture by Timer/Counter 1: Off
    ACSR=0x80;
    SFIOR=0x00;

    // Determine the number of DS1820 devices
    // connected to the 1 Wire bus
    ds1820_devices=w1_search(0xf0,ds1820_rom_codes);

    // LCD module initialization
    lcd_init(16);
    lcd_putsf("CodeVisionAVR\n1 Wire Bus Demo");
    delay_ms(2000);
    lcd_clear();
    devices=w1_search(0xf0,rom_code);
    sprintf(lcd_buffer,"%u DS1820\nDevice detected",devices);
    lcd_puts(lcd_buffer);
    delay_ms(2000);

    if (devices)
    {
    for (i=0;i<devices;i++)
    {
    sprintf(lcd_buffer,"Device #%u ROM\nCode is:",i+1);
    lcd_clear();
    lcd_puts(lcd_buffer);
    delay_ms(2000);
    lcd_clear();
    for (j=0;j<8;j++)
    {
    sprintf(lcd_buffer,"%02X ",rom_code[i][j]);
    lcd_puts(lcd_buffer);
    if (j==3) lcd_gotoxy(0,1);
    };
    delay_ms(5000);
    };
    }
    else
    while (1); /* stop here if no devices were found */

    /* measure and display the temperature(s) */
    while (1)
    {
    for (i=0;i<devices;)
    {
    temp=ds1820_temperature_10(&rom_code[i][0]);
    j='+';
    if (temp<0)
    {
    j='-';
    temp=-temp;
    };
    sprintf(lcd_buffer,"t%u=%c%i.%u\xdfC",++i,j,temp/10,temp%10);
    lcd_clear();
    lcd_puts(lcd_buffer);
    delay_ms(800);
    };
    };
    }
  • #2
    aster11
    Level 19  
    Na pierwszy rzut oka dostrzegłem prawdopodobnie nieświadomy błąd w definicji tablic:

    Code:
    unsigned char ds1820_rom_codes[MAX_DS1820,9]; 
    
    unsigned char rom_code[MAX_DS1820,9];


    Tak zadeklarowane tablice są jednowymiarowe (zobacz na znaczenie operatora <przecinek> w C). Prawie na pewno chodziło Ci o to:

    Code:
    unsigned char ds1820_rom_codes[MAX_DS1820][9]; 
    
    unsigned char rom_code[MAX_DS1820][9];


    ... ale nie wiem, czy ta poprawka pomoże w całkowitym rozwiązaniu problemu.
  • #3
    adams03
    Level 12  
    Sprawdziłem tą deklaracje i jest ok. Wyświetla mi poprawnie id dsa. Jeśli by to była błędnie zdeklarowana tablica to by w ogóle nie wyświetlał informacji ze znalazł urządzenie. Pozdrawiam.
  • #4
    aster11
    Level 19  
    Wziąłeś ten programik gotowy, czy sam napisałeś? Tablice są źle zdefiniowane, jako jednowymiarowe (znam język C)! - to nie ulega wątpliwości. Może "ponaginałeś" program w innych miejscach tak, aby dobrze dział ze złymi tablicami, a teraz nie działa z dobrymi :D

    Najlepiej wklej plik ds1820.h, zobaczymy jakich argumentów oczekują funkcje.
  • #5
    adams03
    Level 12  
    Proszę bardzo.

    Quote:


    #ifndef _DS1820_INCLUDED_
    #define _DS1820_INCLUDED_

    #include <1wire.h>

    #define DS1820_FAMILY_CODE 0x10
    #define DS1820_SEARCH_ROM_CMD 0xf0
    #define DS1820_ALARM_SEARCH_CMD 0xec

    #pragma used+
    extern struct __ds1820_scratch_pad_struct
    {
    unsigned char temp_lsb,temp_msb,
    temp_high,temp_low,
    res1,res2,
    cnt_rem,cnt_c,
    crc;
    } __ds1820_scratch_pad;

    unsigned char ds1820_select(unsigned char *addr);
    unsigned char ds1820_read_spd(unsigned char *addr);
    int ds1820_temperature_10(unsigned char *addr);
    unsigned char ds1820_set_alarm(unsigned char *addr,signed char temp_low,signed char temp_high);
    #pragma used-

    #pragma library ds1820.lib

    #endif




    wyświetlam sobie na lcd wartość adresu z pozycji " &rom_code[0][2] " i jest ok zgadza sie z stanem faktycznym. Tak że tablice są dobrze zadeklarowane sprawdzalem tak jak napisałeś i tak zostawiłem.

    Dodano po 49 [minuty]:

    Problem sam się rozwiązał. Trzeba zwrócić uwagę na montaż dsa. Musi być doprowadzone zewnętrzne zasilanie :]. Za pomoc serdeczne dzięki. Pozdrawiam adams03.
  • #6
    Mad Bekon
    Level 23  
    Zewnętrzne zasilanie być nie musi.
    Z tym, że jeśli się zasila po linii danych, to trzeba dość często ustawiać na niej stan wysoki w momencie braku transmisji. Wsio jest w PDFie DS'a

    A swoją drogą, mógłbyś podrzucić tutaj plik 1wire.c i 1wire.h?
  • #7
    aster11
    Level 19  
    Zaintrygowała mnie ta Twoja deklaracja:

    Code:
    unsigned char ds1820_rom_codes[MAX_DS1820,9]; 
    
    unsigned char rom_code[MAX_DS1820,9];


    - żaden z moich kompilatorów C, w tym WinAVR, tego nie przetrawi.
    Jakiego kompilatora używasz :?:

    Kod programu wygląda na "zapożyczony" i lekko zmodyfikowany, a nie utworzony przez "Polaka" (Ciebie) - ale może się mylę.
    Wygląda jednak na to, że wspomniane deklaracje tworzą tablice dwuwymiarowe. Inaczej (jak sprawdzałem) kompilator nie pozwoliłby odnieść się do tablicy jednowymiarowej jako dwuwymiarowej. W nawiasach deklarujących rozmiar tablicy wymagane jest wyrażenie stałe (o wartości całkowitej, znanej na etapie kompilacji) i (jak też sprawdzałem) nie są standardowo dopuszczalne wartości oddzielone przecinkiem (błąd kompilacji). Zatem przecinek nie działa tu jako standardowy operator <przecinek> (błędnie nie dopatrzyłem tego we wcześniejszym poście - przepraszam) i prawdopodobnie został dla niego wprowadzony nowy kontekst, pozwalający na alternatywną składnię deklaracji tablicy wielowymiarowej (jakkolwiek bardzo mylną w przypadku języka C) - wykorzystaną w danym kompilatorze lub przy danych opcjach kompilacji.

    Deklaracja o standardowej składni, którą próbowałem Ci wcześniej narzucić, powinna dać w rezultacie identyczne działanie programu.

    Może zdradzisz jakiego kompilatora (albo specjalnej opcji kompilacji) użyłeś ?
  • #8
    nojmi
    Level 20  
    Mi to wygląda na CodeVisionAVR.
    Koledzy co do tablicy mają rację. Wklejam przykład oprogramowania DS1820 z examles:
    Code:

    AN 4.7k PULLUP RESISTOR MUST BE CONNECTED
       BETWEEN DQ (PA6) AND +5V !
    */
    #asm
        .equ __w1_port=0x1b
        .equ __w1_bit=6
    #endasm

    /* Use an 2x16 alphanumeric LCD connected
       to PORTC as follows:

      [LCD]   [STK500 PORTC HEADER]
       1 GND- 9  GND
       2 +5V- 10 VCC 
       3 VLC- LCD contrast control voltage 0..1V
       4 RS - 1  PC0
       5 RD - 2  PC1
       6 EN - 3  PC2
      11 D4 - 5  PC4
      12 D5 - 6  PC5
      13 D6 - 7  PC6
      14 D7 - 8  PC7
    */

    #asm
        .equ __lcd_port=0x15
    #endasm

    #include <lcd.h> // LCD driver routines
    #include <ds1820.h>
    #include <delay.h>
    #include <stdio.h>

    char lcd_buffer[33];

    /* maximum number of DS1820/DS18S20 connected to the 1 Wire bus */
    #define MAX_DEVICES 8

    /* DS1820/DS18S20 devices ROM code storage area */
    unsigned char rom_code[MAX_DEVICES][9];

    main()
    {
    unsigned char i,j,devices;
    int temp;

    lcd_init(16);
    lcd_putsf("CodeVisionAVR\n1 Wire Bus Demo");
    delay_ms(2000);
    lcd_clear();

    /* detect how many DS1820/DS18S20 devices
       are connected to the 1 Wire bus */
    devices=w1_search(0xf0,rom_code);
    sprintf(lcd_buffer,"%u DS1820\nDevice detected",devices);
    lcd_puts(lcd_buffer);
    delay_ms(2000);

    /* display the ROM codes for each device */
    if (devices)
       {
       for (i=0;i<devices;i++)
           {
           sprintf(lcd_buffer,"Device #%u ROM\nCode is:",i+1);
           lcd_clear();
           lcd_puts(lcd_buffer);
           delay_ms(2000);
           lcd_clear();
           for (j=0;j<8;j++)
               {
               sprintf(lcd_buffer,"%02X ",rom_code[i][j]);
               lcd_puts(lcd_buffer);
               if (j==3) lcd_gotoxy(0,1);
               };
           delay_ms(5000);
           };
       }
    else
    while (1); /* stop here if no devices were found */

    /* measure and display the temperature(s) */       
    while (1)
          {
          for (i=0;i<devices;)
              {
              temp=ds1820_temperature_10(&rom_code[i][0]);
              j='+';
              if (temp<0)
                 {
                 j='-';
                 temp=-temp;
                 };
              sprintf(lcd_buffer,"t%u=%c%i.%u\xdfC",++i,j,temp/10,temp%10);
              lcd_clear();
              lcd_puts(lcd_buffer);
              delay_ms(800);
              };
          };
    }


    Tablice są tu tradycyjnie zadeklarowane:
    unsigned char rom_code[MAX_DEVICES][9];
  • #9
    aster11
    Level 19  
    Rzeczywiście CodeVisionAVR. Nigdy tego środowiska wcześniej nie wykorzystywałem, ale teraz zainstalowałem z ciekawości. Faktycznie kompilator dopuszcza definicje tablic wielowymiarowych o składni:
    Code:
    <type> <name>[<dim1>, <dim2>, ..., <dimN>];

    co działa równoważnie do definicji:
    Code:
    <type> <name>[<dim1>][<dim2>]...[<dimN>];

    Odniesienie się w podobny sposób do elementów tablic wielowymiarowych nie jest możliwe, gdyż z oczywistych względów łamałoby to podstawowe zasady składni języka C.
    W przypadku definicji, alternatywna możliwość obsadziła istniejącą "lukę składniową", dla której kompilatory standardowo zgłaszają błąd. W dokumentacji nie spotkałem (przeglądałem dość pobieżnie) wzmianki na ten temat. Może producent dodał taką opcję "po cichu", a może powstała ona jako swego rodzaju efekt uboczny.

    Nigdy nie przyszłoby mi do głowy tak definiować tablice w C, stąd moje początkowe oburzenie. Sprawdza się klasyczne powiedzenie (bez urazy dla adams03), że człowiek jest zdolny dokonać tym genialniejszego odkrycia, im mniej jest skażony wiedzą! :D
  • #10
    adams03
    Level 12  
    Zgadzam się w zupełności. Problem nie polegał na deklaracji tablicy " wiem jak się deklaruje tablice dwuwymiarowe, moje przeoczenie :], o dziwo działa " a mianowicie na podłączeniu dsa. Czym jest spowodowany fakt iż nie dostarczając napięcia do dsa " pracując w konfiguracji dwóch linii danych z podciągnięciem i masa " na pc czujnik działa ok a po podłączeniu do up nie można odczytać danych? Komunikacja jest poprawna ponieważ jest możliwe odczytanie id dsa.

    Pozdrawiam adams03.
  • Helpful post
    #11
    aster11
    Level 19  
    Quote:
    Czym jest spowodowany fakt iż nie dostarczając napięcia do dsa " pracując w konfiguracji dwóch linii danych z podciągnięciem i masa " na pc czujnik działa ok a po podłączeniu do up nie można odczytać danych? Komunikacja jest poprawna ponieważ jest możliwe odczytanie id dsa.

    Ogólnie tym, że połączenie w trybie dwuprzewodowym (pasożytniczym) wymaga bardziej starannego opracowania obsługi magistrali 1-wire, aby wszystko działało OK. W szczególności dla DS18B20:

    1. Należy zastosować silne podciąganie na czas konwersji.
    2. Nie należy pozostawiać linii danych (i jednocześnie zasilania) w stanie niskim na czas dłuższy, niż to wymagane dla czynności komunikacyjnych - zwłaszcza pomiędzy operacją konwersji i odczytu temperatury!

    Trochę naprodukowałem się już o tym w tym poście:
    https://www.elektroda.pl/rtvforum/topic816435.html
    poza tym pewnie znajdziesz inne posty na ten sławetny temat na tym forum, a datasheet układu jest do tego cudowną skarbnicą informacji.

    W praktyce będziesz musiał prawdopodobnie zaingerować w funkcję ds1820_temperature_10(), a może też w inne funkcje obsługi 1-wire. Jednak nie mam żadnego doświadczenia z CodeVisionAVR, a widze, że 1-wire jest tam dość mocno wspierane - może wystarczy więc coś tylko prosto przekonfigurować? - na to jednak nie potrafię odpowiedzieć.

    Jeżeli kod obsługi magistrali 1-wire napisany jest porządnie, może wystarczyć prosty eksperyment sprzętowy, polegający na zmniejszeniu rezystancji podciągającej do wartości ok. 2k.
  • #12
    firefox_PL
    Level 17  
    Taka informacja, co do samego DS1820 temperatura 85C to jest pierwszy "fałszywy" odczyt zaraz po inicjalizacji ale jeszcze przed prawdziwym odczytem, temperatura ta jest po prostu zapisana w jego flash'u i zawsze jest jako pierwszy odczyt (tylko na ogół tego nie widać jak czujnik robi ileś tam odczytów na sekundę). Fakt że ona się nie zmienia, zakładając że nic nie pozmieniałeś z bibliotekami CodeVision (też go używałem z tym czujnikiem i zawsze wszystko mi działało bez żadnych modyfikacji), wskazuje wg mnie na awarie czujnika (ja przegrzałem parę takich czujników przy lutowaniu ich do kabelków (i przez to raz w ogóle nie inicjalizowały się, ale na ogół po prostu wyświetlały właśnie 85C), zatem spróbuj z innym modelem, jeśli masz takowy "pod ręką"
  • #13
    adnix
    Level 12  
    To było dość dawno ale może komuś przyda się rozwiązanie.
    Błąd wynika z faktu, że czujniki DS18S20 mają wolniejszy czas reakcji(konwersja pomiaru na temperaturę) wynoszący 750ms. Rozwiązaniem jest dodanie w pliku diigtemp.conf wiersza:
    Code:
    READ_TIME 1500
    

    W moim układzie po takiej modyfikacji błędy zniknęły.