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

[Atmega8] Prosty program obsługujący UART

09 Kwi 2010 23:48 5114 24
  • Poziom 18  
    Napisałem najprostsze możliwe funkcje do komunikacji po RS232.
    Cytat:
    void usart_init(void)
    {


    UCSRC = _BV(URSEL) | _BV(USBS) | _BV(UCSZ1) | _BV(UCSZ0);

    UBRRL = 51;

    UCSRB = _BV(RXEN) | _BV(TXEN);

    }

    void wyslij(char dana)
    {
    while(bit_is_clear(UCSRA, UDRE));
    UDR = dana;
    }


    uint8_t odbierz(void)
    {
    while(bit_is_clear(UCSRA, RXC));
    return UDR;
    }

    Niestety nie działa. Oscylator jest wewnętrzny 8Mhz. Atmega nie wysyła żadnych danych, odbiera tylko ff lub fd.

    Co jest nie tak?
  • Poziom 18  
    Żadnych pomysłów? Przejrzałem jakieś przykładowe programy i niestety nie widzę różnic...

    Ktoś napisał że trzeba ustawić porty jako wyjściowe i później skasował post... To chyba nie jest powodem, bo przecież zmieniamy przeznaczenie portu...
  • Poziom 43  
    To byłem ja. Zmiana przeznaczenia pinu (nie portu) to nie jest żaden argument. Są peryferia które zmieniają przeznaczenie pinu ale nie ustawiają pinu jako wyjście. Ale UARTa to nie dotyczy więc jak się zorientowałem to skasowałem post.
    Najlepiej to pokaż cały program i schemat.
  • Pomocny post
    Poziom 19  
    jaka prędkość transmisji z z którego socylatora kożysztasz (zewnętrznego czy wewnętrznego)
  • Pomocny post
    Poziom 43  
    Przecież napisał.
    jacobs242 napisał:
    Oscylator jest wewnętrzny 8Mhz.


    A po drugie to bez znaczenia bo komp mimo niewłaściwej prędkości by jednak coś odbierał. Totalne krzaki, ale jednak.
  • Poziom 19  
    no i tutaj się mylisz, ale co mogę doradzić, to zapisz w rejestrze konfiguracyjnym oscylatora wartośc kalibracyjną, którą nalezy najpierw odczytać z danego procka.
    P.S. Nie doczytałem, że kożysta z wewnętrznego oscylatora, za co przepraszam.
  • Poziom 18  
    Smoczy, po twoim poście stwierdziłem, że sprawdzę fusy, i o dziwo był tam 1mhz, zamiast 8mhz, które wydawało mi się, że są. Zmieniłem więc na 8, prędkość 9600.

    Po zmianie zaczęło działać odbieranie znaków. Niestety nadal nie wysyła...

    Schematu nie ma, układ połączony jest następująco: USB -> konwerter USB/RS232 na ft232 -> max232 -> atmega. Jestem prawie na 100% pewny że połączenia są dobrze.

    Program wygląda tak (przykładowy bo testowałem już wiele):
    Code:
    int main(void)
    

    {
       char *bufor;

       sei();

       

       LCD_Initalize();

       USART_Init();

       

       while(1)
       {
          
          LCD_GoTo(0,0);
          LCD_WriteText("testtest");
          wyslijstring("String");
          LCD_GoTo(0,1);
          LCD_WriteText(itoa(odbierz(), bufor, 16));

       }
    }
  • Poziom 19  
    A max232 to po co jak z ftdi masz wyjście na poziomie ttl.
    Zapisz jeszcze bajt kalibracyjny oscylatora, powinno pomóc.
  • Poziom 18  
    To jest cały konwerter, więc napięcie są jak w standardzie rs232.

    Bajt kalibracyjny, to znaczy F_CPU? Jeśli tak to jest zapisany...
  • Poziom 19  
    W procku są zapisane wartości kalibracyjne wewnętrznego oscylatora, które są zależne od częstotliwości jaką wybierzemy. W momencie startu do rejestru osccal jest zapisywana wartośc dla częstotliwości pracy równej 1MHz. W przypadku wyboru innej częstotliwości trzeba ten rejestr samemu zapisać. Podczas programowania odczytuje sie te wartości z procka i zapisuje np. w eepromie. Następnie wprowadzamy je na początku programu do ww. rejestru i jest wszystko oki. Poczytaj trochę pdf, tam jest to dokładniej opisane.
  • Poziom 18  
    Faktycznie jest coś takiego i nawet widać, że wpływa na uC. Po ustawieniu 0xFF nic nie działało, więc ustawiłem 0x7F. Niestety wysyłanie nadal nie działa... Sprawdziłem jeszcze miernikiem czy wszystko "łączy" i jest ok. Dziwne.

    PS. Jaki jest najprostszy sposób zamiany liczby ascii na znak w C?
  • Poziom 43  
    Smoczy napisał:
    no i tutaj się mylisz

    W czym sie mylę, bo nie rozumiem?

    A co do wartości OSCCAL to nie trzeba jej nigdzie zapisywać.
    Tak samo kalibruje ona 1MHz i 8MHz. Przecież wewnętrzny zegar zawsze chodzi na 8MHz.
    Jedynie preskalerem wybiera się 4, 2 czy 1 MHz.

    jacobs242: a na pinie TXD po inicjalizacji UARTa, ale w stanie spoczynku (gdy nic nie nadajesz), masz mocny stan wysoki? Podłącz jakiegoś LEDa przez rezystor o małej wartości (małej czyli ze 220R) i zobacz. LED powinien się jasno zaświecić.
    W ogóle to pin TXD jako normalny pin IO mógł byś przetestować.
  • Poziom 18  
    Sprawdziłem multimetrem, stan jest wysoki.
  • Poziom 19  
    do atom1477: Odnośnie oscylatora: str 29 pdf do procka jest tam opisane co i jak. Mylisz się co do tego, że częstotliwość transmisji nie ma znaczena, a dowodem na to jest to, że nie odbierał uart komputera nic, ponieważ procek miał ustawiony oscylator na 1MHz, a wg. Twojej opini powinny pojawiać się krzaki.
    Nie polemizuję więcej.

    Pokaż procedurkę void wyslijstring().
  • Poziom 18  
    Myślałem, że wstawiłem w pierwszym poście. Poniżej ta procedura:

    Code:
    void wyslijstring(char *dana)
    
    {
       int dl, k=0;

       dl = strlen(dana);

       for(k = 0; k<dl; k++)
          wyslijznak(dana[k]);
    }
  • Poziom 19  
    wydaje mi się, że procedurka powinna wyglądać tak:
    Code:

    void wyslijstring(char *dana)
    {
       char dl, k;

       dl = sizeof(*dana);

       for(k = 0; k<dl; k++)
          wyslijznak(&dana[k]); //lub wyślijznak(dana++);
    }


    Sprawdź czy to zadziała.
    Pozdrawiam, Łukasz
  • Poziom 43  
    Smoczy napisał:
    do atom1477: Mylisz się co do tego, że częstotliwość transmisji nie ma znaczena, a dowodem na to jest to, że nie odbierał uart komputera nic, ponieważ procek miał ustawiony oscylator na 1MHz, a wg. Twojej opini powinny pojawiać się krzaki.

    Po pierwsze chodziło mi o błąd np. 8,5 zamiast 8MHz.
    A po drugie to to nie jest żaden dowód, bo nie wiadomo czy to akurat to jest powodem że komputer nic nie odbiera. U mnie na przykład odbiera mimo wielokrotnego błędu prędkości transmisji.

    PS. Na stronie 29 mam External RC Oscillator. O to Ci chodzi?
  • Poziom 18  
    Udało się. Zmontowałem dziś układ jeszcze raz z nowym maxem i atmegą. Zaczęło działać, ale sypało krzakami. Wykasowałem z programu linijkę z osccal, no i wszystko jest już tak jak powinno.

    Dzięki za zainteresowanie.
  • Poziom 43  
    Czyli MAX232 albo ATMega8 była walnięta, tak?
  • Poziom 18  
    Na to wygląda. Ewentualnie coś nie stykało.
  • Poziom 2  
    Witam,
    Sporo tego już na forum, więc nie chciałem zakładać nowego tematu, ale też mam problem z UARTEM. Jak zaraz zobaczycie jestem świeży, więc nie krzyczcie na mnie zbyt głośno. Chciałbym zorganizować komunikację między dwiema atmegami8L, ale już przy tak prostym programie mi się to nie udało. Dioda nadajnika świeci w odpowiednim momencie, ale odbiornik nie reaguje wcale. Bardzo proszę o pomoc. Schematy i kody programów przedstawiam poniżej.
    //GND na procesorach, są oczywiście podłączone, zapomniałem tego na schemacie.
    Program nadajnika:
    Code:
    #define F_CPU 1000000L 
    
    #include <avr/io.h>
    #include <util/delay.h>

    int main(void)
    {
    SPL=(unsigned char)(RAMEND);
    SPH=(unsigned char)(RAMEND>>8);
    unsigned int baud=0x19;
    UBRRH = (unsigned char)(baud>>8);
    UBRRL = (unsigned char)baud;
    UCSRB = (1<<TXEN);
    UCSRC = (1<<URSEL)|(3<<UCSZ0);
    DDRB = 0xFF;
    DDRC = 0x00;
    PORTC = (1<<5);

    while(1)
    {
    PINC=(1<<5);
    if(!(PINC & 0x20))
    {
    int data=0x02;
    while ( !( UCSRA & (1<<UDRE)) ) {UDR = data;}
    PORTB=0x01;
    _delay_ms(2000);
    PORTB=0x00;
    }
    }
    }

    -------------------------------------------------------------------
    Program odbiornika:
    Code:

    #define F_CPU 1000000L
    #include <avr/io.h>
    #include <util/delay.h>

    int main(void)
    {
    SPL=(unsigned char)(RAMEND);
    SPH=(unsigned char)(RAMEND>>8);
    unsigned int baud=0x19;
    UBRRH = (unsigned char)(baud>>8);
    UBRRL = (unsigned char)baud;
    UCSRB = (1<<RXEN);
    UCSRC = (1<<URSEL)|(3<<UCSZ0);
    DDRB = 0xFF;
    unsigned char data;
    while(1)
    {
    while ( !(UCSRA & (1<<RXC)) )
    {
    data=UDR;
    }

    if(!(data==0x00))
    {
    PORTB=0xff;
    _delay_ms(2000);
    PORTB=0x00;

    }

    }
    }


    [Atmega8] Prosty program obsługujący UART [Atmega8] Prosty program obsługujący UART
  • Poziom 16  
    Po pierwsze widzę że masz błąd w funkcji odbioru, powinna ona wyglądać tak

    Code:
    while ( !(UCSRA & (1<<RXC)))
    
          ;
       return UDR;


    Po drugie, proponuję skorzystać z gotowych funkcji z noty katalogowej, z nimi nie ma problemów ;)


    Podobny błąd masz przy funkcji transmit
  • Poziom 2  
    Dziękuję za reakcję. Nie wydaje mi się, żeby w tym tkwił problem, bo po prostu nie mam funkcji odbioru i funkcji transmit. Te zadania są realizowane w main().
    Ale próbuję wszystkiego, więc poszedłem za Twoją sugestią i zrobiłem to na funkcjach z dokumentacji atmegi. Ciągle bez zmian. Oto one:
    Nadajnik:
    Code:

    #define F_CPU 1000000L
    #include <avr/io.h>
    #include <util/delay.h>               
    #define FOSC 1000000L// Clock Speed
    #define BAUD 2400
    #define MYUBRR FOSC/16/BAUD-1

    void USART_Init( unsigned int ubrr);
    void USART_Transmit( unsigned char data );

    int main(void)
    {   
       DDRB=0XFF;
       DDRC-0X00;
       PORTC=0XFF;
       PINC=0X20;
       USART_Init(MYUBRR);
       unsigned char message='w';
       while(1){
          if(!(PINC & 0x20)){
             PORTB=0X01;
             USART_Transmit( message );
             _delay_ms(2000);
             PORTB=0X00;
             
          }
       }

    }

    /************************************************/

    void USART_Init( unsigned int ubrr){
       UBRRH = (unsigned char)(ubrr>>8);
       UBRRL = (unsigned char)ubrr;
       UCSRB = (1<<TXEN);
       UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
    }

    /************************************************/

    void USART_Transmit( unsigned char data ){
       while ( !( UCSRA & (1<<UDRE)) )
       UDR = data;
    }

    /*************************************************/

    Odbiornik:
    Code:

    #define F_CPU 1000000L
    #include <avr/io.h>
    #include <util/delay.h>               
    #define FOSC 1000000L// Clock Speed
    #define BAUD 2400
    #define MYUBRR FOSC/16/BAUD-1

    void USART_Init( unsigned int ubrr);

    unsigned char USART_Receive( void );


    int main(void)
    {   
       DDRB=0XFF;
       USART_Init(MYUBRR);
       unsigned char message;
       while(1){
          message=USART_Receive();
          if (message != 0){
                PORTB=0X01;
                _delay_ms(2000);
                PORTB=0X00;
          }
       }

    }

    /************************************************/
    void USART_Init( unsigned int ubrr){
       UBRRH = (unsigned char)(ubrr>>8);
       UBRRL = (unsigned char)ubrr;
       UCSRB = (1<<RXEN);
       UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
    }

    /************************************************/
    unsigned char USART_Receive( void )
    {

    while ( !(UCSRA & (1<<RXC)) )
    ;
    return UDR;
    }


    /*************************************************/


    Macie jakieś pomysły?
  • Poziom 16  
    W funkcji transmit dalej brakuje Ci średnika, BAUD warto dać więcej, zwykle bywa to 9600

    nie potrzebnie dodawałeś, tak wystarczy

    Code:
     UBRRL = ubrr;
    
    UBRRH = (ubrr>>8); 


    jak korzystasz z tych funkcji z data sheet to popraw przy inicjalizacji na:
    Code:
    UCSRB |= (1 << RXEN) | (1 << TXEN); 


    jak doczytasz dokładnie to wymagane jest potwierdzenie odbioru
  • Poziom 2  
    Już działa. Drugi przewód i aktywacja TXEN dla odbiornika i RXEN dla nadajnika nie są potrzebne. Cosiek, dziękuję bardzo za pomoc i zalezienie błędów w kodzie. Jeszcze raz wielkie dzięki! Pozdrawiam.