Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[ATmega8] [C] DS18B20 i problem z 1-wire

l0g0s 18 Jul 2009 22:58 3360 2
  • #1
    l0g0s
    Level 1  
    Mam problem z prawidłowym ustawieniem protokołu 1-Wire dla czujnika DS18B20. Ustawiałem i zmieniałem już wiele razy ale dalej otrzymuje -1028,06 st C . Pracuje na ATmega8 z wew. kwarcem 1Mhz.

    
    /* Szkielet prostego programu dla avr-gcc */
    
    #define F_CPU       1000000                     // 1MHz zegar procesora -> częstotliwość kwarcu
    
    
    
    #include <avr/io.h>
    #include <stdlib.h>
    #include <util/delay.h>
    #include <avr/pgmspace.h>
    #include "lcd_lib.h"
    
    
    //makra
    #define WE 0
    #define PORT1_WIRE PINB
    #define SET_1WIRE DDRB &=~_BV(WE)
    #define CLEAR_1WIRE DDRB |=_BV(WE)
    
    
    char buffer[8];
    
    //resetujemy magistrale
    unsigned char RESET_PULSE(void)
    {
    	unsigned char PRESENCE;
    	CLEAR_1WIRE;
    	_delay_us(500);
    	SET_1WIRE;
    	_delay_us(30);
    
    	if( bit_is_clear(PORT1_WIRE , WE ) )
    	{
    		PRESENCE = 1;
    	}
    	else
    	{
    		PRESENCE = 0;
    	}
    	
    	_delay_us(470);
    
    	if( bit_is_set( PORT1_WIRE , WE ) )
    	{
    		PRESENCE = 1;
    	}
    	else
    	{
    		PRESENCE = 0;
    	}
    	return PRESENCE;
    }
    
    void send(char value)
    {
    	CLEAR_1WIRE;
    	_delay_us(5);
    
    	if( value == 1)
    	{
    		SET_1WIRE;
    	}
    	_delay_us(65);
    	SET_1WIRE;
    }
    
    unsigned char read(void)
    {
    	unsigned char PRESENCE;
    	CLEAR_1WIRE;
    	_delay_us(1);
    	SET_1WIRE;
    	_delay_us(10);
    
    	if( bit_is_set(PORT1_WIRE , WE ) )
    	{
    		PRESENCE = 1;
    	}
    	else
    	{
    		PRESENCE = 0;
    	}
    	_delay_us(55);
    	
    	return PRESENCE;
    }
    
    void send_byte( char wartosc )
    {
    	unsigned char i;
    	unsigned char pom;
    
    	for( i=0; i < 8; i++ )
    	{
    		pom = wartosc>>i;
    		pom &= 0x01;
    
    		send(pom);
    	}
    	//_delay_us(100);
    }
    
    void send_temp( char wartosc )
    {
    	unsigned char i;
    	unsigned char pom;
    
    	for( i=0; i < 8; i++ )
    	{
    		pom = wartosc>>i;
    		pom &= 0x01;
    		
    		if( pom == 1)
    			LCDsendChar('1');
    		else
    			LCDsendChar('0');
    	}
    
    }
    
    unsigned read_byte(void)
    {
    	unsigned char wartosc;
    	unsigned char i;
    
    	for( i=0; i<8;i++)
    	{
    		if( read() )
    			wartosc |= 0x01<<i;
    		
    	}
    	return wartosc;
    }
    
    
    
    
    int main(void)
    {
    	char temp1 = 0, temp2 = 0;
    	unsigned char sprawdz;
    
    
    
      	LCDinit();
      	LCDclr();
    	LCDsendChar('a');
    	LCDsendChar('b');
    
    	_delay_ms(200);
      	
    	while(1)
    	{
    		sprawdz = RESET_PULSE();
    		if( sprawdz == 1 )
    		{
    			send_byte(0xCC);
    			send_byte(0x44);
    			_delay_ms(750);
    
    			sprawdz = RESET_PULSE();
    
    			if( sprawdz == 1 )
    			{
    				LCDGotoXY(10,1);
    				LCDsendChar('o');
    				LCDsendChar('k');
    			}	
    			send_byte(0xCC);
    			send_byte(0xBE);
    
    			temp1 = read_byte();
    			temp2 = read_byte();
    
    			sprawdz = RESET_PULSE();
    			LCDGotoXY(0,0);
    			send_temp(temp2);
    			send_temp(temp1);
    
    			float temp = 0;
    			temp = (float)temp1+(temp2*256);
    			temp = temp/16;
    			
    			dtostrf(temp,1,4,buffer);
    
    			LCDGotoXY(0,1);
    			LCDsendChar(buffer[0]);
    			LCDsendChar(buffer[1]);
    			LCDsendChar(buffer[2]);
    			LCDsendChar(buffer[3]);
    			LCDsendChar(buffer[4]);
    			LCDsendChar(buffer[5]);
    			LCDsendChar(buffer[6]);
    			LCDsendChar(buffer[7]);
    
    			_delay_ms(300);
    		}
    		else
    		{
    			LCDGotoXY(0,0);
    			LCDsendChar('l');
    			LCDsendChar('o');
    			LCDsendChar('l');
    		}
    			
    	}
    }
    
  • #2
    Brutus_gsm
    Level 25  
    Na szybko przeglądając kod, to nigdzie nie stosujesz podciągania portów. Np tutaj
    void send(char value)
    {
       CLEAR_1WIRE;
       _delay_us(5);
    
       if( value == 1)
       {
          SET_1WIRE;
       }
       _delay_us(65);
       SET_1WIRE;
    } 


    Robisz tylko SET_1WIRE, a więc ustawiasz kierunek na wyjściowy i nic więcej. Musisz też ustawić port w stan wysoki (albo nisko, w zależności od tego co chcesz wysłać). Poczytaj dokładnie specyfikację protokołu 1 wire.

    Ewentualnie tu masz moje jakieś stare funkcje do 1wire. Powinny działać. Ale nie gwarantuję. ;)

    /* PORT & PIN CONFIGURATION*/
    #define OW_PIN		2
    #define OW_DIR		DDRB
    #define OW_OUT		PORTB
    #define OW_IN		PINB
    
    #define OW_WRITE	OW_DIR |= (1<<OW_PIN)
    #define OW_READ		OW_DIR &= ~(1<<OW_PIN)
    
    #define OW_WRITE_1	OW_OUT |= (1<<OW_PIN)
    #define OW_WRITE_0	OW_OUT &= ~(1<<OW_PIN)
    
    #define OW_IS_SET	(OW_IN & (1<<OW_PIN))
    #define OW_IS_CLEAR	(!(OW_IN & (1<<OW_PIN)))
    
    /*1 wire reset */
    uint8_t reset_1w(void)
    {
    	uint8_t presence;	// zmienna obecnosci
    	OW_WRITE;			// port w trybie wyjscia
    	OW_WRITE_0;			// wyprowadzenie w stanie niskim
    	_delay_us(480);		// czekaj 480us
    	OW_READ;			// port w stanie wejscia
    	_delay_us(20);		// czekaj 20us
    	if(OW_IS_CLEAR)		// jeśli wyprowadznie w stanie niskim, to urzadzenie obecne
    		presence=1;		// ustaw zmienna obecnosci
    	else
    		presence=0;
    	_delay_us(480);		// czekaj 480us
    	
    	return presence;	// zwroc wartosc zmiennej obecnosci
    }
    
    uint8_t read_byte_1w(void)
    {
    	uint8_t byte=0, i;	// zmienne pomocnicze
    	for(i=0;i<8;i++)	// petla 8 razy
    	{
    		byte>>=1;		// przesun wynik o jeden bit w prawo
    		OW_WRITE;		// port w trybie wyjscia
    		OW_WRITE_0;		// wyprowadzenie w stanie 0
    		_delay_us(1);	// czekaj 1us
    		OW_READ;		// port w trybie wejscia
    		_delay_us(1);	// czekaj 1us
    		if(OW_IS_SET)	// sprawdz czy bit = 1
    			byte |= (1<<7);	// jesli tak, to dodaj na koncu 1
    		_delay_us(60);	// czekaj 60us
    	}
    	
    	return byte;
    }
    
    void write_byte_1w(uint8_t byte)
    {
    	uint8_t i;				// zmienna pomocnicza
    	for(i=0;i<8;i++)		// petla 8 razy
    	{
    		if(byte & 0x01)		// sprawdz czy ostatni bit = 1
    		{	
    			/* write 1 */
    			OW_WRITE;		
    			OW_WRITE_0;
    			_delay_us(10);
    			OW_READ;
    			_delay_us(70);
    		}
    		else
    		{
    			/* write 0 */
    			OW_WRITE;
    			OW_WRITE_0;
    			_delay_us(70);
    			OW_READ;
    			_delay_us(10);
    		}
    		byte>>=1;
    	}
    }
  • #3
    ksarim
    Level 15  
    Załączam sprawdzoną, działającą bibliotekę do 1-Wire. Opóźnienia są policzone dla kwarcu 16MHz. Skoro Ty wykorzystujesz kwarc 1MHz to wystarczy, że podzielisz przez 16 argumenty funkcji opóźniających. Jakbyś miał z tym problem to napisz. Gratis dorzucam też sprawdzoną i działającą funkcję do odczytu i konwersji temperatury z czujnika DS18B20.

    // odczytanie temperatury na czujniku
    void odczytaj_temperature()
    {
    	unsigned char lsb = 0;			// młodsze bity odczytane z czujnika temperatury		
    	unsigned char msb = 0;			// starsze bity odczytane z czujnika temperatury
    	unsigned char znak_temperatury;
    	unsigned char zp99;
    	owire_reset();					// sekwencja inicjalizująca
    	owire_write_byte(0xCC);			// rozkaz pomiń ROM
    	owire_write_byte(0x44);			// rozkaz konwertuj temperaturę
    	owire_reset();
    	owire_write_byte(0xCC);			// rozkaz pomiń ROM
    	owire_write_byte(0xBE);			// rozkaz umożliwiający odczytanie temperatury 
    	lsb = owire_read_byte();		// odczytanie młodszych bitów temperatury 
    	msb = owire_read_byte();		// odczytanie starszych bitów temperatury 
    	znak_temperatury = 1;			// do określenia znaku temperatury
    	// konwersja odczytanych z czujnika danych na temperaturę
    	if(msb & 0x80)					// sprawdzenie znaku temperatury	
    	{
    		lsb ^= lsb;					// konwersja ujemnej temperatury
    		msb ^= lsb;
    		if(lsb == 0xFF)
    			msb = msb + 1;
    		else
    			lsb = lsb + 1;	
    		znak_temperatury = 0;		// określa ujemny znak temperatury
    	}
    	zp1 = lsb & 0x0F;				// pozbycie się 4 najstarszych bitów(pozostała liczba wskazuje na wartości dzięsiętne temperatury)
    	lsb  = lsb >> 4;				// pozbycie się 4 najmłodszych bitów
    	msb  = msb << 4;				// pozbycie się 4 najstarszych bitów
    	if(znak_temperatury == 0 && (lsb + msb) > 0)// ujemna temperatura
    	{
    		w_temperatura[0] = '-';
    		zp99 = dBCD(lsb+msb) >> 4;;	// konwersja temperatury do kodu BCD i pozbycie się 4 najmodszych bitów
    		if(zp99 != 0)				// temperatura <= -10
    		{
    			w_temperatura[1] = 48 + zp99;
    			zp99 = dBCD(lsb+msb) & 0x0F;;// maska pozostawiająca 4 najmłodsze bity
    			w_temperatura[2] = 48 + zp99;
    			w_temperatura[3] = ',';
    			zp1 = (zp1*625)/1000;	// wartości po ,
    			w_temperatura[4] = 48 + zp1;
    			w_temperatura[5] = 'º';     // stopień
    			w_temperatura[6] = 'C';			
    		}
    		else						// temperatura > -10, < 0 
    		{
    			zp99 = dBCD(lsb+msb) & 0x0F;
    			w_temperatura[1] = 48 + zp99;
    			w_temperatura[2] = ',';
    			zp1 = (zp1*625)/1000;	// wartość po ,
    			w_temperatura[3] = 48 + zp1;
    			w_temperatura[4] = 'º';// stopień
    			w_temperatura[5] = 'C';
    		}
    	}
    	else							// dodatnia temperatura
    	{
    		zp99 = dBCD(lsb+msb) >> 4;
    		if(zp99 != 0)				// temperatura >= 10
    		{
    			w_temperatura[0] = 48 + zp99;
    			zp99 = dBCD(lsb+msb) & 0x0F;// maska pozostawiająca 4 najmłodsze bity
    			w_temperatura[1] = 48 + zp99;
    			w_temperatura[2] = ',';
    			zp1 = (zp1*625)/1000;	// wartość po ,
    			w_temperatura[3] = 48 + zp1;
    			w_temperatura[4] = 'º';// stopień
    			w_temperatura[5] = 'C';
    		}
    		else						// temperatura >= 0, < 10
    		{
    			zp99 = dBCD(lsb+msb) & 0x0F;
    			w_temperatura[0] = 48 + zp99;
    			w_temperatura[1] = ',';
    			zp1 = (zp1*625)/1000;	// wartosć po ,
    			w_temperatura[2] = 48 + zp1;
    			w_temperatura[3] = 'º';
    			w_temperatura[4] = 'C';
    		}
    	}
    }

    Otrzymana temperatura jest zapisywana do tablicy w kodzie ASCII. Przerobisz sobie do postaci jaka będzie Ci odpowiadała.

    Tak jak pisałem wcześniej wszystko jest sprawdzone. Jedyna rzecz, do której ktoś bardziej dociekliwy może się przyczepić jest to, że w funkcji odczytującej temperaturę z czujnika nie ma opóźnienia 750ms, które potrzebne jest czujnikowi na konwersję temperatury. Nie umieściłem tego opóźnienia świadomie bo zatrzymanie programu na tak długi okres czasu w przypadku mojego programu robiło dużą różnicę. Nie wstawiając opóźnienia nie miałem wyniku pomiaru z danej chwili a z wcześniejszego pomiaru ale nie traciłem czasu na czekanie na konwersję temperatury. Nie potrzebowałem takiej dokładności więc jeżeli będziesz potrzebował to wstawisz sobie te opóźnienie.