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

Atmega32 - Jak napisać program do komunikacji UART i sterowania pinem?

147 24 Kwi 2006 20:37 2445 17
REKLAMA
  • #1 2561678
    147
    Poziom 11  
    Posty: 9
    Witam
    Jestem początkujacym programistą, chciałbym napisac program do komunikacji poprzez UART. Program powinien działac tak, że jeśli odbierze jakiś znak np "a" to powinien ustawić 1 na dany pin portu np B. Znalazłem w pdfie z atmegi o uarcie ale nie pomogło mi to za wiele.

    Wielkie dzięki za wszelką pomoc
  • REKLAMA
  • #2 2561786
    pubus
    Poziom 30  
    Posty: 1289
    Pomógł: 138
    Ocena: 31
    Po pierwsze w czym piszesz... C, Bascom, Asm...?.?.?
    Nie masz w pdf-e przykładów...?.?.?
    Poszukaj na forum było już troche tematów o UART w różnych językach...
  • #3 2561799
    euromatic
    Poziom 21  
    Posty: 422
    Pomógł: 17
    Ocena: 14
    Witam,
    moze napisz w czym programujesz bo to istotne.
    pozdrawiam

    grzegorz

    ps:
    kolega mnie ubiegł....
  • #4 2564127
    147
    Poziom 11  
    Posty: 9
    Przepraszam niedopatrzenie z mojej strony :/ Programuje w C, chodzi mi o uruchomienie UART. Częstotliwość kwarcu 15MHz, prędkość transmisji 115200 b/s (obliczyłem że przy tej prędkości UBRR=7 a bład 1,7% więc jak wyczytałem poniżej 2%). Z góry dziękuje za pomoc
  • REKLAMA
  • #6 2564364
    147
    Poziom 11  
    Posty: 9
    Hej, to jes5t kod z postu do którego odnośnik powyżej
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    #include <inttypes.h>
    #define PARITY_NONE 0
    #define PARITY_EVEN (1<<UPM1)
    #define PARITY_ODD ((1<<UPM1)|(1<<UPM0))
    #define STOP_BITS_1 0
    #define STOP_BITS_2 (1<<USBS)
    #define DATA_BITS_5 0
    #define DATA_BITS_6 (1<<UCSZ0)
    #define DATA_BITS_7 (1<<UCSZ1)
    #define DATA_BITS_8 ((1<<UCSZ1)|(1<<UCSZ0))
    #define DATA_BITS_9 ((1<<UCSZ2)|(1<<UCSZ1)|(1<<UCSZ0))
    
    #define F_CPU 15000000 // 15MHz zegar procesora
    #define UART_BAUD 115200
    #define _UBBR_ ((F_CPU/(16*UART_BAUD))-1)
    unsigned char byte;
    
    
    int USART_Transmit( unsigned char data )
    {
    while ( !( UCSRA & (1<<UDRE)) );/* Wait for empty transmit buffer */
    UDR = data;/* Put data into buffer, sends the data */
    return 0;
    }
    
    
    //void USART_Init( unsigned int baud_reg )
    /*   UBRRH = (unsigned char)(baud_reg>>8);
       UBRRL = (unsigned char)baud_reg;*/
    // To jest to, co najbardziej kocham w AVR-gcc -
    // - brak elastyczności preprocesora w obliczeniach... ;)
    // W tym przypadku wywala : "warning: integer overflow in expression"
    // i oczywiście wstawia bzdury, więc wszystko muszę ręcznie wyliczać...
    // Dlaczego AVRasm2 nie ma z tym problemu i w nim moge pisać łatwo kod na różne
    // częstotliwości oscylatorów, bez chrzanienia się z wyliczeniami... ? ;)
    void USART_Init( void )
       {
       UBRRH = 0x00;
       UBRRL = 0x07;
       UCSRB = (1 << RXCIE) | (1 << RXEN) | (1 << TXEN);
       UCSRC = (1 << URSEL) | DATA_BITS_8 | PARITY_NONE | STOP_BITS_1;
       sei();
       }
    
    
    
    int main (void)
       {
    //   USART_Init(_UBBR_);
       USART_Init();
       DDRB |= (1 << PB1);
    
       while(1)
          {
          }
       return 0;
       }
    
    
    SIGNAL (SIG_UART_RECV)
       {
       PORTB ^= (1 << PB1);
       byte = UDR;
       USART_Transmit(byte);
       }

    Zmieniłem:
    #define F_CPU 15000000 // z 4MHz na 15MHz
    #define UART_BAUD 115200 // z 19200 na 115200
    UBRRL = 0x07; // z 0x0C na 0x07
    czy coś jeszcze trzeba zmienić dla Atmega32 ?? bo w AVRStudio mi to nie chce iść ??
  • #7 2564464
    pubus
    Poziom 30  
    Posty: 1289
    Pomógł: 138
    Ocena: 31
    Jak byś przeanalizował ten kod to zauważyłbyś, że choć został fragmęt kodu gdzie jest ta wartość wyliczana to dalej nie jest podstawiana wartość z makra _UBRR_ tylko wyliczona na piechotę...
    To ten fragmęt:
    UBRRH = 0x00;
    UBRRL = 0x07;
    Także musisz wyliczyć UBRR dla kwarcu 15MHz...
    W pdf do uC są tabele z wartościami UBRR ale akurat dla 15MHz nie ma...
    Wzór też jest w pdf ale go i tak napiszę...
    UBRR = (fosc / (16 * BAUD)) - 1
    fosc to oczywiście f kwarcu/gneratora etc na jakim uC biega...
    BAUD to prędkość transmisji...
    Jeszcze tylko wynik rozbić na dwa bajty i podstawić...
  • #8 2564475
    147
    Poziom 11  
    Posty: 9
    Jak napisałem wyżej to też już zmieniłem z 0x0C na 0x07, obliczyłem wszystko dla 15MHZ ale nie działa dalej :/
  • REKLAMA
  • #9 2564821
    pubus
    Poziom 30  
    Posty: 1289
    Pomógł: 138
    Ocena: 31
    Tzn. wogule nic nie przechodzi ani nie wraca...?.?.?
    Czy idzie siano...?
    Czy kompilator błąd wywala...?
    Jesteś pewny, że układ (pewnie z max232) jest poprawnie złożony...?
  • #10 2564851
    147
    Poziom 11  
    Posty: 9
    Nie wiedzieć czemu poszło dopiero za którymś razem :) A jak teraz dorobić do tego że jeśli oebrano znak np 'a' to żeby ustawił np 1 na pin 0 portu B ????
    Wielkie dzięki

    Dodano po 1 [godziny] 9 [minuty]:

    Chodzi mi o coś typu
    if (UDR='a')
    {
    PORTB0=0;
    }
    else
    {
    PORTB0=1;
    }
    tylko nie bardzo wiem jak to ugryźć
  • #11 2565644
    pubus
    Poziom 30  
    Posty: 1289
    Pomógł: 138
    Ocena: 31
    Możesz to zrobić tak...
    
    SIGNAL (SIG_UART_RECV) 
    { 
     byte = UDR;
    }
    


    a w pętli głównej...

    
    While(1)
    {
     ...
     if(byte=='a') PORTB |= _BV(0);
    }
    


    Pamiętaj, że zmienną byte deklarujesz jako globalną volatile...
    czyli... volatile unsigend char byte;
  • REKLAMA
  • #13 2566045
    147
    Poziom 11  
    Posty: 9
    Hej
    Czy to ma wyglądac tak:
    
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include <inttypes.h>
    #define PARITY_NONE 0
    #define PARITY_EVEN (1<<UPM1)
    #define PARITY_ODD ((1<<UPM1)|(1<<UPM0))
    #define STOP_BITS_1 0
    #define STOP_BITS_2 (1<<USBS)
    #define DATA_BITS_5 0
    #define DATA_BITS_6 (1<<UCSZ0)
    #define DATA_BITS_7 (1<<UCSZ1)
    #define DATA_BITS_8 ((1<<UCSZ1)|(1<<UCSZ0))
    #define DATA_BITS_9 ((1<<UCSZ2)|(1<<UCSZ1)|(1<<UCSZ0))
    
    #define F_CPU 15000000UL 			// 15MHz zegar procesora
    #define UART_BAUD 115200UL
    #define _UBBR_ ((F_CPU/(16*UART_BAUD))-1)
    volatile unsigend char byte;
    
    
    int USART_Transmit( unsigned char data )
    {
    while ( !( UCSRA & (1<<UDRE)) );	/* Wait for empty transmit buffer */
    UDR = data;							/* Put data into buffer, sends the data */
    return 0;
    }
    
    SIGNAL (SIG_UART_RECV)
    {
     byte = UDR;
    } 
    
    
    void USART_Init( void )
       {
       UBRRH = 0x00;
       UBRRL = 0x07;
       UCSRB = (1 << RXCIE) | (1 << RXEN) | (1 << TXEN);
       UCSRC = (1 << URSEL) | DATA_BITS_8 | PARITY_NONE | STOP_BITS_1;
       sei();
       }
    
    
    
    int main (void)
    {
       USART_Init();
    if(byte=='a')
       	{
       	PORTB ^= (1 << PB1);
    	}
    else
    	{
    	PORTB ^= (0 << PB1);
    	}
    
       while(1)
          {
          }
       return 0;
    }
    
    

    Dzieki za pomoc :)
  • #14 2566153
    pubus
    Poziom 30  
    Posty: 1289
    Pomógł: 138
    Ocena: 31
    Trochę namieszałeś...
    Zapis PORTB ^= (1 << PB0) powoduje zmianę stanu pinu PB0 w porcie B zawsze na przeciwny niż aktualnie jest ustawiony...
    Więc zapis PORTB ^= (0 << PB1) jest bez sensu...
    Light-I już też podał link do tematu gdzie to wszystko jest... zresztą tego samego co ja... ciekawe dlaczego... ;)
  • #15 2566542
    147
    Poziom 11  
    Posty: 9
    Wiec tak, takim programem:
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    #include <inttypes.h>
    #define PARITY_NONE 0
    #define PARITY_EVEN (1<<UPM1)
    #define PARITY_ODD ((1<<UPM1)|(1<<UPM0))
    #define STOP_BITS_1 0
    #define STOP_BITS_2 (1<<USBS)
    #define DATA_BITS_5 0
    #define DATA_BITS_6 (1<<UCSZ0)
    #define DATA_BITS_7 (1<<UCSZ1)
    #define DATA_BITS_8 ((1<<UCSZ1)|(1<<UCSZ0))
    #define DATA_BITS_9 ((1<<UCSZ2)|(1<<UCSZ1)|(1<<UCSZ0))
    
    #define F_CPU 15000000 // 15MHz zegar procesora
    #define UART_BAUD 115200
    #define _UBBR_ ((F_CPU/(16*UART_BAUD))-1)
    unsigned char byte;
    
    
    int USART_Transmit( unsigned char data )
    {
    while ( !( UCSRA & (1<<UDRE)) );/* Wait for empty transmit buffer */
    UDR = data;/* Put data into buffer, sends the data */
    return 0;
    }
    
    
    //void USART_Init( unsigned int baud_reg )
    /*   UBRRH = (unsigned char)(baud_reg>>8);
       UBRRL = (unsigned char)baud_reg;*/
    // To jest to, co najbardziej kocham w AVR-gcc -
    // - brak elastyczności preprocesora w obliczeniach... ;)
    // W tym przypadku wywala : "warning: integer overflow in expression"
    // i oczywiście wstawia bzdury, więc wszystko muszę ręcznie wyliczać...
    // Dlaczego AVRasm2 nie ma z tym problemu i w nim moge pisać łatwo kod na różne
    // częstotliwości oscylatorów, bez chrzanienia się z wyliczeniami... ? ;)
    void USART_Init( void )
       {
       UBRRH = 0x00;
       UBRRL = 0x07;
       UCSRB = (1 << RXCIE) | (1 << RXEN) | (1 << TXEN);
       UCSRC = (1 << URSEL) | DATA_BITS_8 | PARITY_NONE | STOP_BITS_1;
       sei();
       }
    
    
    
    int main (void)
       {
    //   USART_Init(_UBBR_);
       USART_Init();
       DDRB |= (1 << PB1);
       if (byte=='a')
       {
       PORTB ^= (1 << PB1);
       }
    
       while(1)
          {
          }
       return 0;
       }
    
    
    SIGNAL (SIG_UART_RECV)
       {
       byte = UDR;
       
       USART_Transmit(byte);
       }
    
    wysyłając do uK znak 'a' mikrokontroler nie zmienia stanu na bicie 0, odpowiada mi znakiem 'c' nie wiem dlaczego, wysyłając kilka razy znak 'a' uK odpowiada sekwencją znaków coś w stylu 'ccccccc#ccccc##' itd Co z tym zrobić ???
  • #16 2566820
    pubus
    Poziom 30  
    Posty: 1289
    Pomógł: 138
    Ocena: 31
    Wygląda to na niezgodnośc parametrów transmisji...
    Muszą być takie same po obu stronach... uC i Komputer...
    Dlatego też stan na pinie się nie zmienia...
    Bo uC odbiera nie to co pownien...
  • #17 2566855
    147
    Poziom 11  
    Posty: 9
    Co do parametrów to w programie w którym nadaje znak ustawiam: 8 bitów danych, 1 bit stopu, bez bitów parzystości. A czy program jest już dobry??

    Dodano po 38 [minuty]:

    Czy trzeba definiować
    #define PARITY_NONE 0
    #define PARITY_EVEN (1<<UPM1)
    #define PARITY_ODD ((1<<UPM1)|(1<<UPM0))
    #define STOP_BITS_1 0
    #define STOP_BITS_2 (1<<USBS)
    #define DATA_BITS_5 0
    #define DATA_BITS_6 (1<<UCSZ0)
    #define DATA_BITS_7 (1<<UCSZ1)
    #define DATA_BITS_8 ((1<<UCSZ1)|(1<<UCSZ0))
    #define DATA_BITS_9 ((1<<UCSZ2)|(1<<UCSZ1)|(1<<UCSZ0))
    to?? Mi zalezy żeby było 8 bitów danych. Poniewaz wszystko będzie (może kiedyś) działało tak że oprócz tego że jeśli odbierze jakiś znak i ustawi dany stan na danym bicie portu b to na port A i port C beda podawane dane (2 x 8 bitów) i je trzeba bedzie też wysłać do kompa. Dla mnie to jest masakra, elektronika tak programowanie nie, dlatego zadaje różne dziwne pytania. Wielkie dzięki za wszelką pomoc. Ewentualnie moge sie odwdzięczyć jakoś :) Kwestia dogadania się :)
  • #18 2567268
    pubus
    Poziom 30  
    Posty: 1289
    Pomógł: 138
    Ocena: 31
    Pierwsza sprawa... pytałem czy jest to samo ustawione w programie który na komputerze ma odbierać co w uC...
    Druga... nie nie musisz tego deklarować jeśli jesteś pewny, że nie będziesz w przyszłości zmieniał parametrów i zbawi cie te pare bajtów więcej które zyskasz...

Podsumowanie tematu

✨ Dyskusja dotyczy napisania programu w języku C dla mikrokontrolera Atmega32 umożliwiającego komunikację UART przy częstotliwości kwarcu 15 MHz i prędkości transmisji 115200 b/s. Omówiono obliczanie wartości rejestru UBRR według wzoru UBRR = (fosc / (16 * BAUD)) - 1 oraz konieczność poprawnego ustawienia parametrów transmisji (8 bitów danych, 1 bit stopu, brak parzystości) zgodnie po obu stronach komunikacji. Zaproponowano użycie przerwania od odbioru znaku (RXC) i globalnej zmiennej volatile do przechowywania odebranego bajtu. Przykładowo, po odebraniu znaku 'a' można ustawić stan logiczny na pinie PB0 portu B, wykorzystując instrukcję warunkową w pętli głównej programu. Podkreślono, że manipulacja portem powinna odbywać się przez odpowiednie bity rejestru PORTB, np. PORTB |= _BV(0) do ustawienia pinu PB0. Wskazano również na poprawne deklaracje zmiennych i obsługę przerwań w AVR. Dyskusja zawierała fragmenty kodu źródłowego oraz uwagi dotyczące poprawności sprzętowej, m.in. użycia układu MAX232 do konwersji poziomów sygnału UART.
Wygenerowane przez model językowy.
REKLAMA