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.

konwersja temperatury ds18b20

25 Kwi 2005 12:29 4040 7
  • Poziom 18  
    witajcie. mam problem z konwersj± temperatury na czujniku ds18b20

    wszystko jak w manualu, ale...

    1wire działa dobrze. vcc jest zewnętrzne, data jest podpięte do portu i do vcc poprzez rezystor 4.7K jak w datasheet. uklad dziala, ale pokazuje temperatury o jakie¶ 80 stopni C za niskie. to znaczy jak w pokoju mam 20 stopni, to na lcd mam -60 (około). wyniki s± powtarzalne.

    jak przytrzymam czujnik palcami, temperatura wzrasta, dochodzi do 0 a potem (tempoeratura ro¶nie) cofa się od 128 (już na plusie) do dołu.

    nie jest to wina czujnika, bo kupiłem 2 i dzieje się to samo. ogólnie działa to sprawnie, ale odniesienia do rzeczywisto¶ci brak. wydaje mi się ze z programem co¶ nie tak, ale podobno jest dobry (przysłał mi go kolega z elektrody -> któremu dziekuje raz jeszcze).

    poradĽcie co¶ prosze!!
    sdzięki
    dmz
  • Pomocny post
    Poziom 19  
    Podejrzewam, ze jest jakis bład w algorytmie interpretacji odczytanych ajtów z termometru. Z ciekawosci wlazlem na

    http://pdfserv.maxim-ic.com/en/ds/DS18B20.pdf

    i jest tam tabelka przykładowych wskazań dla wybranych temperatur. Nie znaj±c programu niemożliwe jest powiedzenie czegos wiecej.

    pozdrawiam
  • Poziom 18  
    plik numer 1wire.c
    Code:

    #include <avr/io.h>
    #include <avr/pgmspace.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <math.h>
    #include <stdlib.h>
    #include <stddef.h>
    #include  "my_lib.h"


    unsigned char wiersz=0;
    unsigned char kolumna=0;

    int main(void)
    {
    lcd_init();
    char *tekst1=PSTR("Temp:");
    char *tekst2=PSTR("C");
    char *tekst3=PSTR("nie ma");

    //while(1){
    while(exist1w()){

    write1w(0xCC);
    write1w(0x44);
    waitms(1000);
    reset1w();
    write1w(0xCC);
    write1w(0xBE);
    unsigned char wynik1=0;
    unsigned char wynik2=0;
    wynik1=read1w();
    wynik2=read1w();
    reset1w();
    float temp=0;
    if((wynik2)!=0){       //temp ujemna
    wynik1=~wynik1;
    temp=wynik1+1;
    temp=-temp/2;
    }
    else{                //temp dodatnia
    if(wynik1>0xAA) break;
    temp=wynik2;
    temp=temp*8;
    temp=temp+wynik1;
    temp=-temp/2;
    }
    pisz_tekst_xy(tekst1,0,0);
    piszliczba_float_xy(temp,1,0);
    lcdxy(0,12);
    piszdlcd(0xDF);          //znak stopni
    //pisz_tekst_xy(tekst2,1,5);

    //pisz_tekst_xy(wynik2,0,0);


    }
    return(0);
    }


    Dodano po 1 [minuty]:

    Code:

    //deklaracje wszystkich funkcji
    unsigned char exist1w(void);   
    void reset1w(void);
    void slot_wyslij1w(unsigned char znak);
    void write1w(unsigned char dana);
    unsigned char slot_odbierz1w(void);
    unsigned char read1w(void);
    void waitus(unsigned char czas);
    void waitms(unsigned int czas);
    void piszilcd(unsigned char instr);
    void piszdlcd(char dana);
    void czysclcd(void);
    void piszznak(char znak);
    void piszliczba_int_xy(unsigned char l, unsigned char w, unsigned char k,unsigned char system);
    void piszliczba_float_xy(float l, unsigned char w, unsigned char k);
    void lcdxy(unsigned char w, unsigned char k);
    void pisztekst(char *tekst);
    void lcd_init(void);
    void pisz_tekst_xy(char *tekst,unsigned char w, unsigned char k);
    extern unsigned char wiersz;
    extern unsigned char kolumna;


    //definicje funkcji
    //--------------------------------------------------------------------------------------------------
    //                           1WIRE
    //funkcje napisane w C++ do obsługi urzadzen 1wire, nazewnictwo funkcji na wzor Bascoma...

    #define PIN1w PINC            //definicje dotyczace portu do ktorego podlaczone jest urzadzenie 1wire
    #define DDR1w DDRC
    #define PORT1w PORTC
    #define PIN PC5            
    unsigned char exist1w(void){   //sprawdzanie czy urzadzenie 1wire jest podł±czone do procesora
    cbi(PORT1w,PIN);            //zwraca 1 jesli wszysko ok, w przeciwnym wypadku zwraca zero
    sbi(DDR1w,PIN);               //stan 0   
    waitus(250);
    waitus(250);
    cbi(DDR1w,PIN);               //stan 1
    waitus(75);
    if(bit_is_clear(PIN1w,PIN)){waitus(250); waitus(250); return 1;}
    else{waitus(250); waitus(250); return 0;}
    }

    void reset1w(void){         //reset urzadzenia 1wire
     cbi(PORT1w,PIN);
     sbi(DDR1w,PIN);      
     waitus(250);
     waitus(250);
     cbi(DDR1w,PIN);
     waitus(75);
     waitus(250);
     waitus(250);
     }

    void slot_wyslij1w(unsigned char znak){   //wysyła bit 0 lub 1 do urzadzenia 1wire
       if(znak==1){                     //organizujac transmisje bitu w slot czasowy
       cbi(PORT1w,PIN);                  //jest to podfunkcja wywoływana w funkcji 1wwrite
       sbi(DDR1w,PIN);                     //stan 0
       waitus(6);
       cbi(DDR1w,PIN);                     //stan 1 i probkowanie przez urzadzenie 1wire
       waitus(64);                        //czekaj az minie czas slotu
       }
       else{
       cbi(PORT1w,PIN);
       sbi(DDR1w,PIN);                     //stan 0
       waitus(70);
       cbi(DDR1w,PIN);                     //stan 1
       }
     }

    void write1w(unsigned char dana){         //wysyła instrukcje do urzadzenia 1wire
     unsigned char i;                     //jako argument podajemy numer instrukcji
       for(i=0;i<8;i++){                  //np. 0x33 - co oznacza read rom
       slot_wyslij1w(dana&0x01);
       dana>>=1;
       }
     }

    unsigned char slot_odbierz1w(void){      //odbiera bit nadany przez urz. 1wire
    unsigned char bit1w=0;               //w jednym slocie czasowym
    cbi(PORT1w,PIN);                     //jest podfunkcj± funkcji 1wread
    sbi(DDR1w,PIN);                        //stan 0
    waitus(2);
    cbi(DDR1w,PIN);                        //stan 1
    waitus(2);
    if(bit_is_clear(PIN1w,PIN)) bit1w=0;
    else bit1w=1;
    waitus(70);
    return bit1w;
    }

    unsigned char read1w(void){            //odbiera jeden bajt danych od urzadzenia 1wire
    unsigned char dana=0;
    unsigned char j;
    for(j=0x01;j!=0;j=j<<1)
    dana|=slot_odbierz1w()?j:dana;
    return dana;
    }

    //--------------------------------------------------------------------------------------------------
    //                              TIMER0
    //procedury opoznienia wykorzystujace 8-bitowy timer0
    //funkcja opoznienia, jako argument czas w zakresie od 1 do 255 - nie mozna wiecej bo bedzie zle dzialac!!!
    //czas podajemy w mikrosekundach, jesli wpiszemy do argumentu 1 to odmierzanie 1us dla kwarcu 8MHz
    void waitus(unsigned char czas){      
    TCCR0=0x02;                        //zliczamy impulsy 1us dla fosc=8MHz, clk jest dzielony przez 8
    TCNT0=255-czas;
    while((inp(TIFR)&0x01)!=0x01);      //spr czy licznik przepelniony?
    sbi(TIFR,TOV0);                     //kasowanie flagi przepe-nienia
    }

                                  //funkcja opoznienia, czas w mikrosekundach
    void waitms(unsigned int czas){      //tutaj nie ma ograniczenia przedzialu czasu do 255 :-)
       for(;czas>0;czas--){
          unsigned char   x=10;
          for(;x>0;x--){               //petla 1000us=1ms
          TCCR0=0x02;                  //zliczamy impulsy 1us dla fosc=8MHz, clk/8
          TCNT0=155;
          while(bit_is_clear(TIFR,TOV0));//czy licznik przekrecony?
          TIFR=1<<TOV0;               //kasowanie flagi przepe-nienia
          }
       }
    }

    //--------------------------------------------------------------------------------------------------
    //                              OBSŁUGA LCD
                                  //Dane do lcd przesyłane sa przez 4 starsze bity portu
    #define PORTLCD PORTB               //definiuje do jakiego portu podlaczony LCD
    #define DDRLCD DDRB                  //definiuje rejestr DDR portu do ktorego dolaczony wy¶wietlacz
    #define lcd_rs 2                      //definicja bitu portu dla linii RS
    #define lcd_e 3                       //definicja bitu portu dla linii E
    #define CR 0x0a                       //definicja znaku CR (przej»cie do nowej linii)


    void piszilcd(unsigned char instr)    //zapisz instrukcjŕ steruj¦c¦ do LCD
    {
     cbi(PORTLCD,lcd_rs);
     sbi(PORTLCD,lcd_e);
     PORTLCD=(PORTLCD&0x0f)|(instr&0xf0);  //przygotuj starszy p·-bajt do LCD
     waitus(3);
     cbi(PORTLCD,lcd_e);                    //impuls strobuj¦cy
     waitus(100);
     sbi(PORTLCD,lcd_e);
     PORTLCD=(PORTLCD&0x0f)|((instr&0x0f)<<4); //przygotuj m-odszy p·-bajt do LCD
     waitus(3);
     cbi(PORTLCD,lcd_e);                    //impuls strobuj¦cy
     waitus(100);
    }

    void piszdlcd(char dana)                 //zapisz dan¦ do LCD
    {
     sbi(PORTLCD,lcd_rs);
     sbi(PORTLCD,lcd_e);
     PORTLCD=(PORTLCD&0x0f)|(dana&0xf0);   //przygotuj starszy p·-bajt do LCD
     waitus(3);
     cbi(PORTLCD,lcd_e);                   //impuls strobuj¦cy
     waitus(100);
     sbi(PORTLCD,lcd_e);
     PORTLCD=(PORTLCD&0x0f)|((dana&0x0f)<<4); //przygotuj m-odszy p·-bajt do LCD
     waitus(3);
     cbi(PORTLCD,lcd_e);                    //impuls strobuj¦cy
     waitus(100);
    }

    void czysclcd(void)                   //czy»© ekran
    {
     piszilcd(0x01);                     //polecenie czyszczenia ekranu dla kontrolera LCD
     waitms(2);
     wiersz=0;
     kolumna=0;
    }

    void piszznak(char znak)             //procedura umieszcza znak na wy»wietlaczu
    {
     piszdlcd(znak);                     //wy»wietl znak na LCD
     if(++kolumna==16)                   //czy bie¬¦ca kolumna mie»ci siŕ na wy»wietlaczu?
     {                         
      kolumna=0;                         //je»li nie, to ustaw pocz¦tkow¦...
      if(++wiersz==2)                    //i przejdč do nowego wiersza
      {
       wiersz=0;                         //je»li nowy wiersz jest poza wy»wietlaczem, ustaw pocz¦tkowy
      }
     }
    }

    void piszliczba_int_xy(unsigned char l, unsigned char w, unsigned char k,unsigned char system){
    piszilcd((w*0x40+k)|0x80);           //ustawienie kursora
    piszznak(' ');                     //wymazanie zbednych liczb na koncu
    piszznak(' ');
    piszznak(' ');
    piszznak(' ');
    piszilcd((w*0x40+k)|0x80);           //ustawienie kursora
       unsigned char *wsk;
       unsigned char buflcd[5];
       wsk=utoa(l,buflcd,system);
       while(*wsk) {
       piszdlcd(*wsk++);
       }
    }

    void piszliczba_float_xy(float l, unsigned char w, unsigned char k){
    piszilcd((w*0x40+k)|0x80);           //ustawienie kursora
    piszznak(' ');                     //wymazanie zbednych liczb na koncu
    piszznak(' ');
    piszznak(' ');
    piszznak(' ');
    piszznak(' ');
    piszznak(' ');
    piszilcd((w*0x40+k)|0x80);           //ustawienie kursora
       unsigned char *wsk;
       unsigned char buflcd[10];
       unsigned char width=0;
       wsk=dtostrf(l,width,1,buflcd);      //uwaga!!! zeby ta funkcja dzialala, to musi byc w pliku
       while(*wsk) {                  //makefile w 7 linijce LIBS=-lm
       piszdlcd(*wsk++);
       }
    }

    void lcdxy(unsigned char w, unsigned char k)    //ustaw wsp·-rzŕdne kursora
    {
     piszilcd((w*0x40+k)|0x80);           //standardowy rozkaz sterownika LCD
                                  //ustawiaj¦cy kursor w okre»lonych wsp·-rzŕdnych
    }

    void pisztekst(char *tekst)           //pisz tekst na LCD wskazywany pointerem *tekst
    {
     char zn;
     char nr=0;
     while(1)
     {
      zn=PRG_RDB(&tekst[nr++]);           //pobranie znaku z pamiŕci programu
      if(zn!=0)                           //czy nie ma ko˝ca tekstu?
      {
       if(zn==CR)                         //czy znak nowej linii
       {
        wiersz==1?wiersz=0:++wiersz;       //przejdč do nowej linii
        kolumna=0;
        lcdxy(wiersz,kolumna);            //ustaw obowi¦zuj¦ce po zmianie wsp·-rzŕdne na LCD
       }
       else
       {
        piszdlcd(zn);                     //umie»© pojedynczy znak tekstu na LCD
       }
      }
      else
      {
       break;                             //zako˝cz pŕtlŕ, je»li koniec tekstu
      }
     }
    }

    void lcd_init(void){
     PORTLCD=0x03;                     //port z podci¦ganiem
     DDRLCD=0xff;                      //PORTLCD - jako wyj¶ciowy
     waitms(45);
     unsigned char i;
     for(i=0;i<3;i++)                   //3-krotne wys-anie 3-
     {
      sbi(PORTLCD,lcd_e);
      PORTLCD=(PORTLCD&0x0f)|0x30;       //wy»lij 3- do LCD
      asm("nop");
      asm("nop");
      asm("nop");
      cbi(PORTLCD,lcd_e);
      waitms(5);
     }
     sbi(PORTLCD,lcd_e);
     PORTLCD=(PORTLCD&0x0f)|0x20;        //wy»lij 2- do LCD
     asm("nop");                        //wymagane wyd-u¬enie impulsu
     asm("nop");
     asm("nop");
     cbi(PORTLCD,lcd_e);
     waitus(100);
     piszilcd(0x28);                    //interfejs 4-bitowy, 2 linie, znak 5x7
     piszilcd(0x08);                    //wy-¦cz LCD, wy-¦cz kursor, wy-¦cz mruganie
     piszilcd(0x01);                    //czy»© LCD
     waitms(2);
     piszilcd(0x06);                    //bez przesuwania w prawo
     piszilcd(0x0c);                   //w-¦cz LCD, w-¦cz kursor, w-¦cz mruganie
    }

    void pisz_tekst_xy(char *tekst,unsigned char w, unsigned char k)  //pisz tekst na LCD wskazywany pointerem *tekst
    {
    piszilcd((w*0x40+k)|0x80);
    char zn;
    char nr=0;
    while(1){
    zn=PRG_RDB(&tekst[nr++]);           
       if(zn!=0){
       piszdlcd(zn);                     
       }
       else{
       break;                             
       }
    }
    }
    [/code]
  • VIP Zasłużony dla elektroda
    Może Reset 1Wire przed Skip ROM (0xCC) i Convert T (0x44) ?
  • Pomocny post
    Poziom 39  
    A co to za cudaczne obliczenia :wink:
    Code:

    ...
    unsigned char wynik1=0;
    unsigned char wynik2=0;
    wynik1=read1w();
    wynik2=read1w();
    reset1w();
    float temp=0;
    if((wynik2)!=0){       //temp ujemna
    wynik1=~wynik1;   
    temp=wynik1+1;     //dlaczego /2 i gdzie się podział wynik2 ?
    temp=-temp/2;       //???
    }
    else{                //temp dodatnia
    if(wynik1>0xAA) break;
    temp=wynik2;
    temp=temp*8;     //dlaczego *8 ?
    temp=temp+wynik1;
    temp=-temp/2;  //???
    }
    ...

    Proponuję po "mikroprocesorowemu"
    Code:

    unsigned char wynik1=0;
    unsigned char wynik2=0;
    wynik1=read1w();
    wynik2=read1w();
    reset1w();
    float temp=0;
    temp=wynik1+(wynik2*256);
    temp=temp/16;
    //teraz już tylko "*char=dtostrf(temp,0,1,buffer)" ....

    I masz swoje stopnie z dziesiętnymi i znakiem liczby na dokładkę.

    Pozdrawiam
    Piotrek
  • Poziom 18  
    niestety do bascoma sie nie dobrałem jeszcze. pisze w c. bo podobno jest szybszy.
    dzieki za podpowiedz.

    dmz
  • Poziom 18  
    zumek -> masz racje. z twoj± procedur± działa. całkiem dokladnie.
    do dziesi±tek stopnia.

    tylk mam wrazenie ze DS cos nieskalibrowany, bo jakby zawyża temp o 3 stopnie(tak mi sie zdaje), ale tu odejmuję od wyniku 3 stopnie i jest OK.

    teraz czeka mnie zabawa z odczytem wielu czujników na jednej linii :)

    Dzięki stokrotne wszystkim za pomoc!!!

    Dmz