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

[AVR][C] Odbieranie znaku przez uC wysyłanego z komputera przez USART

nelik1987 25 Mar 2011 13:28 5468 7
REKLAMA
  • #1 9320453
    nelik1987
    Poziom 31  
    Witam dzisiaj chciałem przetestować odbieranie znaku wysyłanego przez komputer do USART mikrokontrolera. Sprawa okazała się bardzo prosta napisałem prosty programik który po wysłaniu znaku 'a' ma włączać diodę a na wysłanie znaku 'b' ma ją gasić. Ku mojemu zdziwieniu należy wysłać aa lub bb by uzyskać jakiś efekt. Nie wiem dlaczego się tak dzieje. Wysłanie samego znaku a nie powoduje niczego dopiero gdy powtórnie wyślę a to zmienia się stan. Zamieszczam kod programu jaki i bibliotekę.

    #include <avr/io.h>
    #include "biblioteki/usart.c"  	// Biblioteka odpowiadająca za transmisję USART / USART library
    #include <avr/interrupt.h> 		// Biblioteka przerwań
    #include <rc5.h>
    
    volatile char zmienna; 
    volatile char zmienna2;
    
    int licznik = 0;  				// POMOCNICZY LICZNIK do UART
    int licznik1 = 0; 				// POMOCNICZY LICZNIK do UART
    int licz = 0;
    
    #define FOSC 16000000			// Czestotliwosc zegara w Hz / System Clock in Hz
    #define BAUD 19200    			// Predkosc transmisji USART / USART speed
    #define MYUBRR FOSC/16/BAUD	
    
    int main (void)
    {
    USART_Init(MYUBRR);					// Inicjalizacja transmisjii USART
    DDRA = 255;						   	// TEST dla TOGGLE LED jako wyjście
    PORTA=0xFF;			
    
    while(1)  							// Program glowny, petla nieskonczona
    {
    if(licz>=1000)
    {
    zmienna = USART_Receive();
    	if(licznik>=1000)
    	{
    		USART_Transmit(13); //ENTER (CR)
    		USART_Putint(zmienna);
    		licznik=0;
    	}
    	licznik++;
    	licz=0;
    }
    licz++;
    if(zmienna == 98) // jeżeli b
    PORTA=0x00;
    if(zmienna == 97) // jeżeli a
    PORTA=0xFF;
    }} 	//zamyka while i main
    


    Biblioteka USART

    //--------------------------------------------------------------
    // inicjacja portu szeregowego
    //--------------------------------------------------------------
    void USART_Init(unsigned int ubrr)
    {
    	unsigned char temp = 0;
    	UBRRH =  ubrr>>8; 				// ustawianie prędkości
    	UBRRL =  ubrr;
    
    	UCSRB |= _BV(TXEN);				// włączenie  nadajnika
    	UCSRB |= _BV(RXEN);				// włączenie  odbiornika
    
    	temp |= _BV(URSEL);				// ustawienie parametrów przesyłu, jeden bit stopu 
    	temp |= _BV(UCSZ1);				// 8bitów danych
    	temp |= _BV(UCSZ0);				// brak parzystości
    	
    	UCSRC = temp;					// zapisanie parametrów do rejestru
    }		 
    //--------------------------------------------------------------
    // odbiór danych
    //--------------------------------------------------------------
    char USART_Receive(void)
    {
    unsigned char data;
    while (bit_is_clear(UCSRA,UDRE));	//czekanie na zwolnienie buforu danych
    data = UDR;
    return data;
    }
    
    //--------------------------------------------------------------
    // wysyłanie danych
    //--------------------------------------------------------------
    void USART_Transmit(unsigned char data)
    {
    	while (bit_is_clear(UCSRA,UDRE));	//czekanie na zwolnienie buforu danych
    	UDR=data;							//zapisanie danych do rejestru UDR, wysyłanie następuje automatycznie
    } 
    
    //--------------------------------------------------------------
    // Wysłanie liczby do 9999
    //--------------------------------------------------------------
    void USART_Putint(uint16_t liczba)
    {	
    	uint16_t temp,temp1;			// zmienne pomocnicze
    	temp1 = liczba%10000/1000;  	// wyodrębnienie cyfry tysięcy
    	if(temp1) 						// jeżeli zerowa to pomiń wysłanie
    		USART_Transmit(temp1+48);	// wyślij w kodzie ASCII
    	temp = liczba%1000/100;  		// wyodrębnienie cyfry setek
    	if(temp|temp1)					// jeżeli zerowa i cyfra tys. zerowa to pomiń wysłanie
    		USART_Transmit(temp+48);	// wyślij w kodzie ASCII
    	temp = liczba%100/10;  			// wyodrębnienie cyfry dziesiątek
    	USART_Transmit(temp+48);		// wyślij w kodzie ASCII
    	temp = liczba%10;  				// wyodrębnienie cyfry jedności
    	USART_Transmit(temp+48);		// wyślij w kodzie ASCII
    }
    
  • REKLAMA
  • #2 9320675
    duke_luke
    Poziom 15  
    Wydaje mi się, że problem leży w tym, że jeśli przez terminal wysyłasz a to traktowane jest to jako liczba zapisana w hex, czyli w systemie dziesiętnym 10. Zależy jeszcze jakiego terminala używasz. Ja zacząłbym od tego, żeby sprawdzić w jakim systemie wysyłane są liczby z PC do Twojego uC. Ewentualnie zamiast 97 i 98 w if'ach daj 10 i 11, wtedy od razu będziesz miał odpowiedź, czy nadajesz z PC do uC w hex.
  • REKLAMA
  • #3 9321106
    Dr. Kuj
    Poziom 13  
    A ja bym na Twoim miejscu wszystko to skasował i wyciągnął obsługe UARTU z datasheeta kontrolera.
    Twoja biblioteka jest napisana w starym stylu. Kod odbierania jest za długi. Całość można zamknąć w kilku linijkach.
  • #4 9321424
    namlooc
    Poziom 15  
    Nie wiem jaka atmege masz ale dokumentacja atmegi32:
    doc2503.pdf
    Zobacz na strona 146 oraz 147.

    Tam widnieje taki kod:
    void usart_init()                     //(unsigned int baud)
    {
    UBRR0H = (unsigned char) (baud>>8);  // ustawiamy predkosc transmisji
    UBRR0L = (unsigned char) baud;       //
    
    UCSR0B = (1<<RXEN1) | (1<<TXEN0);    // WLANCZA ODBIORNIK I NADAJNIK
    
    UCSR0C = (1<<USBS1) | (3<<UCSZ00);
    }
    
    void usart_transmit(char data)
    {
    
    while ( !( UCSRA & (1<<UDRE)) )
    UDR= data;
    }


    ktory bez problemow mozna uzyc w programie:

    np.

    
    #define baud ((F_CPU/(predkosc*16UL))-1)
    #define predkosc 2400      
    #define F_CPU 16000000UL    
    .
    .
    .
    int main (void)
    {
    usart_init();
    while(1)
    {
    usart_transmit("a");
    }
    
    }


    Polecam ten terminal:
    http://realterm.sourceforge.net/
    Nie ma problemu z echem znaku, tak jak ty musisz to robic dwukrotnie.
  • Pomocny post
    #5 9321784
    Andrzej__S
    Poziom 28  
    Jak odbierasz znak powinieneś czekać na ustawienie flagi RXC, a nie UDRE:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • REKLAMA
  • #6 9322571
    namlooc
    Poziom 15  
    Andrzej__S napisał:
    Jak odbierasz znak powinieneś czekać na ustawienie flagi RXC, a nie UDRE:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Masz racje. Dokumentacja mowi tez jasno o tym:
    unsigned char USART_Receive( void )
    {
    /* Wait for data to be received */
    while ( !(UCSRA & (1<<RXC)) )
    ;
    /* Get and return received data from buffer */
    return UDR;
    }
  • REKLAMA
  • #8 9337384
    Andrzej__S
    Poziom 28  
    Pozwolę sobie zauważyć, że:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    nie jest równoważne:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Powinno być raczej:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Twoja funkcja USART_Receive() sprawdzi, czy flaga RXC jest ustawiona i - jeśli nie - zakończy działanie, zwracając właściwie trudno mi określić co. Trudno określić, bo funkcja zwraca niezainicjowaną zmienną, której - w przypadku, gdy RXC=0 - nie przypisujesz żadnej wartości. Nie wiem też co z tym kodem zrobi optymalizacja. W zasadzie definiowanie zmiennej lokalnej data wewnątrz funkcji nie jest konieczne. Wystarczy return UDR;
    Istotą pętli while() wewnątrz funkcji USART_Receive() jest oczekiwanie na ustawienie flagi RXC i dopiero później zwrócenie zawartości rejestru UDR, więc powinna ona wyglądać tak, jak zaproponowałem.
REKLAMA