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

[atmega88][C][DS18B20] Odczyt temperatury - 0x07FF

uowiec 08 Mar 2009 23:41 2699 2
  • #1 6256092
    uowiec
    Poziom 11  
    To mój pierwszy raz z DS18B20. Mam problem z odczytem temperatury z DS18b20. Pierwszy odczyt z układu daje warość 0x0550 czyli defaultowa wartosc po resecie.
    Jednak nastepne odczyty dają wartość 0x07FF. WTF?
    Poniżej listing. Procek taktowany 16MHz z zewnętrznego oscylatora. (F_CPU zdefiniowane na 16000000)
    
    int main () {
    	
    uint8_t a=0;
    uint8_t sp[9] = {0,0,0,0,0,0,0,0,0};
    	// podswietlenie LCD
    	backLightOn();
    	mcuInit();	
    	lcd_init(LCD_DISP_ON)
    	for (;;) {                           /* loop forever */
    		if ( second >= T0_SEC_VAL ) { // ta czesc kodu wykonuje sie raz na sekunde
    			second = 0;
    			(....)
    
    			lcd_clrscr();
    			// to tylko wyswietla na lcd wartosc bufora sp - scratchpad
    			for (uint8_t x = 0; x < 5; x++) {
    			   lcd_gotoxy(x*3,0);
    			   ultoa(sp[x], buff, 16);
    			   lcd_puts(buff);
    			}
    			for (uint8_t x = 0; x < 4; x++) {
    			   lcd_gotoxy(x*3,1);
    			   ultoa(sp[x+5], buff, 16);
    			   lcd_puts(buff);
    			}
    			
    			//odczyt temperatury z polecenia w poprzedniej petli
    			if (a >= 5 ){ // odczyt temperatury co 5 sekund
    				read_scratchpad(sp);
    				convert_temp();  //wywolanie nastepnej konwersji, ktoej wynik zostanie odczytany za 5 sekund
    				a=0;
    			}
    			else 
    				a++;
    		}
    	}
    	return 0;
    }
    
    
    uint8_t reset_onewire() {
        uint8_t r;
    	// set D0 to output
    	owOutput();
    	owHigh();
    	owLow();
        _delay_us(550);
        // set D3 back to input
    	owInput();
    	r =  (OW_PIN_REG & _BV(OW_BIT));
        _delay_us(500);
    	return r;
    }
    
    void write_onewire(uint8_t bit) {
    	
    	owOutput();
    	owHigh();
    
    	if (bit == 0) {
    		owLow();
    		_delay_us(65); // hold low for at least 60us
    		owHigh();
    	} else {
    		owLow();
    		_delay_us(10); // < 15us for 1 bit
    		owHigh();
    	}
    	owInput();
    	if (bit == 1)
            _delay_us(60); // just to pad out the rest of the slot to >60us
    
    }
    
    uint8_t read_onewire() {
        uint8_t result;
    	// set D3 to output
    	owOutput();
    	owHigh();
    	owLow();
    	_delay_us(2);
    	owInput();
    	_delay_us(10);
    	
    	result = (OW_PIN_REG & _BV(OW_BIT));
    	result = result ? 1 : 0; // always return either 1 or 0
        _delay_us(60); // make sure the slot is >60us long
        return result;
    
    
    }
    
    void write_onewire_byte(uint8_t command) {
        uint8_t i;
    	cli();
        for (i = 0; i < 8; i++) {
            write_onewire(command & 1);
            command >>= 1;
        }
    	sei();
    }
    
    uint8_t read_onewire_byte() {
        uint8_t r,i;
    	cli();
        r = 0;
        for (i = 0; i < 8; i++) {
            r |= (read_onewire() << (i));
        }
    	sei();
        return r;
    }
    
    void convert_temp() {
        reset_onewire();
        write_onewire_byte(0xCC); // skip ROM command
        write_onewire_byte(0x44); // convert T
    }
    
    uint16_t read_temp() {
        uint8_t scratchpad[9];
        read_scratchpad(scratchpad);
        // Just return the temp. in Celcius from the scratchpad.
        return ((scratchpad[1] << 8) | scratchpad[0]);
    }
    
    void read_scratchpad(uint8_t *scratchpad){
    	uint8_t i;
        for (i = 0; i < 9; i++) scratchpad[i] = 0;
        reset_onewire();
        write_onewire_byte(0xCC); // skip ROM
        write_onewire_byte(0xBE); // read scratchpad (9 bytes)
        for (i = 0; i < 9; i++) {
            scratchpad[i] = read_onewire_byte();
        }	
    }
    
    inline void owHigh() {
    	OW_PORT |= _BV(OW_BIT);
    }
    
    inline void owLow() {
    	OW_PORT &= ~_BV(OW_BIT);
    }
    
    inline void owInput() {
    	OW_DDR &= ~_BV(OW_BIT);
    }
    
    inline void owOutput() {
    	OW_DDR |= _BV(OW_BIT);
    }
    
    void mcuInit()
    {	
    
    	cli();
                //wszystkie porty jako wejscia z pullupami
    	DDRB = 0;
    	DDRC = 0;
    	DDRD = 0;
    	PORTB = 0xFF;
    	PORTC = 0xFF;
    	PORTD = 0xFF;
    
    	(...)
    	sei();
    }
    
    


    Kod okrojony, ale nie ma nic wspólnego z one wire.
    Linia do której podciągnięty jest DQ z DS-a ma pullupa 5K. Próby podłączenia z zasilaniem pasożytniczym i osobnym dają identyczne wyniki (oprócz odczytu zasilania). Jestem 100% pewny co do podłączenia pinów (aż 3) i co do timingów (odczyt romu i pierwszej temperatury 100% poprawny)
    Testy kodu na 2 DS-ach:
    odczyt ROMu - works perfect
    pierwszy odczyt scratchpada po resecie - [0-8] {0x50, 0x05, 0x4B, 0x46, 0x7F, 0xFF, 0x01, 0x10, 0x2F} temperatura 0x0550 czyli perfect
    oczyt scratchpada po pierwszej konwersji temperatury i następne w odstępach 5s - [0-8] {0xFF, 0x07, 0x4B, 0x46, 0x7F, 0xFF, 0x01, 0x10, 0x2F} za każdym razem temperatura 0x07FF !!!
    odczyt zasilania READ POWER SUPPLY [B4h] - perfect (wynik 0, czyli zasilanie parasite, 0xFF przy osobnym zasilaniu)

    Dodam jeszcze że między konwersją a jakąkolwiek aktywnością na linii onewire mam odstęp 5 sekund.
    Skończyły mi się pomysły. Jakieś sugestie?
  • #2 6257554
    kaktus_c++
    Poziom 18  
    nie zaszkodziło by gdybyś umieścił kompletny kod bo może jednak covert t nie jest wywoływany co 5 s. tylko znacznie częściej.
  • #3 6259830
    uowiec
    Poziom 11  
    Problem rozwiązany.
    W datasheet zalecany jest rezystor podciągający ok. 5k. Jednak dalej, jest informacja, że podczas niektórych operacji (m.in. przy konwersji temperatury) zapotrzebowanie na prąd, może wynieść 1,5 mA.
    5V/5kohm = 1mA max.
    Zmiana rezystora na 3,3k rozwiązało problem. Szkoda tylko że maxim jest mało konsekwentny w swojej dokumentacji :)

    Przy okazji, widziałem dużo postów na temat konwersji danych ze scratchpada do float-a. Dużo dzielenia, warunków, masek i problemów z liczbami ujemnymi, a wystarczy temperature zrzutować na signed int i pomnożyć razy kwant temperatury:

    temp = (int16_t) ((scratchpad[1] << 8) | scratchpad[0]) * 0.0625; //0.0625 - kwant temperatury dla rozdzielczości 12 bitowej
    


    Co lepsze, przy zmianie rozdzielczości najmniej znaczące bity są wyłączone, zatem jedyne co zmieia się w powyższej linijce to wartość kwantu.
REKLAMA