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

[ATMega128][C] Problem z komunikacją przez USART1

lebe 21 Cze 2009 21:10 2204 18
  • #1 6685740
    lebe
    Poziom 10  
    Ponieważ jest to mój pierwszy post chciałbym wszystkich serdecznie powitać :).

    Mój problem polega na tym, że nie mogę ustawić połączenia uC <-> PC z Atmegą 128. Przy AT16 wszystko jest w porządku, a ze 128 wyświetla mi nieprawidłowe znaki w Terminalu. Przy transmisji dioda się świeci i i wszystko poza tym działa jak powinno.


    
    #include <avr/io.h>                // dostęp do rejestrów
    
    // Zmieniając poniższe definicje można dostosować program do potrzeb
    
    #define F_CPU                14745600ul         // częstotliwość zegara w Hz
    #define UART_BAUD        19200ul                // prędkość transmisji bit/s
    
    #define LED_PORT        PORTB                // port diody LED
    #define LED_BIT                7                // bit diody LED
    
    #define DDR(x) _SFR_IO8(_SFR_IO_ADDR(x)-1) // adr. rej. kier. PORTx
    #define PIN(x) _SFR_IO8(_SFR_IO_ADDR(x)-2) // adr. rej. wej. PORTx
    
    #define LED_PORT_O        LED_PORT             // rejestr wyjściowy
    #define LED_PORT_D        DDR(LED_PORT)   // rejestr kierunkowy
    #define LED_PORT_I        PIN(LED_PORT)   // rejestr wejściowy
    
    #define UART_CONST        (F_CPU/(16ul*UART_BAUD)-1)
    
    // _UCR_
    
    #ifdef        UCR
    #define _UCR_        UCR
    #endif
    
    #ifdef        UCSRB
    #define _UCR_        UCSRB
    #endif
    
    #ifdef        UCSR1B
    #define _UCR_        UCSR1B
    #endif
    
    // _USR_
    
    #ifdef        USR
    #define _USR_        USR
    #endif
    
    #ifdef        UCSRA
    #define _USR_        UCSRA
    #endif
    
    #ifdef        UCSR1A
    #define _USR_        UCSR1A
    #endif
    
    // Definicje funkcji
    
    // inicjalizacja portu szeregowego
    void UART_init(void) 
    {
      UBRR1L = (unsigned char)UART_CONST;         // ustaw prędkość transmisji 
      _UCR_ = _BV(RXEN1)|_BV(TXEN1);                // załącz tx, rx
    }
    
    // wysyła znak podany jako parametr na port szeregowy
    void UART_putchar (char c)
    {
      UDR1 = c;                                // wpisz c do rejestru UDR
      loop_until_bit_is_set(_USR_,TXC1);        // czekaj na zakończenie transmisji
      _USR_ |= _BV(TXC1);//sbi(_USR_,TXC);                                // ustaw bit TXC w rej. USR
    }
    
    // odbiera znak z portu szeregowego i zwraca go jako wartość funkcji
    char UART_getchar (void)
    {
      loop_until_bit_is_set(_USR_,RXC1);        // czekaj na zakończenie odbioru
      _USR_ &=~_BV(RXC1);//cbi(_USR_,RXC);                                // skasuj bit RXC w rej. USR
      return UDR1;                                // zwróć zawartość rejestru UDR
    }
    
    int main(void)                        // program główny
    {
      UART_init();                        // inicjalizacja portu szeregowego
    
      LED_PORT_D |= _BV(LED_BIT);//sbi(LED_PORT_D,LED_BIT);        // użyj linii jako wyjścia
    
      while(1)                        // pętla nieskończona
      {
        LED_PORT_O &= ~_BV(LED_BIT);//cbi(LED_PORT_O,LED_BIT);        // zapal diodę LED
        UART_putchar('m');                // wyślij '1' na port szeregowy
        UART_getchar();                // czekaj na znak z portu szeregowego
        LED_PORT_O |= _BV(LED_BIT);//sbi(LED_PORT_O,LED_BIT);        // zgaś diodę LED
        UART_putchar('n');                // wyślij '0' na port szeregowy
        UART_getchar();                // czekaj na znak z portu szeregowego
      }
    }
    


    [ATMega128][C] Problem z komunikacją przez USART1

    [ATMega128][C] Problem z komunikacją przez USART1

    Dodam tylko, że przejrzałem posty dotyczące podobnych tematów lecz niestety nie znalazłem rozwiązania.
  • #2 6686245
    donelbaron
    Poziom 15  
    zakładam ze masz kwarc 16 Mhz, zmien częstotliowść własnie na taką i zobacz, mnie to pomogło.

    Dodano po 4 [minuty]:

    a druga sprawa to procedura inicjalizująca
    
    void USART_Init ( unsigned int ubrr) // inicjalizacja UARTU
    {
       UBRRH= (unsigned char)(ubrr>>8);
       UBRRL= (unsigned char)(ubrr);      //ustawienie prędkości transmisji
    
       UCSRB=  (1<< RXEN)|(1<<TXEN) ; 
    
       UCSRC= (1<<URSEL)|(3<<UCSZ0); //Ustawienie ilości danych i parzystości
    
    }
    
  • #3 6686378
    lebe
    Poziom 10  
    Niestety nie chodzi tu o kwarc, sprawdzałem oscyloskopem i wyszło mi, że jest dobrze ustawiony. Co do inicjalizacji to zmieniłem ją zgodnie z datasheet'em i sprawdziłem z 1 i 2 bitami stopu, ale nadal to nie pomogło.

    
    void USART_Init (unsigned int ubrr)
    {
    	UBRR1H = (unsigned char)(ubrr>>8);
    	UBRR1L = (unsigned char)ubrr;
    
    	UCSR1B = (1<<RXEN1)|(1<<TXEN1);		//receive/transmit enable
    	UCSR1C = (1<<USBS1)|(3<<UCSZ10);		//2 stop bits / 8 bit transmission
    }
    


    Zastanawiam się czy nie chodzi tu o jakieś ustawienia w AVRStudio, ponieważ wcześniej miałem problemu z uruchomieniem LCD i pomogła zmiana z optymalizacji Os na O0.

    [ATMega128][C] Problem z komunikacją przez USART1
  • #4 6686387
    donelbaron
    Poziom 15  
    ale chociaż sprawdz to, ja tez ustwiałem dla kwarcu 16 mega, te samą wartość co ty masz, i mi krzaki wychodzily.
  • #5 6686395
    lebe
    Poziom 10  
    Oczywiście całe sprawdzanie zacząłem od tego. Sprawdziłem chyba wszystkie dostępne częstotliwości od 4 MHz :)
  • #6 6686409
    donelbaron
    Poziom 15  
    proponuje Ci jednak spradzic ten kod, zmienaijac tylko albo szybko procka w makefile, albo tu w kodzie, po wysalniu jakiegos znaku powineienes dostac odpowiedz w postaci jedynki. Jak to nie działa, to masz pewność że to nie wina kodu.
    
    #include <avr/io.h>                // dostęp do rejestrów
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    
    
    #define F_CPU      16000000    //częstotliwość zegara w Hz
    #define UART_BAUD   19200UL       //prędkość transmisji
    #define UART_CONST   (F_CPU/(16ul*UART_BAUD)-1)
    
    void USART_Init ( unsigned int ubrr) // inicjalizacja UARTU
    {
       UBRRH= (unsigned char)(ubrr>>8);
       UBRRL= (unsigned char)(ubrr);      //ustawienie prędkości transmisji
    
       UCSRB=  (1 << RXCIE) |(1<< RXEN)|(1<<TXEN) ; //uaktywnienie przerwań od odbioru i nadawania, uaktywnienie nadajnika i odbiornika UART. Tu trzeba usunąć (1<<TXCIE) lub dopisać do tego przerwania obsługę
    
       UCSRC= (1<<URSEL)|(3<<UCSZ0); //Ustawienie ilości danych i parzystości
    
       sei(); //zezwolenie na przerwania
    }
    
    void USART_Transmit ( unsigned char data) //podprogram do transmisji danych
    {
       while (!(UCSRA&(1<<UDRE)));
    
       UDR = data;
    }
    
    int main(void)                        // program główny
    {
       USART_Init( UART_CONST);
       DDRB=0xFF;
    
    
        while(1)
        {
    
        	//USART_Transmit('A');
        	_delay_ms(1000);
        }
    
    }
    
    
    SIGNAL(SIG_UART_RECV) //obsługa przerwania od odbiornika (bit RXCIE w UCSRB)
       {
          PORTB=0x03;
          char odebrane=UDR;
          USART_Transmit('1');
    
       }
    
  • #7 6686630
    lebe
    Poziom 10  
    Po dopasowaniu do AT128 skończyłem z takim kodem:
    
    #include <avr/io.h>                // dostęp do rejestrów
    #include <util/delay.h>
    #include <avr/interrupt.h>
    //#include <avr/signal.h>
    
    
    #define F_CPU      14745600    //częstotliwość zegara w Hz
    #define UART_BAUD   19200UL       //prędkość transmisji
    #define UART_CONST   (F_CPU/(16ul*UART_BAUD)-1)
    
    void USART_Init ( unsigned int ubrr) // inicjalizacja UARTU
    {
       UBRR1H= (unsigned char)(ubrr>>8);
       UBRR1L= (unsigned char)(ubrr);      //ustawienie prędkości transmisji
    
       UCSR1B=  (1 << RXCIE1) |(1<< RXEN1)|(1<<TXEN1) ; //uaktywnienie przerwań od odbioru i nadawania, uaktywnienie nadajnika i odbiornika UART. Tu trzeba usunąć (1<<TXCIE) lub dopisać do tego przerwania obsługę
    
       UCSR1C=  (3<<UCSZ10); //Ustawienie ilości danych i parzystości
    
       sei(); //zezwolenie na przerwania
    }
    
    void USART_Transmit ( unsigned char data) //podprogram do transmisji danych
    {
       while (!(UCSR1A&(1<<UDRE1)));
    
       UDR1 = data;
    }
    
    int main(void)                        // program główny
    {
       USART_Init( UART_CONST);
       DDRB=0xFF;
    
    
        while(1)
        {
    
           //USART_Transmit('A');
           _delay_ms(1000);
        }
    
    }
    
    
    SIGNAL(SIG_UART1_RECV) //obsługa przerwania od odbiornika (bit RXCIE w UCSRB)
       {
          PORTB=0x03;
          char odebrane=UDR1;
          USART_Transmit('1');
    
       } 
    


    Sprawdzałem z kwarcem 16MHz i 14.7456 także z różnymi ustawieniami BaduRate i optymalizacji, niestety zamiast '1' dostaję 'g' ;/
  • #8 6686682
    donelbaron
    Poziom 15  
    a patrzyłes np czy Ci może dobrze czyta na innych szybkościach? kiedyś czytałem coś takiego ze ktoś miał ustawiony fuse bit dzielnika taktowania procka przez 8. pewnie to nei to, ale sprawdz na wszystkich predkosciach.
  • #9 6686704
    lebe
    Poziom 10  
    Sprawdzałem różne prędkości i nic. Korzystam z płytki modułu mikrovega
    Link
    zastosowane w nim kondensatory przy maksie to: 4x 1uF i 1x 10 uF.
    Jeśli masz czas i możliwości mógłbyś skompilować mi program na swoim kompilatorze i podesłać hex'a? Byłbym bardzo wdzięczny.
  • #10 6686711
    donelbaron
    Poziom 15  
    jasne , który? ten wyżej?
  • #11 6686720
    lebe
    Poziom 10  
    może najlepiej obydwa, te z prędkościami 14,7456 MHz, bo co do kwarcu jestem dość mocno przekonany

    Chciałem jeszcze dodać, że Twój program działa u mnie po skompilowaniu na ATmedze16.
  • #12 6686739
    donelbaron
    Poziom 15  
    to jest hex dla twojego procka, z twoja predkoscia dla kwarcu. tylko zmien rozszezenie, z cpp na hex, bo nie można plików hex wrzucać.
  • #13 6686741
    donelbaron
    Poziom 15  
    to dla mojej atmegi raczej by ci chyba nie poszlo bo widze ze w atmedze128 jest juz wiecej rejestrów UDR niż jeden i pewnei trzeba deklarować który.
  • #14 6686745
    lebe
    Poziom 10  
    Wielkie dzięki za dotychczasową pomoc. Jutro wracam do walki tymczasem postaram się wykorzystać pozostałe 4 godziny na sen ;)
  • #15 6692768
    djnick
    Poziom 11  
    Witam!
    Może pomoge, o to mój kod do obsługi USART1 dla ATmega128

    
    
    char __USART1_buf_RX[50];
    char __USART1_buf_TX[50];
    char __AT_comand_buf[20];
    #define __CR 0x0a
    #define osc_freq 16
    
    void USART1_ini(uint16_t __baud, uint8_t __parality, uint8_t __stop)	// __baud-prędkosć transmisji w b/s
    																	// __parality bit parzystości 0-tak 1-nie
    																	// __stop liczba bitów stopu 1 lub 2
    {
    	union
    	{
    		uint16_t __ubrr;
    		uint8_t __ubrr8[2];
    	}__speed;
    
    	__speed.__ubrr = (62500*osc_freq/__baud)-1;
    	if(__speed.__ubrr<255)
    	{
    		UBRR1L = __speed.__ubrr;
    		UBRR1H = 0;
    	}
    	else
    	{
    		UBRR1L = __speed.__ubrr8[0];
    		UBRR1H = __speed.__ubrr8[1];		
    		
    	}
    	if(__parality == 1)sbi(UCSR1C,UPM11);
    	if(__stop == 2)sbi(UCSR1C,USBS1);	
    	
    	UCSR1C = (1<<UCSZ10)|(1<<UCSZ11);			// modyfikuj rejestr UCSRS, 8 bitów, brak bitu parzystości, 1 bit stopu
    	UCSR1B = (1<<RXEN1)|(1<<TXEN1);				// włącz TX i RX , włacz 	
    }
    char USART1_read_byte()
    {
    	while(bit_is_clear(UCSR1A,RXC1))					// czekaj na odebranie bajtu danych
    		if(UCSR1A&0x1C != 0)return(0xFF);				// sprawdz znaczniki błędów
    													// jeśli odebrano z błedem zwróć FF jako monit o błędzie
    		return(UDR1);									// jeśli poprawne zwróć odebrany bajt danych
    }
    void USART1_write_byte(char __byte)
    {
    	while(bit_is_clear(UCSR1A,UDRE1));		// czekaj na zwolnienie bufora nadawczego
    	UDR1 = __byte;							// prześlij bajt danych
    }
    uint8_t USART1_read_block(uint8_t __size)
    {
    	uint8_t __nr = 0;
    	for(;__size>0;__size--,__nr++)
    	{
    		__USART1_buf_RX[__nr] = USART1_read_byte();
    		if(__USART1_buf_RX[__nr] == 0xFF)
    		{
    			return(0);
    			break;
    		}
    	}
    	return(1);
    }
    void USART1_write_block(uint8_t *__pointer_ram, uint8_t __size)
    {
    	uint8_t __nr = 0;
    	for(;__size>0;__size--)
    	{
    		USART1_write_byte(__pointer_ram[__nr++]);
    	}
    }
    
    void USART1_write_tekst(char *__tekst)
    {
    	char __zn;
    	char __nr = 0;
    
    	while(1)
    	{
    		__zn = __tekst[__nr++];
    		if(__zn != 0)
    		{
    			USART1_write_byte(__zn);
    		}
    		else
    		{
    			USART1_write_byte(0x0D);
    			break;
    		}
    	}
    }
    uint8_t USART1_read_tekst(void)
    {
    	char __zn;
    	char __nr = 0;
    
    	while(1)
    	{
    		__zn = USART1_read_byte();
    		if(__zn != 0x0D)
    		{
    			__USART1_buf_RX[__nr++] = __zn;
    		}
    		else
    		{
    			__USART1_buf_RX[__nr] = 0;
    			break;
    		}
    	}
    	return(*__USART1_buf_RX);
    }
    


    Jeśli coś niezrozumiałe lub jak namierzyliście jakiś bład piszcie :D .
    Działam na tym kodzie już od jakiegoś czasu.
    Pozdrawiam!
  • #16 6693220
    donelbaron
    Poziom 15  
    po co te podkreslenia przy zmiennych? przeciez to sie robie nieczytelne przez to
  • #17 6693330
    djnick
    Poziom 11  
    Podkreślenia daje po to żeby później przez przypade nie używć tych samych zmiennych. Ten kod jest u mnie jako część bibloteki.
    Gdzieś już tak widziałem i teraz tak zawsze robie :D
  • #18 6695351
    donelbaron
    Poziom 15  
    pewnei zobaczyłęs to w jakimś c++ builderze, tam są niektore funkcje tak definiowane np __fastcall czy cos takiego.
  • #19 6751117
    lebe
    Poziom 10  
    Problem został rozwiązany. Okazało się, że był nim wadliwy przewód, który działał z płytką startową pod AT16 (firma And-Tech) - jak się okazało nie wyposażoną w Maxa. Nie działał już natomiast z płytką od AT128, gdzie Max jest już zamontowany. Dziękuję wszystkim za udzieloną pomoc :)
REKLAMA