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

attiny2313 + ds18b20 brak polaczenia 1wire

03 Sie 2005 13:45 3070 10
  • Poziom 13  
    Witam. Przejrzalem CALE forum w poszukiwaniu rozwiazania mojego problemu. Probowalem wszystkiego co bylo podane w postach. Mam problem z polaczeniem tn2313 z ds18b20.
    zegar: kwarc 4MHz (testowalem juz na wew 1-8MHz bez rezultatow - ckdiv8 konfigurowalem poprawnie 1dis 0 en)
    podlaczam do portu d pod rozne piny. Od strony programowej tez powinno byc all ok. Calosc napisana zostala w winavr. Oto listing:

    Code:
    #include <stdlib.h>
    
    #include <avr/io.h>

    #define F_CPU 4000000
    #define CYCLES_PER_US ((F_CPU+500000)/1000000)

    //

    #define LCD  PORTB
    #define E  2
    #define RW  1
    #define RS  0
    //
    #define SET_E   LCD |= _BV(E)
    #define CLR_E   LCD &= ~_BV(E)
    //
    #define SET_RW   LCD |= _BV(RW)
    #define CLR_RW   LCD &= ~_BV(RW)

    //
    #define SET_RS  LCD |= _BV(RS)
    #define CLR_RS  LCD &= ~_BV(RS)

    //


    #define PIN1w PIND            //definicje dotyczace portu do ktorego podlaczone jest urzadzenie 1wire
    #define DDR1w DDRD
    #define PORT1w PORTD
    #define PIN 1

    #define wire0 PORT1w&=~(1<<PIN)
    #define wire1 PORT1w|=1<<PIN
    #define input DDR1w&=~(1<<PIN)
    #define output DDR1w|=1<<PIN





       unsigned char n=0;
       char ls,ms=0;
       float temp=0;
       int t=0;
     
    void delayus(unsigned int us)
    {
      unsigned int delay_loops;
      register unsigned int i;
      delay_loops = ((us/5*CYCLES_PER_US)*50)/100;
    //  _delay_loop_2 (delay_loops);
      for (i=0; i < delay_loops; i++)
      {
        asm("WDR");
      };
    }

    void delayms(unsigned int count)
    {
      while (count-- != 0)
        delayus(1000);
    }





    // procedura zapisu bajtu do wyświetlacza LCD
    // bez rozróżnienia instrukcja/dana
    void write_to_lcd(char x)
    {
    SET_E; // ustaw na E stan wysoki
    LCD = ((LCD & 0x0F) | (x & 0xF0)); // zapis pierwszej połówki bajtu
    CLR_E; // opadające zbocze na E -> zapis do wyświetlacza
    SET_E; // ustaw na E stan wysoki
    LCD = ((LCD & 0x0F) | ((x & 0x0F) << 4)); // zapis drugiej połowki bajtu
    CLR_E; // opadające zbocze na E -> zapis do wyświetlacza
    delayms(1); // czekaj 1ms
    }




    // procedura zapisu instrukcji do wyświetlacza LCD
    void write_command(char x)
    {
    CLR_RS; // niski stan na RS -> zapis instrukcji
    write_to_lcd(x); // zapis do LCD
    }




    // procedura zapisu danej do wyświetlacza LCD
    void write_char(char x)
    {
    SET_RS; // wysoki stan na RS -> zapis danej
    write_to_lcd(x); // zapis do LCD
    }




    // procedura zapisu tekstu do wyświetlacza LCD
    void write_text(char * s)
    {
    while(*s) // do napotkania 0
      {
      write_char(*s); // zapisz znak wskazywany przez s na LCD
      s++; // zwiększ s (przygotuj nastepny znak)
      }
    }





    // procedura inicjalizacji wyświetlacza LCD
    void lcd_init(void)
    {
    delayms(15); // czekaj 15ms na ustabilizowanie się napięcia zasilającego
    CLR_E; // E = 0
    CLR_RS; // RS = 0
    char i; // zmianna licznikowa
    for(i = 0; i < 3; i++) // trzykrotne powtórzenie bloku instrukcji
      {
      SET_E; // E = 1
      LCD &= 0x3F; //
      CLR_E; // E = 0
      delayms(5); // czekaj 5ms
      }
    SET_E; // E = 1
    LCD &= 0x2E; //
    CLR_E; // E = 0
    delayms(1); // czekaj 1ms
    write_command(0x28); // interfejs 4-bity, 2-linie, znak 5x7
    write_command(0x08); // wyłącz LCD, kursor i miganie
    write_command(0x01); // czyść LCD
    write_command(0x06); // bez przesuwania w prawo
    write_command(0x0C); // włącz LCD, bez kursora i mrugania
    }








    // moje procedurki na 1wire

    unsigned char exist1w(void) //sprawdzanie czy urzadzenie 1wire jest podłączone do procesora

       //unsigned char ack;
       PORT1w&=~(1<<PIN);            //zwraca 1 jesli wszysko ok, w przeciwnym wypadku zwraca zero
       DDR1w|=1<<PIN;               //stan 0   
       delayus(250);
       delayus(250);
       DDR1w&=~(1<<PIN);               //stan 1
       delayus(75);
       if(bit_is_clear(PIN1w,PIN))
       {
          delayus(500);
          return 1;
       }
       else
       {
          delayus(500);
          return 0;
       }
    }

    unsigned char reset1w(void)         //reset urzadzenia 1wire
    {
       unsigned char potwierdzenie;
        output;
       wire0;
        delayus(700);
        wire1;
        delayus(80);
       input;
        potwierdzenie=bit_is_clear(PIN1w,PIN);
        delayus(400);
       return potwierdzenie;
     }

    void slot_wyslij1w(unsigned char znak)   //wysyła bit 0 lub 1 do urzadzenia 1wire
    {
       output;
       wire0;
       if(!znak)                     //organizujac transmisje bitu w slot czasowy
       {
        delayus(80);
       }
       else
       {
        wire1;
       delayus(60);
       }
     }

    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;               //w jednym slocie czasowym
       output;
       wire0;
       delayus(5);
       wire1;
       delayus(5);
       input;
       bit1w=bit_is_set(PIN1w,PIN);
       if(!bit1w) delayus(55);
       return bit1w;
    }

    unsigned char read1w(void)            //odbiera jeden bajt danych od urzadzenia 1wire
    {
       unsigned char dana=0x00;
       unsigned char j;

       for(j=0x01;j!=0;j=j<<1)
       dana|=slot_odbierz1w()?j:dana;
       
       return dana;
    }










    // program główny
    int main(void)
    {
    // konfiguracja portów we/wy
    DDRB = 0xFF;
    DDRD = 0xff;
    PORTB = 0xFF;
    PORTD = 0xFF;
    // inicjalizacja LCD
    CLR_RW;
    lcd_init();
    CLR_RW;
    output;

    reset1w();
    delayms(1000);
    write1w(0xcc); //skip rom
    write1w(0x4e); // ustawienie
    write1w(0xff); // th=127
    write1w(0x00); // tl=0
    write1w(0x3f); // rodzielczosc 12 bit
    reset1w();

    while(1)
    {
       reset1w();
       write1w(0xcc); //skip rom
       write1w(0x44);
       delayms(1000);
       reset1w();
       write1w(0xbe);
       ls=read1w();
       ms=read1w();
       reset1w();
       

       
       temp=ls+(ms*256);
       temp=temp/16;
       t=temp*100;
       write_command(0x01);
       write_command(0x02);
       
       
       write_text("Temp:     ");
       t=t%10000;
       n=0x30+t/1000;
        write_char(n);
       t=t%1000;
       n=0x30+t/100;
       write_char(n);
        t=t%100;
       write_char(0x2c);
       n=0x30+t/10;
        write_char(n);
        t=t%10;
       n=0x30+t;
        write_char(n);


    }


    return 0;
    }


    testowalem tez codevision:
    Code:

    /*****************************************************
    This program was produced by the
    CodeWizardAVR V1.24.6 Evaluation
    Automatic Program Generator
    © Copyright 1998-2005 Pavel Haiduc, HP InfoTech s.r.l.
    http://www.hpinfotech.com
    e-mail:office@hpinfotech.com

    Project :
    Version :
    Date    : 2005-08-03
    Author  : Freeware, for evaluation and non-commercial use only
    Company :
    Comments:


    Chip type           : ATtiny2313
    Clock frequency     : 4,000000 MHz
    Memory model        : Tiny
    External SRAM size  : 0
    Data Stack size     : 32
    *****************************************************/

    #include <tiny2313.h>   
    #include <delay.h>

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

    // DS1820 Temperature Sensor functions
    #include <ds1820.h>

    // Alphanumeric LCD Module functions
    #asm
       .equ __lcd_port=0x18 ;PORTB
    #endasm
    #include <lcd.h>

    // Declare your global variables here

    void main(void)
    {
    // Declare your local variables here

    // Crystal Oscillator division factor: 1
    #pragma optsize-
    CLKPR=0x80;
    CLKPR=0x00;
    #ifdef _OPTIMIZE_SIZE_
    #pragma optsize+
    #endif

    // Input/Output Ports initialization
    // Port A initialization
    // Func2=In Func1=In Func0=In
    // State2=T State1=T State0=T
    PORTA=0x00;
    DDRA=0x00;

    // 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 D 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
    PORTD=0x00;
    DDRD=0x00;

    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: Timer 0 Stopped
    // Mode: Normal top=FFh
    // OC0A output: Disconnected
    // OC0B output: Disconnected
    TCCR0A=0x00;
    TCCR0B=0x00;
    TCNT0=0x00;
    OCR0A=0x00;
    OCR0B=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
    // Timer 1 Overflow Interrupt: Off
    // Input Capture Interrupt: Off
    // Compare A Match Interrupt: Off
    // Compare B Match Interrupt: Off
    TCCR1A=0x00;
    TCCR1B=0x00;
    TCNT1H=0x00;
    TCNT1L=0x00;
    ICR1H=0x00;
    ICR1L=0x00;
    OCR1AH=0x00;
    OCR1AL=0x00;
    OCR1BH=0x00;
    OCR1BL=0x00;

    // External Interrupt(s) initialization
    // INT0: Off
    // INT1: Off
    // Interrupt on any change on pins PCINT0-7: Off
    GIMSK=0x00;
    MCUCR=0x00;

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

    // Universal Serial Interface initialization
    // Mode: Disabled
    // Clock source: Register & Counter=no clk.
    // USI Counter Overflow Interrupt: Off
    USICR=0x00;

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

    // 1 Wire Bus initialization
    w1_init();

    // LCD module initialization
    lcd_init(16);
       
    lcd_putsf("hello ");
    while (1)
          {     
       
             if (w1_init())
           
             lcd_putsf("ok ");
             delay_ms(1000);
           

          };;
    }


    Nie wiem gdzie tkwi moj blad. Obawiam sie ze zle podlaczam czujki. Probowalem juz 2 sposobow: 1-masa, 2-port i 4k7 do vcc, 3- vcc oraz 1,3-masa 2-port i 47 vcc. Wszystko zgodnie z rozpiska producenta. Czujki mam 2 z sampli. Obie zachowuja sie identycznie tzn. nie dzialaja :P.
    Prosze o pomoc bo juz nerwy mi wysiadaja.

    Probowalem juz kilku funkcji opozniajacych ale zadna nie daje spodziewanych efektow (sprawdzanie nie jest byc moze zbyt dokladne bo wysylam znak co 1s na wyswietlacz i porownuje z zegarkiem). Oryginalna fukcja delayus miala postac:
    Code:

    void delayus(unsigned int us)
    {
      unsigned int delay_loops;
      register unsigned int i;
      delay_loops = us/5*CYCLES_PER_US;
    //  _delay_loop_2 (delay_loops);
      for (i=0; i < delay_loops; i++)
      {
        asm("WDR");
      };
    }


    ale dziala ona za dlugo (daje wieksze opoznienia o mniej wiecej 60%). Calosc ladnie sobie sprawdzam na symulatorze isis pakietu proteus. Wykresy czasowe zmian portu z 0 na 1 z danym opoznieniem.


    pzdr icdark
    [/code]
  • Poziom 13  
    Ten program byl napisany dla 4MHz? AVT3500 maja wlasnie xtal 4MHz. Zauwazylem pewna dolegliwosc mojego winavr. Opoznienia nie sa dokladne. _delay_ms nie daje mi odpowiedniego czasu (wiem ze max to 762/ f w MHz). Co mam zrobic aby opoznienia byly prawidlowe? (opoznienia z delay.h oczywiscie... mzoe sie je w jakis konkretny sposob uzywa nie mowiac o #define F_CPU 4000000)

    p.s. czujki byly uszkodzone... mam juz nowe
  • Poziom 28  
    Tak, 4MHz. Ja nie zwróciłem uwagi, czy opóźnienia z delay.h są dokładne... Używam ich bez jakichś specjalnych zabiegów i programy działają właściwie. Więc może masz coś z WinAVR pokręcone?
  • Poziom 13  
    Tez tak mysle. Program ten nie dziala u mnie poprawnie, ale co mogelm pokrecic z winavrem? Przeciez to zwykla instalacja chyba ze nie wiem o jakiejs konfiguracji ktora trzeba przeprowadzic. Moze cos z makefilem mam nie tak... moze moglbys mi wklej Twoj plik makefile. Ja uzywam przerobionego tego z examples/demo. Z gory dzieki.

    p.s. mam jeszcze pytanie odnosnie opoznien... dla http://mikrokontrolery.net/avr_c_08.htm czy dziala u ciebie zamiana funkcji waitms na _delay_ms? u mnie niestety nie wiec zastanawiam sie co moze byc nie tak z kofiguracja winavra.
  • Poziom 28  
    Ja nie korzystam z makefile. Programy piszę w AVRSide a ostatnio w KamAVR (dostępny na avrfreaks.net).
    Ad PS. Owszem działa... WinAVR masz oczywiście w najnowszej (14 luty 2005) wersji?
  • Poziom 13  
    Tak. Na 3 roznych komputerach instalowalem. Za kazdym razem sciagnalem paczke z netu z sourceforge(oficjalna strona projektu). Widze ze wystartowal ponownie avrfreaks wiec zabieram sie do przeszukiwania ich archiwow moze tam cos znajde. Boje sie ze problem moze byc z iotn2313.h. Dla innych procesorow blad moze nie wystepowac. Niestety tylko te mam pod reka i nie jestem w stanie sprawdzic.

    czy moglby mi ktos powiedziec co jest w tym zle? zwraca 1 przy podlaczeniu dq do portu uK oraz zasilania (bez masy). Kiedy podlacze all to zwraca 0. Czasy opoznien sa na 100% dobre.
    Code:

    #define PIN1w PIND         
    #define DDR1w DDRD
    #define PORT1w PORTD
    #define PIN PD1

    unsigned char exist1w(void) //sprawdzanie czy urzadzenie 1wire jest podłączone do procesora
    {   
       PORT1w&=~(1<<PIN);            //zwraca 1 jesli wszysko ok, w przeciwnym wypadku zwraca zero
       DDR1w|=1<<PIN;               //stan 0   
       delay_long(330);
       DDR1w&=~(1<<PIN);               //stan 1
       delay_long(46);
       if(PIN1w & _BV(PIN))
       {
          delay_long(330);
          return 1;
       }
       else
       {
          delay_long(330);
          return 0;
       }
    }


    Dodano po 40 [minuty]:

    Sprawdzilem wszystko jeszcze raz i oto jak wyglada aktualnie moj uklad:
    czujka i proc sprawne bo po wgraniu programu z codevision (pierwszy post) na lcdku pojawia mi sie napis ok a po odlaczeniu chociazby jednej nozki z dsa pokazuje err wiec uklad jest sprawny. Probowalem doslownie wszystkiego (m.in. wew pullup ddrx=0 i portx=0) ale wszystko nieskuteczne. Najbardziej zdziwil mnie brak reakcji na program do ktorego link mi wkleiles. Skoro jest napisany pod 4MHz to petla opozniajaca delay bedzie poprawnie dzialala na moim procu (w koncu attiny2313 jest w miare dokladnym zamiennikiem dla at90s2313 - w moim ukladzie powinien dzialac identycznie). Otoz funkcje 1wire w/w programu nie dzialaja w moim ukladzie... oto kod ktory testuje... moze robie jakis prosty blad ktorego nie zauwazam ale tyle h juz przy tym spedzilem i jakos go nie znalazlem.

    Code:

    int main(void)
    {
    DDRB = 0xFF;
    DDRD = 0x00;
    PORTB = 0xFF;
    PORTD = 0xFF;

    CLR_RW;
    lcd_init();

    while(1)
    {
       if(ow_reset()) {write_text("ok");} else write_text("err");
       waitms(255);
       waitms(255);
       lcd_clear();
       write_text("hi ");
       waitms(255);
       waitms(255);
    }

    return 0;
    }

    Uklad zachowuje sie dosc dziwacznie. Pokazuje err dla kazdej kombinacji podlaczenia (przy niezmiennym dq) ale w momencie kiedy vcc z dsa podlacze do masy to pojawia mi sie ok. Podejrzewam ze jest to kwestia budowy wew ds18b20. Tak czy inaczej procedury u mnie nie dzialaja. Prosze o pomoc.

    pzdr
  • Poziom 28  
    Nie ustawiaj całego rejestru PORTD w stan wysoki. PORTD.5 MUSI być w stanie niskim! Najlepiej tuż przed wywołaniem ow_reset() wpisz
    Code:
    PORTD &= ~_BV(5);


    edit:
    W preocedurze ow_reset jest bład! Za małe opóźnienie po sygnale reset (przed wystawieniem persence pulse przez ds). Poprawna wersja :
    [code]unsigned char ow_reset(void)
    {
    unsigned char persence;
    CLR_DQ; // stan niski na linii 1wire
    delay(255); //
    delay(119); // opóźnienie ok 480us
    SET_DQ;// stan wysoki na linii 1wire
    delay(20);
    if(IN_DQ) persence = 0;
    else persence = 1; // odczyt sygnału obecności ukłądu 1wire
    delay(255); //
    delay(119); // opóźnienie ok 480 us
    return(persence);
    }[code]
  • Poziom 13  
    Dzieki za podpowiedz. Co do bledu w procedurze to funkcje delay_long mam z innego zrodla... przeliczona na rozkazy i ilosc cykli w asm (6 na petle + 20 na warunku koncowym - pop itp). Moje opoznienia sa zgodne z opisem opoznien w datashetach dallasa. Ten moj delay_long(330) daje= 330*6 + 20= 2000 co przy moim clk 4MHz daje 500us (wedlug specyfikacji 1wire powinno byc od 480-960us potem 15-60us przerwy i odczyt impulsu z urz slave (czas odpowiedzi to jakies 60-240us). Te moje delay_long(44) daje 71us wiec mam pewnosc ze jezeli odpowiedz ukladu slave jest to "trafiam" z odczytem w jej czas trwania.

    Co do ustawiania portud.5 (u mnie pd1) przed restem w stan niski... hmmm... nie widze w tym sensu skoro stan niski oznacza juz transmisje. Stanem nieaktywnym na linii 1wire powinien byc stan 1 jezeli sie nie myle. Zastanawiam sie czy mam na pd.1 w trybie wejscie mam wystawic 1(pull up) czy to nie bedzie klocilo sie w jakis sposob z podciaganiem przez 4k7 w strukturze polaczenia ds-ki.

    P.S. zauwazylem ze nie zmieniasz stanu portx a jedynie sterujesz ddrx
    Code:
     #define SET_DQ DDRD &= ~_BV(DQ)
    
    #define CLR_DQ DDRD |= _BV(DQ)

    ciekawy sposob... meczy mnie to jak to dziala skoro gdy dla pd5=0 przelaczasz ddrd in/out. Port dzialajacy jako wejscie dla pd5=0 nie ma pullapa wiec napiecie to odpowiada stanowi niskiemu (1.5V), a gdy jest jako wyjscie to jest 0V... a gdzie tu miejsce na jedynke? z zew podciagniecia? nie rozumiem tej idei ale skoro u Ciebie dziala to chcialbym ja pojac :]

    dzieki i pzdr
  • Poziom 28  
    Tak, to jest trochę nietypowe :D Mianowicie :
    DDRD.5 = 0 -> wejście, jeśli w PORTD.5 jest 0 to wyprowadzenie jest na potencjale pływającym i przez zewnętrznego pull-upa wymuszany jest stan wysoki
    DDRD.5 = 1 -> wyście, jeśli w PORTD.5 jest 0 to wymuszany jest stan niski przez wewnętrzny tranzystor portu ściagający do masy.

    PS. Sprawdziłem, co avr-gcc robi z ow_reset i stwierdziłem, że nie odczyta obecności układu (jakieś bzdury są w kodzie wynikowym). Więc na razie nie męcz się ze sprawdzaniem obecności tylko dokonaj pomiaru temperatury.
  • Poziom 13  
    Serdeczne dzieki za pomoc... uklad odpalilem i pomiar temperatury dziala bez zarzutu. Faktycznie o ile reset dziala to jezeli chodzi o poprawne zwracanie obecnosci ukladu to jest juz gorzej. Dziekuje jeszcze raz i pozdrawiam.

    icdark