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

[ATmega128][C] problem z konwersja temp. w ds18b20

fartuch 10 Cze 2008 10:18 2745 5
REKLAMA
  • #1 5231357
    fartuch
    Poziom 11  
    Problem polega na tyn, że odczytana z czujnika temperatura wynosi niezmiennie 85 C. Po wydaniu rozkazu konwersji odczekuje 1 sekundę zanim zacznę odczyt temp. czas wydaje mi sie wystarczająco długi, żeby ds zdążył z konwersją. Próbowałem również po wydaniu rozkazu konwersji próbkować stan linii danych i przechodziłem do odczytu, gdy ds zwolnił magistrale. W kółko to samo 85 C.
    Odczytane z ds'a zawartości rejestrów po komendzie read scratchpad zgadzają sie z domyślnymi. Komenda read rom również zwraca poprawna wartość. Ponadto probowałem zapisać scratchpad i potem go odczytać. Niestety odczytana wartość nie zgadza sie z zapisaną. Może to nasuwać wniosek, że coś jest źle z funkcją zapisu, ale przecież wykorzystuje się ją również przy wydawaniu komend rom, a w tym przypadku wszytko wydaje się być ok.
    Zgodnie z dokumentacją pull-up mam 4,7k, ale czytałem, że można zastosować mniejsze, tylko na jakiej podstawie ? Producent nic o tym nie pisze. Czy zbyt duży rezystor może być przyczyną tych problemów ?
    Może ktoś miał podobny problem i znalazł rozwiązanie ? Będę wdzięczny za pomoc.

    kod programu ( linia danych na PD1, kwarc 16MHz, zasilanie z Vdd)
    
    #include<avr/io.h>
    #include<avr/delay.h>
    #include<stdlib.h>
    #include "temp.h"
    #include "mylcd.h"
    
    
    #define SET_DQ DDRD &=~_BV(1)
    #define CLR_DQ DDRD |=_BV(1)
    #define BUS_IN DDRD &=~ _BV(1)
    #define PULL_BUS PORTD |= _BV(PD1)
    #define BUS_OUT DDRD |= _BV(1)
    #define DQ_IN PIND & _BV(1)
    
    // ROM COMMANDS
    #define READ_ROM 0x33
    #define SKIP_ROM 0xcc
    
    // FUNCTION COMMANDS
    #define WRITE_SCRATCHPAD 0x4e
    #define CONV_TEMP 0x44
    #define READ_SCRATCHPAD 0xbe
    
    uint8_t ow_reset(void)
    {
    	uint8_t presence;
    	
    	CLR_DQ;					// DQ = 0, generuj reset
    	_delay_loop_2(2000);	// czekaj > 480us; tutaj 500us
    	
    	SET_DQ;					// zwolnij linie danych
    	_delay_loop_2(280);		// czekaj az linie sie podciagnie i slave odpowie, tutaj 70us
    	
    	presence = DQ_IN;	// sprawsz stan linii (czy slave odpowiedzial)
    	_delay_loop_2(1640);		// czekaj az slave zwolni linie; 410 us 
    	
    	if(DQ_IN)  			// czy slave zwolnil linie ? 
    	presence = 0;				// tak
    	else presence = 1;			// nie
    	
    	SET_DQ;
    	
    	return presence;
    }
    
    uint8_t read_bit(void)
    {
    	uint8_t bit = 1; 
    	
    	CLR_DQ;				// DQ = 0;
    	
    	_delay_loop_2(8);	// czekaj > 1 us; 2us
    	
    	SET_DQ;
    							
    	
    	_delay_loop_2(8);	// czekaj < 15 us od poczatku slotu, 2 us na podciagniecie linii
    	
    	if(!(DQ_IN))
    	bit = 0;
    	
    	
    	
    	
    	_delay_loop_2(280);		// czekaj do konca slotu; 70 us
    	
    	SET_DQ;	
    	return bit;
    }
    
    void write_bit(char bit)
    {
    	
    	
    	if(bit)				// zapisz "1"
    	{	CLR_DQ;			// DQ = 0;
    		
    		
    		_delay_loop_2(28);	// czekaj > 1us; 7us
    		
    		SET_DQ;				// DQ = 1;
    		
    		_delay_loop_2(280);	// czekaj < 60 us; 70us
    	
    	}	
    	else					// zapisz "0"
    	{	CLR_DQ;				// DQ = 0;
    		_delay_loop_2(280);	// czekaj x, 60us < x < 120us; 70
    		
    		SET_DQ;				// DQ = 1;
    		
    		
    		_delay_loop_2(12);	// czekaj az linia sie podcianie, > 1us; 3us
    		
    	}
    	SET_DQ;
    }
    
    uint8_t read_byte(void)
    {
    	uint8_t i;
    	uint8_t value = 0;
    	
    	for(i = 0; i < 8; i++)
    	{
    		value >>= 1;
    		if(read_bit())
    			value |= 0x80;
    	}
    	_delay_loop_2(8);
    	
    	return value;
    }
    
    void write_byte(char byte)
    {
    	uint8_t i;
    	for(i = 0; i < 8; i++)
    	{
    		write_bit(byte & 0x01);
    		byte >>= 1;
    		
    		_delay_loop_2(8);	// czekaj na recovery miedzy slotami > 1us; 2us
    	}
    
    }
    
    
    
    
    int main(void)
    {
    	uint8_t data_tab[9]; // tablica danych pobranych z ds'a
    	uint8_t i;
    	uint8_t buffer[8];
    	uint8_t tmp;
    	
    	lcd_init();
    	PORTD = 0x00;
    
    
    while(1)
    {
    	
    	if(!ow_reset())
    	{
    		write_byte(SKIP_ROM);
    		write_byte(CONV_TEMP);
    		_delay_ms(250); // czekaj az skonczy konwersje
    		_delay_ms(250);
    		_delay_ms(250);
    		
    	}
    	
    	//while(!DQ_IN){}   // probkuj linie DQ, czekaj na koniec konwersji ;DQ= 1
    	
    	if(!ow_reset())
    		{
    		
    		write_byte(SKIP_ROM);
    		write_byte(READ_SCRATCHPAD);
    		for(i = 0; i < 9; i++)
    		{
    		data_tab[i] = read_byte();
    		}
    		
                   tmp= ((data_tab[1] << 4) & 0xf0) | ((data_tab[0] >> 4) & 0x0f);   
    		
    		write_command(0x01);
    		write_text("TEMP: ");
    		write_text(itoa(tmp, buffer,10)); // wyswietla temp na lcd
    		write_text(" C");
    		}
    		
    		
    	_delay_ms(1000); // czekaj sekunde przed nastepnym pobraniem temperatury
    	
    	
    }	
    	
    	
    	return 0;
    }
    
    
    
  • REKLAMA
  • #2 5231861
    wdogli
    Poziom 18  
    Witam.
    Wydaje mi sie ze masz cos naknocone z czasami.
    Po pierwsze to nie masz podanego makra:
    #define F_CPU 16000000UL
    po drugie wydaje mi sie ze:
    "void _delay_ms (double __ms)
    Wstrzymuje działanie programu na __ms milisekund, używając _delay_loop_2().
    Makro F_CPU powinno zawiarac częstotliwość zegara w hercach.
    Maksymalne możliwe wstrzymanie to 262.14 ms / (F_CPU w MHz)."
    To jest bardzo istotne.
    Pozdrawiam
  • REKLAMA
  • #3 5232175
    fartuch
    Poziom 11  
    F_CPU rzeczywiście nie jest podane, ponieważ zmodyfikowałem ta wartość w pliku delay.h

    a co do tych czasów to może masz racje, ale probowałem również sprawdzać stan linii Dq w czasie konwersji i nic to nie dało.

    o tym maksymalnym czasie 262.14ms/F_CPU doczytałem w pliku delay.h, jednak nie bardzo to rozumiem. skoro ja mam 16 Mhz to max. czas wychodzi mi 262.14/16 = 16.3 us. jakie w tym momencie ma znaczenie parametr funkcji, który jest typu double ?
  • REKLAMA
  • #4 5232660
    wdogli
    Poziom 18  
    Witam.

    Niestety nie mam zielonego pojęcia dlaczego tak jest :)
    Jednak tak jest i już. :)
    Poniżej zamieszczam mój program na Atmege162.
    Pozdrawiam.
  • REKLAMA
  • #5 5232786
    zumek
    Poziom 39  
    fartuch napisał:
    ... probowałem również sprawdzać stan linii Dq w czasie konwersji i nic to nie dało...

    A co może dać sprawdzanie linii DQ , w czasie konwersji :?:
    Temat DS18B20 był "wałkowany" tyle razy , że gdyby kolego tylko trochę poszukał , to nie było by tematu ;)
    Zapraszam do lektury.

    Piotrek
  • #6 5234620
    fartuch
    Poziom 11  
    chodziło mi o odczyt bitu, źle to ująłem.

    Niestety zabawa lutownicą nie rozwiązała mojego problemu, tak jak to miało miejsce w przypadku bohatera "lektury".

    EDIT:
    zmieniłem wartość rezystora pull-up o połowę ( połączyłem równolegle 2x4,7k). Teraz po zapisie scratchpada i odczycie go otrzymuje wartość zgodna z zapisywaną, czyli coś sie ruszyło. Nadal jednak nie działa konwersja (cały czas mam temp. 85 C). Po wydaniu komendy konwersji odczytuje bit z linii DQ i czekam aż będzie równy 1.
    while(!read_bit()) 
    { _delay_ms(100);}


    może ktoś ma jakiś pomysł na rozwiązanie tego problemu ?
REKLAMA