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

Komunikacja ATmega16 z DS18B20 - brak odpowiedzi czujnika, rezystor 2.2k zamiast 4.7k

CrazyCat 23 Gru 2005 15:30 10909 18
REKLAMA
  • #1 2109476
    CrazyCat
    Poziom 11  
    Posty: 6
    Witam. Mam pewien problem, ze skomunikowaniem ATmegi z tym czujnikiem. Czytałem pokrewne posty, ale niczego one nie wnoszą do mojej sytuacji.
    Najpierw przedstawię mój program, a następnie disassemblację procedury obsługi pętli opóźniającej. Procedura zaczyna się na adresie 00000054 (podświetlone na zielono). Jest to kolejne 6 instrukcji, które trwają wszystkie po jeden takt zegar, oprócz ostatniej która trwa dwa. Czyli w sumie 7 us. Do tego dochodzi wywołanie i wyjście z procedury, więc cały obieg pętli to jest (6+7*parametr)* 1 us. Chyba dobrze wnioskuję...
    Niestety mimo całego dnia prób z różnymi czasami, także tymi zalecanymi przez producenta, procesor nie odebrał odpowiedzi od czujnika....
    Czujnik pracuje w normalny trybie zasilana, tzn. nóżka zasilania jest podłączona do zasilania. Nie miałem zalecanego rezystora podciągającego linię danych 4.7k, więc zastosowałem 2.2k. Czy to może być powodem problemów??? Moja pula pomysłów na rozwiązanie tego problemu już się skończyła.

    Acha. Dodam, że fusebity są ustawione prawidłowo i procesor na pewno pracuje z zegarem wewnętrznym 1MHz. Próbowałem też z 4MHz, oraz z zewnętrznym 7.3728 MHz... Niestety bez efektów. Sprawdzałem też na różnych nóżkach i portach ATmegi.
    Załączniki:
    • Komunikacja ATmega16 z DS18B20 - brak odpowiedzi czujnika, rezystor 2.2k zamiast 4.7k 1wire.jpg (99.32 KB) Musisz być zalogowany, aby pobrać ten załącznik.
    • Komunikacja ATmega16 z DS18B20 - brak odpowiedzi czujnika, rezystor 2.2k zamiast 4.7k disassembly.jpg (45.32 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • REKLAMA
  • #2 2120116
    snow
    Poziom 31  
    Posty: 1825
    Pomógł: 178
    Ocena: 201
    Zobacz czy w Makefile masz ustawione F_OSC na takie z jakim pracuje ci procesor. Mi działał z rezystorem nawet 1,2k
  • REKLAMA
  • #3 2120345
    juntom
    Poziom 19  
    Posty: 216
    Pomógł: 35
    Ocena: 27
    Na 1 rzut oka w procedurze inicjacji najpierw ustawiasz na pinie 1wire 0 a dopiero potem ustawiasz tryb pracy na wyjscie.Zmien kolejnosc i wowczas sproboj.
    pozdr.
  • #4 2121026
    CrazyCat
    Poziom 11  
    Posty: 6
    Błąd polegał, na odwrotnym podłączeniu czujnika (sic!). Ale mi wstyd. 3 dni pracy stracone!
    Dziękuję za chęć pomocy...
    Te procedurki powyżej działają bezbłędnie.
  • REKLAMA
  • #5 2526719
    maly35
    Poziom 14  
    Posty: 91
    Pomógł: 6
    Ocena: 2
    Tochę stary temat ale może ktoś jeszcze obserwuję.
    Poszukuję procedury opóźnijącej dla kwarcu 16MHz. Ta w powyższym programie nie może być bo przy podstawieniu mnożnika 16 wynik przekroczy zakres char. Zmieniłem na int ale niestety nie działa:(

    Byłbym wdzięczny za wszelką pomoc.

    Zmieniłem oscylator na 1MHz wewnętrzny i mój kod wygląda tak:

    #include <avr/io.h>
    #include <stdlib.h>
    
    unsigned char temp;
    
    void delay_1_wire(unsigned int t)
    {
    	do
    	{
    		asm("nop");
    	}
    	while(--t);
    
    
    }
    
    
    unsigned char init_1wire (void)
    {
    	unsigned char stan=1;
    	DDRA = 0xff;
    	PORTA = 0x00;
    	delay_1_wire((480/7)-6);
    	DDRA = 0x00;
    	delay_1_wire((50/7)-6);
    	if (bit_is_clear(PINA,0)){
    		stan=0;
    		}
    	delay_1_wire((410/7)-6);
    	
    	return(stan);
    }
    
    int main(void)
    {
    	DDRC=0xff; // Port B jako wyjścia
    	PORTC=0x00;
    	temp = init_1wire();
    	if (temp==0){
    		PORTC=0xff;
    	}
    	while(1){};
    
    }


    Czujnik to DS18b20 podłączony Vcc do +5V, DQ przez R=4,7k do +5V i do portu A na PIN0, GND do GND. Niestety nie wchodzi mi do ifa w procedurze init_1wire. Gdzie leży błąd - już drugi dzień próbuję uruchomić tego DS'a. Może walnięty?
  • #6 2527576
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    maly35 napisał:

    ...
    delay_1_wire((480/7)-6);
    ...
    }[/code]
    ...

    Ciekawym , skądeś wytrzasnął takie wyliczenia , bo mnie za nic nie daje to 480 uS ;)
    Po skompilowaniu bez optymalizacji miast 480 uS wychodzi >1000 uS , a dla optymalizacji -Os 319 uS.Najlepiej zaprząć symulator i wtedy wszystko jest jasne ;)

    Piotrek
  • #7 2528095
    maly35
    Poziom 14  
    Posty: 91
    Pomógł: 6
    Ocena: 2
    No właśnie wiem że czasy są do d... ale nie mogę rozgryźć jak je obliczyć:cry: Podstawiłem tak jak kolega napoczątku.
    Fakt, że jestem dopiero początkujący - może napisałbyć coś więcej o tym symulatorze? Programuję w WinAvr i tylko z tym miałem styczność dotej pory:D

    Albo najlepiej wstawił swoją funkcję opóźniającą ze wzorem:D

    Poszedłem za głosem "zumka" i odpaliłem VMLAB. Pierwszy raz więc nie zabardzo wiedziałem o co chodzi. Po godzince (trochę widać w nauce oporny jestem :D) dałem radę odczytać czasy :D przy okazii dowiedzieć się o optymalizcji :D i DS odpowiada

    ZUMEK - WIELKIE DZIĘKI
  • #8 2528460
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    maly35 napisał:

    ...
    Fakt, że jestem dopiero początkujący - może napisałbyć coś więcej o tym symulatorze? Programuję w WinAvr i tylko z tym miałem styczność dotej pory:D

    TEN ;) symulator , to AVRStudio 4.12. Za jednym zamachem masz środowisko dla asemblera, gcc-avr i symulator.

    maly35 napisał:

    Albo najlepiej wstawił swoją funkcję opóźniającą ze wzorem:D

    Standardowa z GCC:
    
    #include <util/delay.h>
    ...
    _delay_us(480);
    ...
    

    I po co wyważać otwarte drzwi :?: ;)
    Piotrek
  • #9 2529270
    pgp
    Poziom 19  
    Posty: 412
    Pomógł: 6
    Ocena: 17
    Polecam wizytę w laboratorium na oscyloskopie albo analizatorze stanów logicznych. Zrób sobie jakąś funkcję zmieniającą stan lini z we na wy i zanotuj sobie czasy dla kilku argumentów. Albo dobierz argumenty tak aby mieć wszystkie interwały które sa Ci potrzebne...
  • #10 2529415
    maly35
    Poziom 14  
    Posty: 91
    Pomógł: 6
    Ocena: 2
    Cytat:
    TEN Wink symulator , to AVRStudio 4.12. Za jednym zamachem masz środowisko dla asemblera, gcc-avr i symulator.

    maly35 napisał:

    Albo najlepiej wstawił swoją funkcję opóźniającą ze wzorem:D

    Standardowa z GCC:
    Kod:

    #include <util/delay.h>
    ...
    _delay_us(480);
    ...

    I po co wyważać otwarte drzwi Question Wink


    Rzeczywiście odpaliłem sobie AVRStudio i jestem zadowolony bo wszystko fajnie widać:D
    Funkcję opóźniającą stosuję

    void _delay_loop_1(uint8_t __count)
    {
    	__asm__ volatile (
    		"1: dec %0" "\n\t"
    		"brne 1b"
    		: "=r" (__count)
    		: "0" (__count)
    	);
    }


    prosto obliczyć wartość bo dla 1MHz = wart * 3 a dla innej (wart *3)/freq.
    Niestety nie da się jej wykorzystać dla 16MHz bo nie uzyskam tak dużego czasu jak 480us
  • REKLAMA
  • #11 2529460
    adamusx
    Poziom 27  
    Posty: 977
    Pomógł: 94
    Ocena: 28
    Witam
    Da sie uzyskac takie czasy z kwarcem 16Mhz.
    Wystarczy ze zamiast preocedurki opozniajace _delay_loop_1 dasz _delay_loop_2 - Po pierwsze mozna wpisac wartosc maks do 65536 a po drugie petla zajmuje 4 cykle procesora.
  • #12 2531545
    maly35
    Poziom 14  
    Posty: 91
    Pomógł: 6
    Ocena: 2
    OK. Poradziłem sobie z czasami. Narazie robię dla 1MHz.

    Jeżeli chodzi o kwarc 16MHz to myślałem żeby zrobić coś podobnego jak delay_loop_2(). Dzięki za wskazanie bo bym sam się męczył a tu obok nie zauważyłem gotowa funkcja:D

    Teraz brnę z moim termometrem dalej i znowu nie wiem co nie gra:cry:

    Oto kod:

    unsigned char ow_reset(void) // reset lini one wire
    {
    	unsigned char presence=1;
    	DDRA |= _BV(0); //DQ = 0; //pull DQ line
    	_delay_loop_1(155);
    	DDRA &= ~_BV(0); //DQ = 1; // allow line to //powrót lini 1w do trybu wejścia
    	_delay_loop_1(23);// wait for presence pulse(pochodzący od DS-a) //czekamy na ustabilizowanie lini
    	if(bit_is_clear(PINA,0)) presence=0; //odczytujemy co wystawił na linię DS
    	_delay_loop_1(133);// 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;
    	DDRA |= _BV(0); 	//DQ = 0; // pull DQ low to start timeslot
    	DDRA &= ~_BV(0);	//DQ = 1; // then return high
    	_delay_loop_1(5); // delay 15us from start of timeslot
    	if(bit_is_clear(PINA,0)) presence=0;
    	if(bit_is_set(PINA,0)) 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.
    {
    	DDRA |= _BV(0); //DQ = 0; // pull DQ low to start timeslot
    	if(bitval==1) DDRA &= ~_BV(0); //DQ =1; // return DQ high if write 1
    	_delay_loop_1(34); // hold value for remainder of timeslot - delay 104us
    	DDRA &= ~_BV(0);//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_loop_1(40); // ??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_loop_1(34);
    
    }
    
    ///---------------------------------------------------------
    
    void Read_Temperature(void)
    {
    	char tmp[12];
    	char temp_lsbyte,temp_msbyte;
    	int k,i;
    
    	LCD_clr();
    	if(ow_reset()) {LCD_xy(0,0); write_text("cisza");}
    	else
    	{
    		write_byte(0xCC); //Skip ROM
    		write_byte(0x44); // Start Conversion
    		_delay_loop_1(255);
    		_delay_loop_1(50);	//wyjdzie ok 950us
    		ow_reset();
    		write_byte(0xCC); // Skip ROM
    		write_byte(0xBE); // Read Scratch Pad
    		LCD_xy(0,0);
    		for (k=0;k<8;k++){
    			tmp[k]=read_byte();
    			i = i+tmp[k];
    			}
    		
    		//printf("DAT=%X%X%X%X%X",tmp[8],tmp[7],tmp[6],tmp[5],tmp[4],tmp[3],tmp[2],tmp[1],tmp[0]);
    		temp_msbyte = tmp[1]; // Sign byte + lsbit
    		
    		temp_lsbyte = tmp[0]; // Temp data plus lsb
    		write_char(temp_lsbyte);
    		if (temp_msbyte <= 0x80){temp_lsbyte = (temp_lsbyte/2);} // shift to tmp whole degree
    		temp_msbyte = temp_msbyte & 0x80; // mask all but the sign bit
    		if (temp_msbyte >= 0x80) {temp_lsbyte = (~temp_lsbyte)+1;} // twos complement
    		if (temp_msbyte >= 0x80) {temp_lsbyte = (temp_lsbyte/2);}// shift to tmp whole degree
    		if (temp_msbyte >= 0x80) {temp_lsbyte = ((-1)*temp_lsbyte);} // add sign bit
    		LCD_xy(0,1);
    		write_char(temp_lsbyte);
    		
    		//printf( "TempC=%d C", (int)temp_lsbyte ); // print temp. C
    		temperature=temp_lsbyte;
    }
    }
    
    int main (void)
    
    {	
    	lcd_init();
    
    	LCD_clr();
    	DDRA=0x00;
    	PORTA=0x00;
    	DDRC=0xff;
    	/*DDRC=0xff; // Port B jako wyjścia
    	PORTC=0x00;
    	temperatura=ow_reset();
    	if (temperatura==0)
    		PORTC=0xff;
    	*/
    	Read_Temperature();
    	while(1)
    	{
    	}
    	
            
    } 


    Oraz fukcje do obsługi LCD:

    void write_to_lcd(char x)
    {
    	SET_E;
    	out_nibble(x >> 4);
    	CLR_E;
    	SET_E;
    	out_nibble(x);
    	CLR_E;
    	_delay_ms(1);
    	
    	//delay_ms(1);
    }
    
    void write_command(char x)
    {
    	CLR_RS;
    	write_to_lcd(x);
    }
    
    void write_char(char x)
    {
    	SET_RS;
    	write_to_lcd(x);
    }
    
    void write_text(char * s)
    {
    	while(*s)
    	{
    		write_char(*s);
    		s++;
    	}
    }


    Problem polega na tym, że zabardzo nie wiem jak wyświetlić na LCD teraz tą temperaturę:cry:

    W funcji odczytu temp wyświetlam 2 razy :

    write_char(temp_lsbyte);


    na końcu i napoczątku - pierwsze wyświetla mi "P", drugie "("
    Co jest grane?
    Myślę, że problemem może być fakt, że używam DS18B20, a tam zdaje się jeszcze trzeba skonfigurować rejestr żeby był wynik 9-bitowy a nie standardowo 12-bitowy. Niestety nie mam pojęcia jak to zrobić - może ktoś używał właśnie tego układu a nie DS1820.


    Czasy w poszczególnych fukcjach powinny być ok bo sprawdzałem na symulatorze (jeszcze raz dzięki zumek), funcje LCD napewno działa bo mogę wyświetlić przykładowy napis. Może być też problem, że fukcja write_char() jest do wyświetlania tylko jednego znaku. No cóż błędów może być sporo więc liczę na uwagi bardziej doświadczonych kolegów.

    Z góry dzięki i WESOŁYCH ŚWIĄT:D:D

    Poprawiłem to:

    char buffer[4]="    ";                
    
               utoa(temp_lsbyte,buffer,10);
    	   write_text(buffer);


    No i wyświetla mi "40" - myślę że chyba błąd tkwi w tym że używam DS18B20:cry: Ale jak go skonfigurować:?:
  • #13 2531980
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    maly35 napisał:

    ...
    Poprawiłem to:

    char buffer[4]="    ";                
    
               utoa(temp_lsbyte,buffer,10);
    	   write_text(buffer);


    No i wyświetla mi "40" - myślę że chyba błąd tkwi w tym że używam DS18B20:cry: Ale jak go skonfigurować:?:

    Hmmm...
    DS zwraca temperaturę w postaci INT , a nie UNSIGNED INT :(
    Nie wnikając w szczegóły:
    
    ...
    union {
    int tds;
    char nds[2];
    }ds;
    
    char buf[6];
    
    int main(void)
    {
    //...
    //odczyt danych o temperaturze z DS-a (2 bajty) ...
    	ds.nds[0]=read_byte();
    	ds.nds[1]=read_byte();
    	itoa(ds.tds/16,buf,10);//temper. całkowita
    	write_text(buf);
    //i jeśli chcemy rozdzielczość 0.1 C , to dopisujemy ...
        write_text(".\0");
    	itoa(abs((ds.tds*10/16)%10),buf,10);
    	write_text(buf);
    //----------------------------------------------------------------
    //lub prościej  ale bardziej pamięciożernie (rozdz 0.1 C)
        dtostrf(((double)(ds.tds*10/16))/10,3,1,buf);
    	write_text(buf);
    //...
    return(0);
    }
    

    Bez solidnych "studiów" nad kompilatorem i DS-em ... wróżę kłopoty :(

    Piotrek

    PS
    Dotyczy DS-a w trybie 12-bit.
  • #14 2532245
    maly35
    Poziom 14  
    Posty: 91
    Pomógł: 6
    Ocena: 2
    Szczerze niezabardzo rozumiem ten zapis:

    union {
    int tds;
    char nds[2];
    }ds;


    No ale wpisałem to co zaleciłeś i otrzymuję teraz "85". Czytałem gdzieś, że to oznacza brak pomiaru:cry: Co z tym zrobić?

    Zmieniony kod:

    if(ow_reset()) {LCD_xy(0,0); write_text("cisza");}
    	else
    	{
    		write_byte(0xCC); //Skip ROM
    		write_byte(0x44); // Start Conversion
    		_delay_loop_1(255);
    		_delay_loop_1(50);	//wyjdzie ok 950us
    		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/16,buf,10);//temper. całkowita
       		write_text(buf);
    	}


    Co do dokumentacji to mielę ją non-stop, ale widać pojemny nie jestem:D Dużo lepiej uczy mi się na przykładach więc byłbym wdzięczny jakbyś podrzucił cały kod - wiedziałbym czy przypadkiem nie mam też gdzieś błędu w montażu.

    Dodam też że bawiłem się trochę przed twoim postem i wpisałem takie coś:

    write_byte(0x4E);
    		write_byte(0x05);
    		write_byte(0x50);
    		write_byte(0x1F); 


    Niby miało to zmienić rozdzielczość DS'a na 9-bitów ale żadnej różnicy nie zobaczyłem więc nawet nie wiem czy zadziałało - mam tylko nadzieję że nie zawaliłem tym DS'a


    DZIAŁA:D:D:D:D:D:D
    Oczywiście błąd leżał po mojej stronie:D Nie wiem co mi sie pomieszało ale ustawiałem czas konwesji większy ale od 750us, zmiana na 750ms pomogła. Mam w domu 23.3:D:D:D

    Dzięki wszystkim a w szczególności zumkowi (za cierpliwość, z tak miernym uczniem:D) Dziś zasnę spokojnie:!:
  • #15 2533414
    maly35
    Poziom 14  
    Posty: 91
    Pomógł: 6
    Ocena: 2
    Ale mam jeszcze jedno pytanie do zumka:)
    Mierzę według powyższego kodu i LCD wyświetla mi np. 22,2 stopnia, 23,3 stopnia itd. W czym mi się wydaje że jest błąd: stopnie całkowite wyświetla prawidłowo (patrząc na zwykły termometr umieszczony obok), ale dziesiętne wydaje mi się, że kopiuje ostatnią całkowitą:cry:
  • #16 2534747
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    maly35 napisał:
    Ale mam jeszcze jedno pytanie do zumka:)
    Mierzę według powyższego kodu i LCD wyświetla mi np. 22,2 stopnia, 23,3 stopnia itd.
    ...

    Według kodu ...
    
    ...      
          ds.nds[0]=read_byte();
             ds.nds[1]=read_byte();
             itoa(ds.tds/16,buf,10);//temper. całkowita
             write_text(buf);
       }

    ... wyświetlasz tylko część całkowitą , więc skąd u Ciebie ułamek :?:

    Piotrek
  • #17 2536457
    maly35
    Poziom 14  
    Posty: 91
    Pomógł: 6
    Ocena: 2
    Oczywiście dodałem kawałek twojego kodu:D Nie wiem czemu powyżej go nie zamieściłem:idea:

    //i jeśli chcemy rozdzielczość 0.1 C , to dopisujemy ...
        write_text(".\0");
       itoa(abs((ds.tds*10/16)%10),buf,10);
       write_text(buf);


    Jeśli chodzi jednak o to, że źle wyświetla ułamki to po dokładnym sprawdzeniu, okazało się, że jednak chodzi chyba w porządku.

    Acha mam prośbę. Mógłbyś wyjaśnić zasadę dziłania:

    union {
    int tds;
    char nds[2];
    }ds;


    Jak to się dzieje, że temp czytamy z tds a zapisujemy ją przecież do nds?
  • #18 2537033
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    maly35 napisał:

    ...
    Acha mam prośbę. Mógłbyś wyjaśnić zasadę dziłania:

    union {
    int tds;
    char nds[2];
    }ds;


    Jak to się dzieje, że temp czytamy z tds a zapisujemy ją przecież do nds?

    Pytasz o podstawy języka C , więc polecam to:
    http://galaxy.uci.agh.edu.pl/~chwastek/lectures/C/tunie.html

    Piotrek

    PS
    Warto zapoznać się z całością ;)
  • #19 2774467
    Mendrek
    Poziom 12  
    Posty: 48
    Pomógł: 2
    Witam.

    Moze tez troche odgrzewam temat, ale chyba nie warto zakładać nowego topiku.

    Mam atmege8 na wewnętrzym zegarze 4Mhz, i ds18B20 podłączony: DQ do pina atmegi, Vcc do +5, Gnd do gnd :), oraz między DQ i Vcc rezystor 4k7.

    A to program:

    
    #define F_CPU 4000000UL
    
    #include <avr/io.h>
    #include <avr/delay.h>
    
    #define a 0
    #define b 1
    #define c 2
    #define d 3
    #define e 4
    #define f 5
    #define g 6
    
    #define TEMPPIN 0x01
    #define TEMPPORT PORTC
    #define TEMPPORTDIR DDRC
    #define TEMPPORTIN PINC
    
    const unsigned char segm[2][7] = {0x00,0x08,0x04,0x0C,0x18,0x14,0x10,0x1C,0x20,0x24,0x28,0x2C,0x30,0x34};
    //-----------------------------------------------------------------
    void Segment(unsigned char seg,unsigned char portc)
    {
    PORTC = (portc&(0x63))|seg;
    _delay_us(8);
    }
    //-----------------------------------------------------------------
    void Wyswietl(unsigned char liczba)
    {
    	
    unsigned char low,high;
    low = liczba%10;
    high = liczba/10;	
    unsigned char i=0;	
    unsigned char portc = 0;
    for(i=0;i<2;i++)	
    {	switch(high)
    	{
    		case 0:
    			{
    			  Segment(segm[i][a],portc);
    			  Segment(segm[i][b],portc);
    			  Segment(segm[i][c],portc);
    			  Segment(segm[i][d],portc);
    			  Segment(segm[i][e],portc);
    			  Segment(segm[i][f],portc);
    			  _delay_us(8);
    			  break;
    			}
    		case 1:
    			{
    			  Segment(segm[i][b],portc);
    			  Segment(segm[i][c],portc);
    			  Segment(segm[i][b],portc);
    			  Segment(segm[i][c],portc);
    			  Segment(segm[i][b],portc);
    			  Segment(segm[i][c],portc);
    			  _delay_us(8);
    			 break;
    			}
    		case 2:
    			{ 
    			  Segment(segm[i][a],portc);
    			  Segment(segm[i][b],portc);
    			  Segment(segm[i][d],portc);
    			  Segment(segm[i][e],portc);
    			  Segment(segm[i][g],portc);
    			  _delay_us(16);
    			 break;
    			}
    		case 3:
    			{
    			  Segment(segm[i][a],portc);
    			  Segment(segm[i][b],portc);
    			  Segment(segm[i][c],portc);
    			  Segment(segm[i][d],portc);
    			  Segment(segm[i][g],portc);
    			  _delay_us(16);
    			 break;
    			}
    		case 4:
    			{
    			  Segment(segm[i][b],portc);
    			  Segment(segm[i][c],portc);
    			  Segment(segm[i][f],portc);
    			  Segment(segm[i][g],portc); 
    			  _delay_us(24);
    			 break;
    			}
    		case 5:
    			{
    			  Segment(segm[i][a],portc);
    			  Segment(segm[i][c],portc);
    			  Segment(segm[i][d],portc);
    			  Segment(segm[i][f],portc);
    			  Segment(segm[i][g],portc);
    			  _delay_us(16);
    			 break;
    			}
    		case 6:
    			{
    			  Segment(segm[i][a],portc);
    			  Segment(segm[i][c],portc);
    			  Segment(segm[i][d],portc);
    			  Segment(segm[i][e],portc);
    			  Segment(segm[i][f],portc);
    			  Segment(segm[i][g],portc);
    			  _delay_us(8);
    			 break;
    			}
    		case 7:
    			{
    			  Segment(segm[i][a],portc);
    			  Segment(segm[i][b],portc);
    			  Segment(segm[i][c],portc);
    			  Segment(segm[i][a],portc);
    			  Segment(segm[i][b],portc);
    			  Segment(segm[i][c],portc);
    			  _delay_us(8);
    			 break;
    			}
    		case 8:
    			{
    			  Segment(segm[i][a],portc);
    			  Segment(segm[i][b],portc);
    			  Segment(segm[i][c],portc);
    			  Segment(segm[i][d],portc);
    			  Segment(segm[i][e],portc);
    			  Segment(segm[i][f],portc);
    			  Segment(segm[i][g],portc);
    			  break;
    			}
    		case 9:
    			{
    			  Segment(segm[i][a],portc);
    			  Segment(segm[i][b],portc);
    			  Segment(segm[i][c],portc);
    			  Segment(segm[i][d],portc);
    			  Segment(segm[i][f],portc);
    			  Segment(segm[i][g],portc);
    			  _delay_us(8);
    			 break;
    			}
    	}
    high = low;
    }
    PORTC = portc|~(0x63);
    return;
    }
    //-----------------------------------------------------------------
    unsigned char init1wire(void)
    {
    	unsigned char stan;
    
    	TEMPPORT &= ~TEMPPIN;		// ustawia 0 na wyjscie	
    	TEMPPORTDIR |= TEMPPIN;		// ustawia pin jako wyjscie
    	_delay_us(480);				// mamy 0 i czekamy 480 us
    
    	TEMPPORTDIR &= ~TEMPPIN;	// ustawiamy na wejscie
    	_delay_us(70);				// czas na zgloszenie slavea
    	stan = TEMPPORTIN & TEMPPIN;// jezeli slave sie zglosil, to stan = 0
    	_delay_us(410);				// 410 us po zgloszeniu sie slave
     
    	return stan;
    
    }
    //-----------------------------------------------------------------
    int main()
    {
    	DDRC = 0xff;
    	PORTC = 0xff;
    	unsigned char stan;
    	_delay_us(200);
    	stan = init1wire();
    	while(1)
    	{
    	 Wyswietl(stan);
    	}
    	return (0);
    }
    


    Nie wiem czemu, ale jak nie ma DS'a to na wyslwietlaczu pojawia mi się 0 a jak podłącze DS'a to mam 1. Powinno chyba być na odwrót? Wiecie co może być źle?
    Czy procedury opóźniające są dobrze zastosowane?
    Czy procedury opóźniające z gotowego pliku "delay.h" są dokładne?

    Z góry dzięki za pomoc.

    Pozdrawiam

Podsumowanie tematu

✨ Dyskusja dotyczy problemów z komunikacją mikrokontrolera ATmega16 z czujnikiem temperatury DS18B20, głównie braku odpowiedzi czujnika na magistrali 1-Wire. Autor początkowo stosował rezystor podciągający o wartości 2.2 kΩ zamiast zalecanego 4.7 kΩ, co mogło wpływać na stabilność sygnału, jednak ostatecznie problemem okazało się odwrotne podłączenie czujnika. Wątek porusza również kwestie precyzyjnego generowania opóźnień czasowych w kodzie asemblerowym i C dla różnych częstotliwości taktowania (1 MHz i 16 MHz), z wykorzystaniem funkcji _delay_loop_1 i _delay_loop_2 oraz symulatora AVRStudio. Omówiono także interpretację danych temperatury odczytywanych z DS18B20, w tym konwersję wartości 16-bitowej (typ int) na format dziesiętny z rozdzielczością 0.1°C, wykorzystując unie w języku C do mapowania bajtów na wartość całkowitą. Wskazano na konieczność stosowania rezystora podciągającego 4.7 kΩ na linii danych 1-Wire oraz poprawne sekwencje inicjalizacji i odczytu danych. Poruszono także temat debugowania sygnałów za pomocą oscyloskopu lub analizatora stanów logicznych. W dalszej części dyskusji pojawiły się przykłady kodu do obsługi DS18B20 z mikrokontrolerem ATmega8 na wewnętrznym zegarze 4 MHz, z wykorzystaniem rezystora 4.7 kΩ oraz wyświetlaniem temperatury na wyświetlaczu segmentowym.
Wygenerowane przez model językowy.
REKLAMA