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

ATMEGA16 - PCet: bledy transmisji przy wyzszych predkosciach

idom 09 Paź 2008 20:40 1611 16
  • #1 5616260
    idom
    Poziom 10  
    mam nastepujaca zagwostke ...
    oto moj kod prostego programu:

    #include <avr/io.h>
    #include <avr/signal.h>
    #include "uart.h"
    
    //register unsigned char data_uart asm("r15");
    unsigned char data_uart; //dana
    **********************************************************************************************/
    /*PROGRAM GLOWNY*/
    /**********************************************************************************************/
    int main( void )
    {
    	USART_Init (17); //9,6k=71;14,4k=47;19,2k=35;28,8k=23;38,4k=17;57,6k=11;76,8k=8;115,2k=5
    	while(1)
    	{	
    		data_uart = USART_Receive();
    		USART_Transmit(data_uart);	
    		USART_Transmit('\n');
    		USART_Transmit('a');
    //...
    		USART_Transmit('Z');
    		USART_Transmit('\n');
    	}
    return(0);
    }
    /**********************************************************************************************/
    /*FUNKCJE deklaracje*/
    /**********************************************************************************************/
    void USART_Init( unsigned int baud )
    {
    	UBRRH = (unsigned char)(baud>>8);
    	UBRRL = (unsigned char)baud;
    
    	UCSRB = (1<<RXEN)|(1<<TXEN);//|(1<<RXCIE);			
    	UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
    }
    /**********************************************************************************************/
    /*WYSYLANIE*/
    void USART_Transmit ( unsigned char data )
    {
    while ( !( UCSRA & (1<<UDRE))) ;
    UDR = data;
    }
    /**********************************************************************************************/
    /*ODBIOR*/
    unsigned char USART_Receive( void )
    {
    	while ( !(UCSRA & (1<<RXC)) );	
    	return UDR;								
    }
    


    jak kazdy widzi, program ma za zadanie wyslanie znakow alfabetu oraz tego znaku, jaki nacisnie uzytkownik na klawiaturze PCta, wszystko ladnie i pieknie chodzi, jesli predkosc jest nie wieksza niz 28800 bodow, powyzej tej wartosci pojawiaja sie duze przeklamania przy wysylaniu znaku z PCta na uC, natomiast w druga strone wszystko jest ok. (wszystkie instrukcje typu "USART_Transmit('Z');" realizowane sa poprawnie). Moim zadaniem jest uzyskanie predkosci 115,2k, niestety poprawna komunikacja jest przy 3 razy nizszej:/ ... oczywiscie uzywam zewn. kwarcu 11,0592MHz, z dwoma C = 22pF (oczywiscie fuse bits sa dostosowane). Uzywam rowniez kosci FTDI jako modulu MMusb232RL, zakupionego w propoxie, co do konfiguracji tego modulu jest ok, gdyz korzystalem z wytycznych manuala. Co do kabli ... sa one krotkie,zamienialem je na inne i nadal nic. Nie wiem co moze byc nie tak, gdybym cos zle poustawial to transmisja w obie strony nie bylaby poprawna na mniejszych predkosciach... . Z gory dzieki za jakiekolwiek sugestie, pozdr
  • #2 5616613
    Przemek_Kuchta
    Poziom 20  
    Nasuwają mi się 2 rzeczy:
    1. Można by dorzucić bit parzystości by zmniejszyć błąd.
    2. Sprawdź kwarc, bo jeśli nie jest on o założonej częstotliwości rezonansowej to pojawi się spory błąd. Looknij strona 169 dokumentacji do atmegi16 są tabele błędów transmisji w zależności od prędkosci i kwarców.
  • #3 5616721
    idom
    Poziom 10  
    ad1. zabawa (1<<UPM1)|(1<<UPM0), zwraca te same bledne wartosci
    ad2. dokladnie na 170ej dla tej wartosci czestotliwosci:), ale blad ma wartosc 0.0%, fakt, moze sam kwarc byc padniety, sprobuje go podmienic
  • #4 5616785
    bolek
    Poziom 35  
    Polecał bym odrazu zapiąć do atmegi generator kwarcowy, z kwarcami różnie bywa. Mi osobiście pomogło i też rozpędziłem sie do 115k
  • #5 5616789
    Pijopic
    Poziom 17  
    I przy okazji wstaw opoznienie miedzy odbiorem a nadawaniem, na pewno pomoze, choc to polsrodek, kompleksowe rozwiazanie to zmiana calkowicie programu...
  • #6 5616802
    idom
    Poziom 10  
    np. tego typu
    void delay( unsigned int time )
    {
    	unsigned int i;
    	for ( i = 0 ; i <= time ; i++ )
    	{
    		asm( "NOP" );
    	}
    }

    tez niestety nie pomaga

    ps1: transmisja z uC na PCta jest uruchamiana przyciskiem START i zatrzymywana STOPem, w tym czasie nie jest mozliwe z pozycji interfejsu uzytkownika wysylanie czegokolwiek z PCta na uC

    ps2: "Polecał bym odrazu zapiąć do atmegi generator kwarcowy, z kwarcami różnie bywa. Mi osobiście pomogło i też rozpędziłem sie do 115k" tylko jaka wartosc tego generatora bylaby najodpowiedniejsza wg Ciebie?? bo z tego co widze na tme.pl to nie ma takich typowych wersji, aby blad wynosil 0.0% w transmisji
  • #7 5617182
    Pijopic
    Poziom 17  
    Opoznienie powinno byc tak wstawione:

    
    data_uart = USART_Receive(); 
    -> delay
    USART_Transmit(data_uart);   
     


    Jesli masz inaczej to normalne, ze nic nie da, no i opoznienie troche wieksze mialem na mysli niz 0,6ms raczej 10-20ms. Sporo tez zalezy od tego co odpowiada za transmisje po stronie PC i to jak napisales ta czesc oprogramowania moze bardziej mieszac niz oprogramowanie w mikrokontrolerze...
    I zostaw kwarc w spokoju na 99,99% to nie on jest powodem problemow.
  • #8 5618221
    Piotr Piechota
    Poziom 22  
    Kiedyś też miałem kwarc który miał 'nienominalną' częstotliwość.
    Pomogło delikatne skorygowanie UBRR dostosowując prędkość do faktycznej częstotliwości kwarcu.

    Pozdrawiam
  • #9 5619248
    idom
    Poziom 10  
    Pijopic napisał:
    Sporo tez zalezy od tego co odpowiada za transmisje po stronie PC i to jak napisales ta czesc oprogramowania moze bardziej mieszac niz oprogramowanie w mikrokontrolerze...
    I zostaw kwarc w spokoju na 99,99% to nie on jest powodem problemow.


    co do opoznienia to oczywiscie mam tak jak napisales, co do oprogramowania w PCcie to jest to jeden z templatow LabWindows/CVI, ale to i tak nie ma znaczenia, bo te same bledne wartosci w transmisji dostawalem na 3ech roznych terminalach

    ps: kwarc musi byc ok, bo transmisja z uC na PCet jest poprawna przy duzych predkosciach
  • #10 5619544
    Piotr Piechota
    Poziom 22  
    Czy wysyłając znak z PC'ta wysyłasz jeden bajt i czekasz czy wysyłasz cały ciąg?
    Jeżeli wysyłasz szybko więcej znaków to bufor uC (a tam nie ma FIFO) zostanie przepełniony. Sprawdź flagę UCSRA DOR - Data OverRun.

    Pozdrawiam

    PS Korzystniej byłoby obsługiwać przychodzące znaki w przerwaniu i pisać do własnego bufora.
  • #11 5619577
    idom
    Poziom 10  
    Piotr Piechota napisał:
    Czy wysyłając znak z PC'ta wysyłasz jeden bajt i czekasz czy wysyłasz cały ciąg?
    Jeżeli wysyłasz szybko więcej znaków to bufor uC (a tam nie ma FIFO) zostanie przepełniony. Sprawdź flagę UCSRA DOR - Data OverRun.

    Pozdrawiam

    PS Korzystniej byłoby obsługiwać przychodzące znaki w przerwaniu i pisać do własnego bufora.



    we wlasciwym kodzie mojego programu uzywam konstrukcji:
    case 'c':	
    {...				
    }
    break;

    wiec tylko jeden znak (bajt)...
    poza tym....gdy wysylam z terminala na PCcie np "cccc" (enter) to uC odpowiada czterema znakami "c", wiec tutaj chyba nadpisywnaie nie wchodzi w gre
  • #12 5619603
    Piotr Piechota
    Poziom 22  
    Nie do końca rozumiem co masz na myśli pisząc:
    case 'c':   
    {...            
    }
    break;


    czy to fragment kodu w PC cz uC

    Dodam jeszcze że Enter to dla niektórych terminali wysłanie dwu znaków CR i LF
  • #13 5619641
    idom
    Poziom 10  
    nie chcialem wklejac calego kodu dla uC :), wybralem tylko ta czesc co mi nie dziala
    oto calosc uC:
    #include <avr/io.h>
    #include <avr/signal.h>
    #include "uart.h"
    #include "SPI.c"
    #include "twiradzio.c"
    
    #define 	MUX_ON		PORTB |= 0x02	//ustawia 1 na pinie
    #define 	MUX_OFF		PORTB &= 0xFD	//ustawia 0 na pinie
    
    #define SlaveAddress_x	0x5E 			//adres slave kanalu CH0 01011110 = 0x5E; slave address 11
    #define SlaveAddress_y	0x5C 			//adres slave kanalu CH1 01011100 = 0x5C; slave address 10
    #define SlaveAddress_z	0x5A 			//adres slave kanalu CH2 01011010 = 0x5A; slave address 01
    
    unsigned int data_uart; //dana
    unsigned int wzm_x; 	//wzmocnienie CH0
    unsigned int wzm_y; 	//wzmocnienie CH1
    unsigned int wzm_z; 	//wzmocnienie CH2
    
    /**********************************************************************************************/
    /*PROGRAM GLOWNY*/
    /**********************************************************************************************/
    int main( void )
    {
    	//USART_Init (UART_CONST);
    	USART_Init (23);
    	while(1)
    	{
    		init(); //konfiguracja, inicjalizacja kanalow ADC (w SPI)
    		data_uart = USART_Receive();	
    
    
    		switch(data_uart)
    		{
    			case 'a':	// obsluga kanalu CH0
    				{				
    					data_CH0 = Get_data(0);		
    					// data_CH0 = 0;					
    					delay(10);
    					USART_Transmit(data_CH0>>8); // odsylamy
    					USART_Transmit(data_CH0); // odsylamy
    					//USART_Transmit('A');
    					//USART_Transmit('\n'); // koniec wiersza <enter>
    				}
    			break;
    
    			case 'b':	// obsluga kanalu CH1
    				{
    					data_CH1 = Get_data(1);		
    					// data_CH1 = 0;					
    					delay(10);	
    					USART_Transmit(data_CH1>>8); // odsylamy
    					USART_Transmit(data_CH1); // odsylamy		
    					//USART_Transmit('B');
    					//USART_Transmit('\n'); // koniec wiersza <enter>				
    				}
    			break;
    
    			case 'c':	// obsluga kanalu CH2
    				{
    					data_CH2 = Get_data(2);		
    					// data_CH1 = 0;					
    					delay(10);	
    					USART_Transmit(data_CH2>>8); // odsylamy
    					USART_Transmit(data_CH2); // odsylamy	
    					//USART_Transmit('C');
    					//USART_Transmit('\n'); // koniec wiersza <enter>					
    				}
    			break;
    			
    			case 'x': //x - ustaw wzmocnienie CH0
    				{	
    					wzm_x = USART_Receive();	// ok, czeka na wzmocnienie
    					I2C_Start();
    					I2C_Write(SlaveAddress_x);
    					I2C_Write(0x00); //frame2 - instruction byte - nota katalogowa
    					I2C_Write(wzm_x); //wzmacnia, np. D=28 -> 00011100 -> 0x1C
    					I2C_Stop();
    					//USART_Transmit('O'); //potwiedzenie operacji
    					USART_Transmit('K'); //potwiedzenie operacji
    					//USART_Transmit('\n'); //potwiedzenie operacji
    			}
    			break;
    
    			case 'y': //y - ustaw wzmocnienie CH1
    				{	
    					wzm_y = USART_Receive();	// ok, czeka na wzmocnienie
    					I2C_Start();
    					I2C_Write(SlaveAddress_y);
    					I2C_Write(0x00); //frame2 - instruction byte - nota katalogowa
    					I2C_Write(wzm_y); //wzmacnia, np. D=28 -> 00011100 -> 0x1C
    					I2C_Stop();
    					//USART_Transmit('O'); //potwiedzenie operacji
    					USART_Transmit('K'); //potwiedzenie operacji
    					//USART_Transmit('\n'); //potwiedzenie operacji
    			}
    			break;
    
    			case 'z': //z - ustaw wzmocnienie CH2
    				{	
    					wzm_z = USART_Receive();	// ok, czeka na wzmocnienie
    					//SlaveAddress_z = 0x5A; //01011100 = 0x5C; slave address 10; write - 0
    					I2C_Start();
    					I2C_Write(SlaveAddress_z);
    					I2C_Write(0x00); //frame2 - instruction byte - nota katalogowa
    					I2C_Write(wzm_z); //wzmacnia, np. D=28 -> 00011100 -> 0x1C
    					I2C_Stop();
    					//USART_Transmit('O'); //potwiedzenie operacji
    					USART_Transmit('K'); //potwiedzenie operacji
    					//USART_Transmit('\n'); //potwiedzenie operacji
    			}
    			break;
    			
    			case 't':
    				{
    					MUX_ON;
    					USART_Transmit('t');
    				}
    			break;
    
    			case 'n':
    				{
    					MUX_OFF;
    					USART_Transmit('n');
    				}
    			break;
    
    			/*default:
    				USART_Transmit('E'); //znak "E" - jak error
    				USART_Transmit('R'); //znak "E" - jak error
    				USART_Transmit('R'); //znak "E" - jak error */
    
    		}
    	}
    return(0);
    }
    /**********************************************************************************************/
    /*FUNKCJE deklaracje*/
    /**********************************************************************************************/
    void USART_Init( unsigned int baud )
    {
    	UBRRH = (unsigned char)(baud>>8);	// Set baud rate
    	UBRRL = (unsigned char)baud;
    
    	// Enable Receiver and Transmitter: zalaczenie RX, TX, RXCIE-przerwanie zakonczenia odbioru	
    	UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);	
    	// Set frame format: 2bit stopu; 8data 		
    	UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);	
    }
    /**********************************************************************************************/
    /*WYSYLANIE*/
    void USART_Transmit ( unsigned char data )
    {
    /* Wait for empty transmit buffer: sprawdzamy jaska jest flaga UDRE - pojawi sie gdy rej UDR
    jest gotowy na przyjecie danych */
    while ( !( UCSRA & (1<<UDRE))) ;
    /* Put data into buffer, sends the data zapisanie danej do rejestru po uprzednim sprawdzeniu UDRE */
    UDR = data;
    }
    /**********************************************************************************************/
    /*ODBIOR*/
    unsigned char USART_Receive( void )
    {
    	/* Wait for data to be received: sprawdzenie flagi RXC,
    	1 - gdy w buforze odbiorczym sa dane nieodczytane */
    	while ( !(UCSRA & (1<<RXC)) );	
    	/* Get and return received data from buffer */		
    	return UDR;									
    }

    dla kazdego bajtu (literki) przypisalem funkcje ...
    nie chce rozpisywac sie na temat CVI, w ktorym robie interfejs, ale uzytkownik cokolwiek zmieniajac powoduje wyslanie z PCta na uC bajtu-literki, ktora wywoluje okreslona reakcje w uC
  • #14 5619756
    Piotr Piechota
    Poziom 22  
    1) Przetestuj sprzęt - połącz linie RXD i TXD po stronie RS232 i napisz program który wysyła znaki, sprawdź czy dostajesz to samo.

    2) Sprawdź jednak w programie flagę overrun - taki sposób w jaki zaproponowałeś obsługę UART'a w żaden sposób nie jest odporny na ciągły strumień danych wejściowych.

    3) Powtórzę się z wbudowaniem obsługi przerwania od ustawienia RXC
  • #15 5621567
    idom
    Poziom 10  
    ad 1. polaczylem kablem RxD i TxD, wrzucilem kod
    int main( void )
    {
    	USART_Init (5); //9,6k=71;14,4k=47;19,2k=35;28,8k=23;38,4k=17;57,6k=11;76,8k=8;115,2k=5
    	USART_Transmit('b');
    	data_uart = USART_Receive();
    return(0);
    }


    no i co nie wpisze w
    USART_Transmit('b');
    to i tak zawsze w zmiennej data_uart zwroci mi poprawna wartosc, gdy ten kod puszcze przez modul FTDI to przy wyzszych predkoscia zwraca mi pod zmienna data_uart bzdurne wartosci.
    Skoro tak sie dzieje, to blad chyba musi byc na drodze uC-modul FTDI lub w samej FTDI

    ad2. flaga zawsze ma wartosc 0
    ATMEGA16 - PCet: bledy transmisji przy wyzszych predkosciach

    ad3. wlasnie tym teraz sie zajme ...
  • #16 5622316
    ilmenauer
    Poziom 14  
    Oscyloskop dobry na wszystko ;)
    Każ terminalowi w PC wysyłać cały czas ten sam znak (na potrzeby synchronizacji analogowego oscyloskopu) albo wyślij jeden znany znak i zatrzaśnij przebieg z linii RxD w cyfrowym oscy. Zobaczysz czy poziomy elektryczne i bity są zgodne z wartością, którą wysłałeś do ATMEGA16.
    Jeśli tu jest O.K. to musisz przeanalizować kod programu i sprawdzić rzeczywistą częstotliwość taktowania.
    Bity transmitowane są raczej OK bo jak piszesz loopback działa dobrze ale poziomy logiczne mogą nieco odstawać od potrzeb ATMEGA16
    Jeśli wchodzący do procesora sygnał jest wadliwy to... nie pomogę :( bo USB, FTDI, windows to nie moje zabawki.
  • #17 5631100
    idom
    Poziom 10  
    dopiero wczoraj mialem okazje pracowac z osyloskopem, no i okazalo sie, ze mialem pojemnosc miedzy linia RxD a GND, w sumie nie wiem po co i jak ona tam sie znalazla, ale na oscyloskopie ladnie wyszlo, ze nie zdazyla przeladowywac sie przy wyzszych predkosciach, wiec usunalem ja i wszystko dziala poprawnie, dzieki za wszystkie pomysly
    pozdr

    @$
REKLAMA