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

[C]Interfejs 1-Wire - zmiana linii danych

Szczeh 19 Maj 2010 23:36 1482 6
  • #1 8096758
    Szczeh
    Poziom 12  
    Witam,

    złożyłem niedawno czujnik temperatury oparty o układ DS18B20. Obecnie linia danych podpięta jest do pinu 0 portu D (RXD). Mam pytanie czy linia ta musi być podpięta pod RXD, czy też można podpiąć ją pod inny port mikroprocesora?

    Podczas pisania kodu korzystałem z pdf-a znalezionego w sieci. W nim kod odpowiedzialny za ustawienie linii danych wygląda nastepująco:
    #define PIN_1WIRE	0
    #define PORT_1WIRE	PIND
    
    #define OUT_1WIRE_LOW	PORT_1WIRE&=~(1<<PIN_1WIRE);
    #define OUT_1WIRE_HIGH	PORT_1WIRE|=1<<PIN_1WIRE;
    #define DIR_1WIRE_IN	DDRD&=~(1<<PIN_1WIRE);
    #define DIR_1WIRE_OUT	DDRD|=1<<PIN_1WIRE;
  • Pomocny post
    #2 8096916
    GSM
    Poziom 25  
    Witam,

    RXD jest alternatywną funkcją portu, UART lub USART - sprzętowe wsparcie dla szeregowej transmisji danych, nie korzystasz z tego przy implementacji 1wire.
    Możesz dowolnie zmienić pin procesora do którego będzie podłączony termometr.

    Pozdrawiam.
    GSM

    P.S.
    Kod który wkleiłeś pisał ktoś niekonsekwentny. Aby uzyskać łatwą zmianę używanego pinu, poza tym zawiera błąd w makrach OUT_*, powinno to wyglądać bardziej tak, poza tym są takie fajne makra jak sbi() oraz cbi() do set/reset-owania bitów w zmiennych/rejestrach, a zamiast 1<<BIT można używać, jeśli ktoś woli, makra _BV(BIT):
    
    #define PINNR_1WIRE 0
    #define DIR_1WIRE   DDRD
    #define PORT_1WIRE  PORTD
    #define PIN_1WIRE   PIND
    
    #define OUT_1WIRE_LOW   PORT_1WIRE&=~_BV(PINNR_1WIRE);
    #define OUT_1WIRE_HIGH  PORT_1WIRE|=_BV(PINNR_1WIRE);
    #define DIR_1WIRE_IN    DDRD&=~_BV(PINNR_1WIRE);
    #define DIR_1WIRE_OUT   DDRD|=_BV(PINNR_1WIRE);
    
  • #3 8097042
    Szczeh
    Poziom 12  
    Ok, dzięki za odpowiedź.
    Czyli teraz, żeby zmienić pin na np. PD5, wystarczy wstawić #define PINNR_1WIRE 5?

    [edit]
    jednak Twój kod nie działa (dla pinu PD0), czy da się to wszystko jakoś prościej zapisać, żeby zmiana pinu nie przysparzała tylu problemów?

    Z góry dzięki za odpowiedź.
  • #4 8098092
    GSM
    Poziom 25  
    A czemu nie działa? Może problem leży gdzie indziej.
    Proszę pokazać przykład użycia.

    Pozdrawiam,
    GSM
  • #5 8098362
    utak3r
    Poziom 25  
    Nie znam budowy atmeg, ale zaproponowany sposób zmiany stanu pinu przy dużym tempie może powodować powstanie problemu określanego mianem "read-modify-write". Na czym polega ten problem? zarówno odczyt, jak i zapis całego portu GPIO to nie jest tylko odczyt jakiegoś tam rejestru - to jest odczyt/zapis fizycznych pinów - a to trwa, zwłaszcza w przypadku niektórych rodzajów obciążeń dołączonych do pinów. Ten fakt pociąga za sobą niebezpieczeństwo, że w trakcie cyklu "odczyt, modyfikacja, zapis zmodyfikowanej wartości", stan tego portu się zmieni.

    Dlatego też, powinno się albo używać instrukcji zmieniających bezpośrednio dany pin, albo mieć gdzieś zmienną służącą jako shadow portu (a przynajmniej jego pinów wyjściowych).

    Ot, taka mała sugestia :) Zawsze należy ją mieć na uwadze, bo czasami może ona prowadzić do problemów, które wytropić jest zwyczajnie nie sposób - nawet z debuggerem. Wiem, że zaraz tutaj setka osób napisze, że używa takich konstrukcji od lat - co wcale nie oznacza, że tak się powinno robić :P
  • #6 8112217
    Szczeh
    Poziom 12  
    Kod całego programu wygląda tak:
    //#define F_CPU 12000000L
    #define F_CPU 8000000L
    #include <avr/io.h>
    #include <util/delay.h>
    
    #define PIN_1WIRE	0
    #define PORT_1WIRE	PIND
    
    #define OUT_1WIRE_LOW	PORT_1WIRE&=~(1<<PIN_1WIRE);
    #define OUT_1WIRE_HIGH	PORT_1WIRE|=1<<PIN_1WIRE;
    #define DIR_1WIRE_IN	DDRD&=~(1<<PIN_1WIRE);
    #define DIR_1WIRE_OUT	DDRD|=1<<PIN_1WIRE;
    
    
    
    char cStringBuffer[8];
    
    unsigned char uc1Wire_ResetPulse(void)
    {
    	unsigned char ucPresenceImpulse;
    	OUT_1WIRE_LOW;
    	DIR_1WIRE_OUT;
    	_delay_us(500);
    	DIR_1WIRE_IN;
    	_delay_us(45);
    
    	if(bit_is_clear(PORT_1WIRE, PIN_1WIRE))
    		ucPresenceImpulse=1;
    	else
    		ucPresenceImpulse=0;
    
    	_delay_us(470);
    
    	return ucPresenceImpulse;
    }
    
    void v1Wire_SendBit(char cBit)
    {
    	DIR_1WIRE_OUT;
    	_delay_us(5);
    
    	if(cBit==1)
    		DIR_1WIRE_IN;
    
    	_delay_us(80);
    	DIR_1WIRE_IN;
    }
    
    
    unsigned char uc1Wire_ReadBit(void)
    {
    	unsigned char ucBit;
    
    	DIR_1WIRE_OUT;
    	_delay_us(2);
    	DIR_1WIRE_IN;
    	_delay_us(15);
    
    	if(bit_is_set(PORT_1WIRE, PIN_1WIRE))
    		ucBit=1;
    	else
    		ucBit=0;
    
    	return(ucBit);
    }
    
    void v1Wire_SendByte(char ucByteValue)
    {
    	unsigned char ucCounter;
    	unsigned char ucValueToSend;
    
    	for(ucCounter=0; ucCounter<8; ucCounter++)
    	{
    		ucValueToSend = ucByteValue >> ucCounter;
    		ucValueToSend &= 0x01;
    		v1Wire_SendBit(ucValueToSend);
    	}
    
    	_delay_us(100);
    }
    
    unsigned char uv1Wire_ReadByte(void)
    {
    	unsigned char ucCounter;
    	unsigned char ucReadByte = 0;
    
    	for(ucCounter=0; ucCounter<8; ucCounter++)
    	{
    		if(uc1Wire_ReadBit())
    			ucReadByte|=0x01<<ucCounter;
    		_delay_us(15);
    	}
    
    	return(ucReadByte);
    }
    
    int main(void)
    {
    	DDRC = 0xff;
    	unsigned char ucReset;
    	char cTemperatureH=0, cTemperatureL=0;
    	float fTemperature=0;
    
    	for(;;)
    	{
    		ucReset=uc1Wire_ResetPulse();
    
    		if(ucReset==1)
    		{
    			v1Wire_SendByte(0xCC);
    			v1Wire_SendByte(0x44);
    			_delay_ms(750);
    			ucReset=uc1Wire_ResetPulse();
    			v1Wire_SendByte(0xCC);
    			v1Wire_SendByte(0xBE);
    			cTemperatureL=uv1Wire_ReadByte();
    			cTemperatureH=uv1Wire_ReadByte();
    			ucReset=uc1Wire_ResetPulse();
    
    			fTemperature=(float)(cTemperatureL+(cTemperatureH<<8))/16;
    
    			
    			_delay_ms(2000);
    		}/*if*/
    	}/*for*/
    }/*main*/
    


    mógłbyś napisać do czego służą funkcję sbi() i cbi()? Nigdy ich dotąd nie używałem.

    Z góry dzięki za odpowiedź
REKLAMA