Elektroda.pl
Elektroda.pl
X
Tektronix
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[Atmega8][USART] Problem z RXD.

24 Lip 2010 19:23 2090 4
  • 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).

    Code:
    #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?
  • Tektronix
  • Pomocny post
    Moderator Mikrokontrolery Projektowanie
    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.
  • Tektronix
  • 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
    Moderator Mikrokontrolery Projektowanie
    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.
  • 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