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

[atmega8L][c + winavr] rs232 - problem z transmisją

_sid 03 Sie 2010 19:43 1806 6
  • #1 8361584
    _sid
    Poziom 11  
    Witam,

    Mam problem z transmisją szeregową na ATMEGA8L. Próbowałem wszystkich znalezionych na forum możliwości ale nic nie pomogło.

    Może zacznę od połączeń:

    atmega8l <-> MAX3232 <-> PC

    MAX-sior (właściwie zamiennik SP3232ECP) podłączony jest według zaleceń datasheet'a. Miedzy MAX-em a PC-tem jest zwykły kabel rs232 (w sensie, że nie przejściówka usb).

    Te połączenia są raczej prawidłowe - zwarcie RX z TX za MAX-em powoduje echo.
    F_CPU ustawione na 8000000, na procku odpowiednie fusebity także. Baudrate = 19200.
    Kod na procku jedynie robi echo.

    Rezultaty:

    Po połączeniu terminalem (niestety zwykły hypertrm ...) z prędkością 19200 zamiast echa dostaje dziwne znaczki. Po połączeniu z prędkością 9600 lub 4800 - niektóre znaki są ok, a niektóre pozamieniane lub też krzaki.

    Jak już wspomniałem próbowałem zabawy z różnymi ustawieniami (F_CPU na 1000000 chyba też - ale jeszcze sprawdzę) ale nic nie pomogło - a że jestem laikiem jeśli chodzi o elektronikę to wolę się zapytać od razu na forum niż tracić czas na losowe próby z losowymi wartościami itp.

    Może ktoś ma listę najczęściej popełnianych błędów przy zabawie z UART-em ? :-)

    Oto kawałek kodu, który wrzucam na procka (obsługa UART-a jest z atmel-owskeigo datasheet-a):

    
    //=======================| MAIN |==========================
    int main( void )
    {
        unsigned char hex = 0;
    
        InitUART( 9600 );
        /* Enable interrupts => enable UART interrupts */
        _SEI();
    
        /* while FOREVER */
        for(;;)
        {
            hex = ReceiveByte();
            TransmitByte(hex);        
        }
        
        return 0;
    }
    
    //=======================| UART |==========================
    
    /* UART Buffer Defines */
    #define UART_RX_BUFFER_SIZE 512     /* 2,4,8,16,32,64,128 or 256 bytes */
    #define UART_TX_BUFFER_SIZE 128
    
    
    #define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1 )
    #if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )
        #error RX buffer size is not a power of 2
    #endif
    
    #define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1 )
    #if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK )
        #error TX buffer size is not a power of 2
    #endif
    
    
    /* Static Variables */
    static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];
    static volatile unsigned char UART_RxHead;
    static volatile unsigned char UART_RxTail;
    static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
    static volatile unsigned char UART_TxHead;
    static volatile unsigned char UART_TxTail;
    
    /* Initialize UART */
    void InitUART( unsigned long int baudrate )
    {
        unsigned char x;
    
        UBRRH = (unsigned char)(((F_CPU/(16UL*baudrate))-1)>>8);
        UBRRL = (unsigned char)((F_CPU/(16UL*baudrate))-1); 
       
        /* Enable UART receiver and transmitter, and both interrupts */
        UCSRB = ((1<<RXCIE) | (1<<RXEN) | (1<<TXEN));
        UCSRC = (1<<URSEL)|(1<<UCSZ0);
    
        x = 0;                 /* Flush receive buffer */
    
        UART_RxTail = x;
        UART_RxHead = x;
        UART_TxTail = x;
        UART_TxHead = x;
    }
    
    /* Interrupt handlers */
    ISR(USART_RXC_vect)
    {
        unsigned char data;
        unsigned char tmphead;
    
        data = UDR;                 /* Read the received data */
        /* Calculate buffer index */
        tmphead = ( UART_RxHead + 1 ) & UART_RX_BUFFER_MASK;
        UART_RxHead = tmphead;      /* Store new index */
    
        if ( tmphead == UART_RxTail )
        {
            /* ERROR! Receive buffer overflow */
        }
        
        UART_RxBuf[tmphead] = data; /* Store received data in buffer */
    }
    
    ISR(USART_UDRE_vect)
    {
        unsigned char tmptail;
    
        /* Check if all data is transmitted */
        if ( UART_TxHead != UART_TxTail )
        {
            /* Calculate buffer index */
            tmptail = ( UART_TxTail + 1 ) & UART_TX_BUFFER_MASK;
            UART_TxTail = tmptail;      /* Store new index */
        
            UDR = UART_TxBuf[tmptail];  /* Start transmition */
        }
        else
        {
            UCSRB &= ~(1<<UDRIE);         /* Disable UDRE interrupt */
        }
    }
    
    /* Read and write functions */
    unsigned char ReceiveByte( void )
    {
        unsigned char tmptail;
        
        while ( UART_RxHead == UART_RxTail )  /* Wait for incomming data */
            ;
        tmptail = ( UART_RxTail + 1 ) & UART_RX_BUFFER_MASK;/* Calculate buffer index */
        
        UART_RxTail = tmptail;                /* Store new index */
        
        return UART_RxBuf[tmptail];           /* Return data */
    }
    
    void TransmitByte( unsigned char data )
    {
        unsigned char tmphead;
        /* Calculate buffer index */
        tmphead = ( UART_TxHead + 1 ) & UART_TX_BUFFER_MASK; /* Wait for free space in buffer */
        while ( tmphead == UART_TxTail );
    
        UART_TxBuf[tmphead] = data;           /* Store data in buffer */
        UART_TxHead = tmphead;                /* Store new index */
    
        UCSRB |= (1<<UDRIE);                    /* Enable UDRE interrupt */
    }
    
  • #2 8361626
    tmf
    VIP Zasłużony dla elektroda
    ATMega jest taktowana kwarcem, czy z wewnętrznego generatora RC? Jeśli z wewnętrznego to zapomnij o transmisji po RS, znaczy czasami działa, ale stabilność tego generatora jest poza wymaganą dla specyfikacji RS232 asynchronicznego.
  • #3 8361651
    l3sz3k
    Poziom 18  
    Źle zmontowany układ na MAX232
    Źle podłączony interfejs: zła polaryzacja, pomylone piny itd.
    Źle skonfigurowany UART: baundrate, bit stopu, ilość bitów itd.

    No i w końcu źle napisany kod :)
  • #4 8361871
    _sid
    Poziom 11  
    tmf napisał:
    ATMega jest taktowana kwarcem, czy z wewnętrznego generatora RC? Jeśli z wewnętrznego to zapomnij o transmisji po RS, znaczy czasami działa, ale stabilność tego generatora jest poza wymaganą dla specyfikacji RS232 asynchronicznego.

    Tak, wewnętrzny - wiem, że będzie działać z pewnym odsetkiem błędów transmisji ale to jedynie do testów miało być ... mimo wszystko wydaje mi się że powinno działać (niestabilnie, ale jednak).

    l3sz3k napisał:
    Źle zmontowany układ na MAX232
    Źle podłączony interfejs: zła polaryzacja, pomylone piny itd.
    Źle skonfigurowany UART: baundrate, bit stopu, ilość bitów itd.
    No i w końcu źle napisany kod :)

    ad 1) jeśli echo za MAX-em działa to przypuszczam, że dobrze go połączyłem (ale jestem laikiem więc może o czymś nie wiem)
    ad 2) hmm możliwe, ale w takim wypadku dostawałbym chyba krzaki na terminalu bez mojej interwencji (tj. wciskania klawiszy) ? Sprawdzałem połączenia ale nie zaszkodzi sprawdzić raz jeszcze - dam znać później.
    ad 3) Kod nie jest skomplikowany ... ale mogłem źle porty poustawiać (choć jest to kod w większości z datasheet-a).
  • Pomocny post
    #5 8362764
    ginar
    Poziom 21  
    proponuję zrobić najprościej jak się da
    
    #define F_OSCILATOR        8000000
    #define MYBOD_RATE         9600
    #define UBRR_number		   (F_OSCILATOR/(16ul*MYBOD_RATE)-1)
    
    int main(void )
    {
    
    	UBRRL =0xFF & UBRR_number;
    	UBRRH = 0x7F & (UBRR_number>>8);
    
    	UCSRB = (1<<RXEN)|(1<<TXEN);
    	/* Set frame format: 8data, 2stop bit */
    	UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
    	while(1)
    	{
    		UDR='a';
    		_delay_ms(100);
    	}
    }
    

    celem określenia położenia błędu hardware/software
  • #6 8363365
    arturt134
    Poziom 27  
    Ja bym sprawdzał to w dwóch etapach:
    1. nadawanie - napisz program wysyłający w pętli jeden znak. Musisz doprowadzić do tego, aby terminal w PC wyświetlał go prawidłowo.
    2. odbiór - jak nadawanie będzie OK, to i odbiór pewnie będzie OK - sprawdź to odsyłając znak odebrany z terminala.

    Teraz możliwe powody niedziałania:
    - zła częstotliwość - sprawdź, czy twoja częstotliwość zegarowa jest na pewno taka jak powinna być. Ustaw jakiś timer na 1 sekundę i migaj diodą, w ten sposób sprawdzisz ustawienie zegara zwykłym zegarkiem mierząc czas np. 60 mignięć (jeżeli masz oscyloskop, to go po prostu zmierzysz). W ten sposób dowiesz się, czy oscylator RC daje właściwą częstotliwość i czy wszystkie bezpieczniki są prawidłowo ustawione (szczególnie CLK8DIV, czy jakoś tak się nazywający, dzielący częstotliwość oscylatora RC przez 8).
    - błąd ustawień UARTA - zaopatrz się w jakiś lepszy terminal (polecam Realterm, do pobrania za darmo), który ci pokaże rodzaj błędu (parity, framing itp.),
    - źle ustawiona prędkość - wpisz do UBRH i UBRL wartości obliczone na kalkulatorze, ewentualnie sprawdź w symulatorze, czy twój kod liczy je prawidłowo.

    Jeżeli to nie pomoże, to warto będzie popatrzeć dokładnie w kod.
  • #7 8365456
    _sid
    Poziom 11  
    Heh, dzięki wszystkim za pomoc, a szczególnie ginar-owi :)
    Tak się skupiłem na braku wiedzy elektronicznej, że nie zwróciłem uwagi na to co piszę w kodzie ...

    
    UCSRC = (1<<URSEL)|(1<<UCSZ0); 
    


    Jak widać coś nie do końca ustawiam to 8 data bits, 1 stop bit ...
    Sprawdziłem kod ginar-a i od razu wyszło.

    Właśnie zauważyłem że Leszek także wymienił źle skonfigurowany UART :)
    Przyznaje - nie sprawdziłem od razu.
REKLAMA