logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Jak wymusić niski stan na linii 1-wire z AtMega32 i DS1820?

Nonilion 13 Lip 2007 15:25 5978 16
REKLAMA
  • #1 4078404
    Nonilion
    Poziom 2  
    Posty: 3
    Witam,

    Jak wymusić niski stan na lini?

    Mam następujący problem. Nie mogę skomunikować się z czujnikiem DS1820. Przejrzałem forum w sprawie komunikacji z czujnikiem. Przeczytalem dokumentacje Dallasa itp.

    Czujnik podłączony jest w następujący sposób:
    1 - GND
    2 - DQ (do procesora do pinu PIND7)
    3 - Vcc
    Dodatkowo linia danych podciągnięta jest przez rezystor 4.7kΩ do zasilania.

    Procesor taktowany jest wewnętrznym zegarem 8Mhz.


    Załączam kluczowe fragmenty kodu:

    #define DQ 7
    #define OW_HI DDRD&=~(1<<DQ);
    #define OW_LO DDRD|=(1<<DQ);

    void delay_s(s)
    {
    int i;
    do{
    for(i=0;i<5;i++)
    {
    _delay_loop_2(0xffff);
    _delay_loop_2(0xffff);
    _delay_loop_2(0xffff);
    }
    }while(s--);
    }

    int main (void)
    {
    for ( ; ; )
    { OW_LO;
    delay_s(3);
    OW_HI;
    }
    return (0);
    }

    Krótkie omówienie kodu. Program na przemian ustawia port D pin 7 w stanie wejścia i wyjścia. Są to podstawowe komendy do sterowania magistrala 1-wire i z tego co przeczytalem to musi działać.
    De facto tak się dzieje. Podłaczając miernik widze, że port zmienia swoją impedancję z niskej na wysoką. Niestety po podłączeniu czujnika napięcia na linii DQ wynoszą 5V dla loginczej "1" oraz 4.23V dla "zera".
    Innymi słowy procek "macha" linią, jednak nie jest w stanie ściągnąc napięcia do zera dla stanu niskiego.

    Proszę o jakiekolwiek sugestie. Czujnik powinien być sprawny, bo mam jeszcze 3 inne sztuki i zawsze dzieje się to samo.

    W trybie parasite napięcie na linii zmienia się poprawnie.

    Pozdrawiam i czekam na pomoc.
  • REKLAMA
  • #2 4078596
    szod
    Poziom 33  
    Posty: 1663
    Pomógł: 215
    Ocena: 120
    Czujniki DS1820 mają wymagania odnośnie dokładności opóźnień, więc jeśli
    zamierzasz go oprogramować to lepiej zastosuj kwarc. Co do obecności czujnika
    na linii to spróbuj inaczej. Ustaw stan niski przez ok. 480 - 960µs. Najlepiej gdzieś
    pośrodku. Po około 65 - 75µs (70µs) sprawdź czy jest czujnik. Powinien odpowiedzieć
    stanem niskim. Oczywiście jak wystawiasz stan niski to port powinien być w trybie
    wyjściowym a jak czytasz wejściowym. Takie dowolne żonglowanie czasami
    jak robisz może powodować różne nieprzewidziane efekty.
  • #3 4080245
    BoskiDialer
    Poziom 34  
    Posty: 1530
    Pomógł: 353
    Ocena: 42
    <<Niestety po podłączeniu czujnika napięcia na linii DQ wynoszą 5V dla loginczej "1" oraz 4.23V dla "zera".>>
    według mnie nieustaliłeś wartości bitu dla PORTD - domyślnie powinien być równy zero, ale kto wie, czy jest inaczej (<<Załączam kluczowe fragmenty kodu>>).. jeśli bit ten będzie równy jeden, to twoje machanie ddr'em z 0 do 1 będzie zmieniać stan pinu pomiędzy HI(ddr:port=1:1)-PULLUP(ddr:port=0:1). przy HI będziesz miał 5V, przy pullup jeśli czujnik wprowadza spadek - odpowiednio mniej...
    jeśli wyzerujesz odpowiadający bit PORTD, to powinieneś uzyskać zamierzone sterowanie LO(ddr:port=1:0)-OPEN-COL(ddr:port=0:0).
    I jak już, to warto zmienić:
    for ( ; ; ) 
    { OW_LO; 
    delay_s(3); 
    OW_HI; 
    }
    na coś takiego:
    for(;;) 
    {
      OW_LO;
      delay_s(3); 
      OW_HI;
      delay_s(3); //<<-- dodatkowe opóźnienie? żeby widzieć efekty zmiany stanu pinu
    }
  • REKLAMA
  • #4 4087737
    Nonilion
    Poziom 2  
    Posty: 3
    Dziękuję forumowiczom za pomoc, niemniej Wasze propozycje nie działają w moim przypadku :(
    Może ktoś z Was zechciałby zobaczyć u siebie jak zachowuje się czujnik DS1820/22 w przypadku podłączenia go do kontrolera i dla programu poniżej?

    Opis programu:
    W cyklu 3 sekundowym (dla 8MHz) Zmienia stan lini na niski i wysoki.

    Jakie napięcia macie na lini DQ?
    U mnie dla podłączenia w trybie parasite (Vcc czujnika nie podłączone) mam odpowiednio 0V i 5V.
    W trybie z podłączonym zasilaniem dostaję 4.25V (stan niski) i 5V stan wysoki.
    Załączniki:
    • low_hi.c (548 Bajtów) Musisz być zalogowany, aby pobrać ten załącznik.
  • #5 4087812
    szod
    Poziom 33  
    Posty: 1663
    Pomógł: 215
    Ocena: 120
    Zwróć uwagę że w programie przestawiasz tylko pin jako wejście albo jako wyjście poprzez DDR.
    Jak ustawisz jako wyjście to powinieneś podać na pin 7 stan niski. Musisz użyć dodatkowo PORTD.
    Tak mi się zdaje bo używam assemblera i mogę się mylić co do kodu. Ale zachowanie układu na
    to wskazuje. Potem tylko wystarczy zrobić jak pisałem i będzie hulać. Wykorzystywałem już
    ten czujnik i nie miałem problemu.
  • #6 4165356
    tokarz
    Poziom 18  
    Posty: 349
    Pomógł: 17
    Ocena: 19
    Witam,

    też mam problem z DS1820. Komunikacja działa, bo czujnik jest wykrywany, ale niestety mierzona temperatora wynosi 0.0 C.
    Sam nie wiem już czy to z opóźnieniami jest problem, czy może z samą ideą działania funkcji. Kod znalazłem w internecie i przerobiłem na swoje potrzeby. Czy ktoś mógłby zerknąć i ocenić poprawność kodu ?

    Linia DQ jest podłączona pod trzecią nóżkę portu D (PD3). Dodatkowo jest podpięta pod VCC przez rezystor 4,7k. VCC jest podpięte pod +5V.
    Czujnik jest wlutowany bezpośrednio na nogi procesora, więc problem odległości pomijam.

    Porty mam skonfigurowane tak:
    DDRD=0x00; //PORTD - we
    PORTD=0x07; //podciąganie linii PD0, PD1, PD2

    
    //procedura opoznienia dla onewire
    void delay(int useconds)
    {
    int s;
    useconds = useconds;
    for (s=0; s<useconds;s++);
    }
    // procedura reset
    unsigned char ow_reset(void) // reset lini one wire
    {
    	unsigned char presence=1;
    	DDRD |= _BV(3); //DQ = 0; //pull DQ line
    	delay(960);
    	DDRD &= ~_BV(3); //DQ = 1; // allow line to //powrót lini 1w do trybu wejścia
    	delay(144);// wait for presence pulse(pochodzący od DS-a) //czekamy na ustabilizowanie lini
    	if(bit_is_clear(PIND,3)) 
    		{
    			presence=0; 	 //odczytujemy co wystawił na linię DS
    		}
    	delay(880);// wait for end
    	return(presence); // presence signal
    } // 0=presence, 1 = no part
    
    // READ_BIT - reads a bit from the one-wire bus. The delay
    // required for a read is 15us, so the DELAY routine won't work.
    // We put our own delay function in this routine in the form of a
    // for() loop.
    unsigned char read_bit(void)
    {
    	unsigned char presence=0;
    	DDRD |= _BV(3); 	//DQ = 0; // pull DQ low to start timeslot
    	DDRD &= ~_BV(3);	//DQ = 1; // then return high
    	delay(30); // delay 15us from start of timeslot
    	if(bit_is_clear(PIND,3)) presence=0;
    	if(bit_is_set(PIND,3)) presence=1;
    	return(presence); // return value of DQ line
    }
    ///---------------------------------------------------------
    
    void write_bit(char bitval) //WRITE_BIT - writes a bit to the one-wire bus, passed in bitval.
    {
    	DDRD |= _BV(3); //DQ = 0; // pull DQ low to start timeslot
    	if(bitval==1) DDRD &= ~_BV(3); //DQ =1; // return DQ high if write 1
    	delay(204); // hold value for remainder of timeslot - delay 104us
    	DDRD &= ~_BV(3);//DQ = 1;
    }
    
    ///---------------------------------------------------------
    
    unsigned char read_byte(void) // READ_BYTE - reads a byte from the one-wire bus
    {
    	unsigned char i;
    	unsigned char value = 0;
    	for (i=0;i<8;i++)
    	{
    		if(read_bit()) value|=0x01<<i; // reads byte in, one byte at a time and then
    		delay(240); // ??shifts it left wait for rest of timeslot 120us
    	}
    	return(value);
    }
    
    ///---------------------------------------------------------
    
    void write_byte(char val) // WRITE_BYTE - writes a byte to the one-wire bus.
    {
    	unsigned char i;
    	unsigned char temp;
    	for (i=0; i<8; i++) // writes byte, one bit at a time
    	{
    		temp = val>>i; // shifts val right 'i' spaces
    		temp &= 0x01; // copy that bit to temp
    		write_bit(temp); // write bit in temp into
    	}
    	delay(204);
    
    }
    
    void write_text(char * s)
    {
    	while(*s)
    	{
    		piszznak(*s);
    		s++;
    	}
    }
    
    union 
    {
    	int tds;
    	char nds[2];
    }	ds;
    
    char bufor[6];
    
    
    void Read_Temperature(void)
    {
    	if(ow_reset()) 
    	{
    		lcdxy(1,0); 
    		write_text("Brak czujnika");
    	}
    	else
    	{
    		write_byte(0xCC); //Skip ROM
    		write_byte(0x44); // Start Conversion
    		_delay_ms(1000);
    		_delay_ms(1000);
    		_delay_ms(1000);
    		ow_reset();
    		write_byte(0xCC); // Skip ROM
    		write_byte(0xBE); // Read Scratch Pad
    		ds.nds[0]=read_byte();
    		ds.nds[1]=read_byte();
       		itoa(ds.tds/2,bufor,10);//temper. całkowita nie za bardzo rozumiem dzialanie tej funkcji, szczegolnie, ze ds.tds nigdy nie jest zmieniana...
    		lcdxy(1,0);
    		write_text("T:");
    		write_text(bufor);
    		write_text(".\0");
       		itoa(abs((ds.tds*10/8)%10),bufor,10);	//części dziesiętne
       		write_text(bufor);
    		write_text(" C");
    	}
    } 
    


    Może ktoś z Was ma jakiś szablon funkcji, która konwertuje zczytaną wartość z DS1820 na ASCII ?
    Czy w pamięci HD44780 jest znak stopni (°) ? A jeśli tak to jaki ma kod ?


    Pozdrawiam.
  • #7 4174952
    tokarz
    Poziom 18  
    Posty: 349
    Pomógł: 17
    Ocena: 19
    Oczywiście problemem okazało się opóźnienie czasowe :) Teraz DS działa, ale mam problem z wskazaniami temperatury. Pokazkuje mi zawyżając o jakieś 6 stopni C. Jakieś sugestie ?

    Pozdrawiam.
  • REKLAMA
  • #8 4175041
    szod
    Poziom 33  
    Posty: 1663
    Pomógł: 215
    Ocena: 120
    Sprawdzałeś w fusebitach na jakiej częstotliwości pracuje µC? Może w tym
    problem. Procedury które znalazłeś były pisane dla określonej częstotliwości
    pracy µC. Wykrywać DS-a może bo akurat mieści się w jakichś widełkach
    czasowych, co nie oznacza że reszta procedur będzie pracować prawidłowo.
    Tak w ogóle to dla większej precyzji odmierzania czasu powinno się stosować
    zewnętrzny kwarc zamiast generatora wewnętrznego. Co ma szczególne
    znaczenie przy DS-ach.
  • #9 4175053
    tokarz
    Poziom 18  
    Posty: 349
    Pomógł: 17
    Ocena: 19
    FB są ustawione na 8MHz; generator wewnętrzny. Zastosuję zewnętrzny rezonator. Ale najpierw muszę rozwiązać problem błędnych wskazań...

    Pozdrawiam
  • #10 4175168
    szod
    Poziom 33  
    Posty: 1663
    Pomógł: 215
    Ocena: 120
    A tam gdzie znalazłeś te procedury nie pisało na jakiej częstotliwości powinien
    pracować µC? Jak nie wiesz to spróbuj zmienić na mniejszą i zobacz jak będzie
    się zachowywać. Może 4MHz będzie ok a może mniej. Trzeba by wiedzieć ile
    czasu wykonują się poszczególne instrukcje w procedurze opóźniającej i wtedy
    można dojść jaka powinna być częstotliwość. Osobiście nie piszę w C
    więc co do kodu to nie powiem Ci czy coś jest nie tak.
  • #11 4175208
    tokarz
    Poziom 18  
    Posty: 349
    Pomógł: 17
    Ocena: 19
    Wcześniej napisałem:
    Cytat:
    Oczywiście problemem okazało się opóźnienie czasowe Teraz DS działa, ale mam problem z wskazaniami temperatury. Pokazkuje mi zawyżając o jakieś 6 stopni C. Jakieś sugestie ?

    Pozdrawiam.


    Teraz tylko nie wiem dlaczego zawyża mi temperaturę o jakieś 6 stopni...

    Pozdrawiam.

    Dodano po 43 [minuty]:

    I jeszcze jedno pytanie. Jak czytać temperatury ujemne ?
    Chyba zapisywane są one jako U2... czyli muszę czytać 9 bitów, zamiast 8 i sprawdzać stan najstarczego bitu. Jeśli jest równy 1 to obliczam jak U2, a jak równy 0 to z BIN do DEC ?
  • #12 4175972
    Konto nie istnieje
    Poziom 1  
  • #13 4176556
    sawitar
    Poziom 18  
    Posty: 226
    Pomógł: 20
    Ocena: 19
    1wire zazwyczaj nie działa ze wzgledu na zle dobrane opoznienia. Musza one byc zrobione z dokladnościa co najmniej 1uS. Jesli tego nie spelnisz NIGDY nie bedziesz mial poprawnych odczytow. Zreszta ta kwestia byla juz poruszana na forum.
    Gotowy, dzialajacy i przetestowany sterownik 1wire w C dostepny jest na stronie Dallasa. Po co wywazac otwarte drzwi ?

    Cytat:
    I jeszcze jedno pytanie. Jak czytać temperatury ujemne ?
    Chyba zapisywane są one jako U2... czyli muszę czytać 9 bitów, zamiast 8 i sprawdzać stan najstarczego bitu. Jeśli jest równy 1 to obliczam jak U2, a jak równy 0 to z BIN do DEC ?

    Polecam zapoznanie sie z dokumentacja do czujnika DS1820 jest łatwo dosępna na stronie producenta (Dallas).
    btw. w jaki sposob wydedukowales ze liczba zapisana w U2 jest 9 bitowa?
  • REKLAMA
  • #14 4178731
    tokarz
    Poziom 18  
    Posty: 349
    Pomógł: 17
    Ocena: 19
    voytaschec - dzięki. Twoje informacje okazały się pomocne. Układ już uruchomiłem i działa sprawnie. Problemem nie były opóźnienia czasowe, tylko sposób konwersji.

    Cytat:
    1wire zazwyczaj nie działa ze wzgledu na zle dobrane opoznienia. Musza one byc zrobione z dokladnościa co najmniej 1uS.

    Po sprawdzeniu nie mogę się zgodzić z tą opinią. Prawie 5 - 7% tolerancja jest dopuszczalna (w układzie, który zaprojektowałem) i układ wciąż działa.
    Cytat:
    Polecam zapoznanie sie z dokumentacja do czujnika DS1820 jest łatwo dosępna na stronie producenta (Dallas).

    To bardzo cenna uwaga. Bardzo przyczyniła się do rozwiązania mojego problemu. Dzięki.

    Dodam jeszcze tylko, że ten sam kod, na dwóch procesorach Atmega32 wymagał odpowiednich zmian w funkcji opóźniającej. Wnioski nasuwają się same.

    Dziękuję za pomoc w rozwiązaniu problemu.

    Pozdrawiam.

    Dodano po 2 [godziny] 14 [minuty]:

    Witam ponownie.

    Mam jeszcze jedno pytanie. Teraz mogę mierzyć już temperatury dodatnie i ujemne w pełnym zakresie, ale pozostał problem zawyżania temperatury (dokładnie o 3 stopnie C). Czy może być to spowodowane np. "samonagrzewaniem" się DS-a pod wpływem wydzielanej mocy ?
    Zastanawiam się czy inny DS będzie zachowywał się tak samo. Jeśli tak, to spróbuję dokleić do niego jakiś mały kawałek blaszki.
    Macie z tym jakieś doświadczenia [tzn. z zawyżaniem temp.] ?
    Dodam, że porównanie było dokonane z jednym miernikiem cyfrowym i dwoma rtęciowymi. Różnica za każdym razem była taka sama.

    Ponawiam pytanie dotyczące wyświetlania znaku stopni (°) na HD44780...

    Pozdrawiam.
  • #15 4179663
    sawitar
    Poziom 18  
    Posty: 226
    Pomógł: 20
    Ocena: 19
    Najkrotszy czas ktory nalezy odmierzyc w 1-wire to (mniej niż) 15uS, a wiec 1uS toleracji to około 7%.

    Informacja w jaki sposób zapisana jest temperatura w DS1820 (takze ujemna znajduje się w dokumentacji do DS1820 i DS1820S na stronie 3, a dla DS1820B na stronie 4. Nie widze sensu w pzepisywaniu dokumentacji.
  • #16 4179725
    BoskiDialer
    Poziom 34  
    Posty: 1530
    Pomógł: 353
    Ocena: 42
    znak stopni wg dokumentacji którą mam, ma kod 0xDF. Ostatecznie można stworzyć znak w pamięci CGRAM i go wyświetlać.
  • #17 4182973
    tokarz
    Poziom 18  
    Posty: 349
    Pomógł: 17
    Ocena: 19
    Cytat:
    Informacja w jaki sposób zapisana jest temperatura w DS1820 (takze ujemna znajduje się w dokumentacji do DS1820 i DS1820S na stronie 3, a dla DS1820B na stronie 4. Nie widze sensu w pzepisywaniu dokumentacji.

    Nie bardzo rozumiem czego dotyczy ta odpowiedź. Przecież nie chodzi mi o pomiar temperatur ujemnych, tylko o to, że DS zawyża pomiar o 3 stopnie C.

    Pozdrawiam.

    P.S. - BoskiDialer - dzięki.

Podsumowanie tematu

✨ Dyskusja dotyczy problemów z wymuszeniem niskiego stanu na linii 1-wire w komunikacji między mikrokontrolerem AtMega32 a czujnikiem temperatury DS1820. Kluczowym zagadnieniem jest prawidłowa konfiguracja portu mikrokontrolera – konieczne jest nie tylko przełączanie pinu między trybem wejścia i wyjścia (DDR), ale także odpowiednie ustawienie rejestru PORTD, aby wymusić stan niski na linii danych. Wskazano, że opóźnienia czasowe muszą być bardzo precyzyjne (rzędu mikrosekund), co jest trudne do osiągnięcia przy wewnętrznym generatorze 8 MHz, dlatego zaleca się stosowanie zewnętrznego rezonatora kwarcowego dla stabilności i dokładności timingów. Problemy z komunikacją i błędnymi odczytami temperatury (np. zawyżanie o kilka stopni) mogą wynikać z nieprawidłowej konwersji danych, niedokładnych opóźnień lub samonagrzewania czujnika. Omówiono także sposób odczytu temperatur ujemnych, które są kodowane w formacie uzupełnienia do dwóch (U2) i wymagają odczytu pełnych 16 bitów rejestru temperatury. Wskazano na dostępność gotowych, przetestowanych sterowników 1-wire w języku C na stronie producenta (Dallas). Podkreślono, że dokładność opóźnień powinna wynosić co najmniej 1 µs, aby zapewnić poprawną komunikację.
Wygenerowane przez model językowy.
REKLAMA