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

[Atmega8][USART] Problem z RXD.

lord_dagoth 24 Lip 2010 19:23 2276 4
  • #1 8326027
    lord_dagoth
    Poziom 25  
    Witam,
    Od kilku dniu próbuję uporać się z komunikacją po RS485, no i napotkałem problem z którym sobie nie radzę.

    Korzystam z płytki testowej ZL2AVR ( http://www.btc.pl/pdf/zl2avr.pdf ) oraz układu MAX485 ( http://ecee.colorado.edu/~mcclurel/max485ds.pdf ) (pomiędzy zasilanie a masę kondensatory 47uF i 100nF, piny !RE i DE połączone razem i podłączone do PB0 uC, RO do RxD od uC, a DI do TxD, B idzie do wejścia przejściówki -485, A do +485, pomiędzy A i B jest opornik 120, przejściówka to kupiony konwerter RS485 na USB zrobiony na FTDI).

    Z wysyłaniem nie ma problemów. Procesor wszystko ładnie wysyła i komputer odbiera. Problem pojawia się przy próbie odbierania. Tuż po włączeniu uC zaczyna odbierać bez przerwy losowe znaki (a nic nie wysyłałem przez terminal). Gdy podłączyłem oscyloskop do pinu RxD od uC układ nagle zaczął częściowo działać. Odbierał jeden bajt poprawnie, następnie drugi bajt 0x00, potem znowu kolejny poprawnie i kolejny 0x00, i tak cały czas. Po odłączeniu oscyloskopu znowu zaczął wariować i w kółko odbierać losowe bajty. Próbowałem programowo podciągać pin RxD pull-up'em, ale nic to nie zmieniło, również dawałem w różnych miejscach opóźnienia, żeby sprawdzić czy może gdzieś za krótko trwa jakiś stan albo coś nie zdążyło się zmienić - no i nadal nic.

    Zamieszczam fragment programu, z którym mam problem (Atmega pracuje na zewnętrznym kwarcu 8MHz).

    #define F_CPU 8000000UL
    
    #include <avr/io.h>
    #include <util/delay.h>
    
    #define USART_BAUD 9600ul
    #define USART_UBBR_VALUE ((F_CPU/(USART_BAUD<<4))-1)
    
    void USART_Init()
    {
    	UBRRH = (uint8_t)(USART_UBBR_VALUE>>8);
    	UBRRL = (uint8_t)USART_UBBR_VALUE;
    	UCSRB = (1<<RXEN)|(1<<TXEN);
    	UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
    }
    
    void USART_Transmit(unsigned char c)
    {
    	while (!( UCSRA & (1<<UDRE))) {};
    	UDR = c;
    	while (!( UCSRA & (1<<UDRE))) {};
    }
    
    unsigned char USART_Receive( void )
    {
    	/* Wait for data to be received */
    	while ( !(UCSRA & (1<<RXC)) ){};
    
    	/* Get and return received data from buffer */
    	return UDR;
    }
    
    void USART_SendString(unsigned char* s, int size)
    {
    	int i;
    	for(i=0;i<size;i++)
    	{
    		USART_Transmit(s[i]);
    	}
    }
    
    int main(void)
    {
    	unsigned char data;
    	char licznik = '1';
    
    	//PB0 jako wyjscie, do sterowania kierunku transmisji max485
    	DDRB |= (1<<0);
    
    	USART_Init();
    
    	while(1)
    	{
    		//max485 na wysylanie
    		PORTB |= (1<<0);
    
    		USART_SendString("Podejscie: ",11);
    		USART_Transmit(licznik);
    		USART_Transmit('\n');
    		
    		//max485 na odbieranie
    		PORTB &= ~(1<<0);
    		data = USART_Receive();
    
    		//max485 na wysylanie
    		PORTB |= (1<<0);
    		USART_SendString("Odebralem: ",11);
    		USART_Transmit(data);
    		USART_Transmit('\n');
    
    		licznik++;
    	}
    }


    Naprawdę nie rozumiem, dlaczego po podłączeniu oscyloskopu odbiera prawie poprawnie (oprócz tego ekstra bajtu 0x00), a po odłączeniu szaleje. Wysyłanie działa dobrze, więc to raczej nie kwestia Baud Rate'a czy jakiś innych ustawień. Może musze dać jakiś zewnętrzny rezystor podciągający?
  • Pomocny post
    #2 8327918
    tmf
    VIP Zasłużony dla elektroda
    A magistralę rs485 masz z terminatorem i rezystorami wymuszającymi stan w spoczynku, czy tak sobie luźno wisi?

    Dodano po 37 [sekundy]:

    Weź pod uwagę, że ta magistrala wymaga właściwego spolaryzowania w stanie spoczynku.
  • #3 8328181
    lord_dagoth
    Poziom 25  
    hmm... mam tak jak napisałem, czyli pomiędzy A i B wychodzące z MAX'a rezystor 120, mam dodawać jeszcze jakieś? (któryś podciągać do plus'a a któryś do gnd? jakimi wartościami?) Bo widziałem schematy gdzie zamiast jednego terminatora to był trójstopniowy dzielnik.
  • Pomocny post
    #4 8328255
    tmf
    VIP Zasłużony dla elektroda
    Musi być coś co polaryzuje linie w spoczynku. Zwykły transceiver RS485 musi mieć sygnał różnicowy>200mV, poniżej tej wartości działanie jest niezdefiniowane. Dodatkowo przy braku takiej polaryzacji każde zakłócenie generuje odpowiedź, co właśnie obserwujesz. Daj rezystor od A do Vcc i od B do GND, wartość około 680 om.
  • #5 8328482
    lord_dagoth
    Poziom 25  
    Ok, dzięki za odpowiedź! Jutro zmontuje i dam znać czy pomogło.

    EDIT: Bomba! dodanie tych rezystorów pomogło, wszystko działa! Dzięki za pomoc :D
REKLAMA