-         

Ergebnis 1 bis 8 von 8

Thema: Mal wieder ein UART Problem

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    18.01.2005
    Alter
    41
    Beiträge
    61

    Mal wieder ein UART Problem

    Anzeige

    Hallo,

    versuche mir zur Zeit eine sichere UART-Verbindung aufzubauen.
    Die Grundlagen dazu, habe ich mir mit eigen geschriebenen Quellcode erarbeitet, was auch beim Senden von Einzelzeichen ganz gut funktioniert hatte.
    Nun wollte ich mir die Herangehensweise mittels Buffer anhand des von Peter Fleury bereitgestellten UART-Quellcodes erarbeiten. Dazu habe ich versucht, diesen Code an den Prozessor (ATMega16) anzupassen, den ich benutzen will und alles andere an QC wegzulassen (den, den ich nicht benötige).
    Leider klappt nicht alles so, wie ichs mir erhofte - den Fehler habe ich leider nicht finden können.
    Das Programm funktioniert quasi bis zur while(1) Schleife - das heißt, die Ausgaben werden ordentlich an ein Terminalprogramm übergeben.
    Allerdings werden keine Zeichen, die im Terminalprogramm eingegeben werden, "geechot".
    Vielleicht habe ich schon zu lange drauf geschaut - ich hoffe mir kann jemand zur Lösung verhelfen.

    Hier der genutzte Quellcode (ohne uart.h, da daran nix geändert wurde):

    Code:
    /*
     * Notes:
     * Based on Atmel Application Notes AVR306 and the library of Peter Fleury
     */
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <util/delay.h>
    #include <avr/pgmspace.h>
    #include "uart.h"
    
    /*
     * constants and makros
     */
    #define F_CPU 8000000UL
    
    /* 9600 baud */
    #define UART_BAUD_RATE      9600
    
    
    //size of RX/TX buffers
    #define UART_RX_BUFFER_MASK (UART_RX_BUFFER_SIZE-1)
    #define UART_TX_BUFFER_MASK (UART_RX_BUFFER_SIZE-1)
    
    /*ATmega with one USART*/
    	#define ATMEGA_USART
    	#define UART0_RECEIVE_INTERRUPT		USART_RXC_vect
    	#define UART0_TRANSMIT_INTERRUPT	USART_UDRE_vect
    	#define UART0_STATUS	UCSRA
    	#define UART0_CONTROL	UCSRB
    	#define UART0_DATA		UDR
    	#define UART0_UDRIE	UDRIE		//USART Data Register Empty Interrupt Enable
    
    /*
     * modul global variables
     */
    static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
    static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];
    static volatile unsigned char UART_TxHead;
    static volatile unsigned char UART_TxTail;
    static volatile unsigned char UART_RxHead;
    static volatile unsigned char UART_RxTail;
    static volatile unsigned char UART_LastRxError;
    
    ISR(UART0_RECEIVE_INTERRUPT)
    /********************************************************************************************************/
    // Function: UART Receive Complete Int
    // Purpose : called, when the UART has received a character
    /********************************************************************************************************/
    {
    	unsigned char tmphead;
    	unsigned char data;
    	unsigned char usr;
    	unsigned char lastRxError;
    
    	/*read UART status register and UART data register*/
    	usr  = UART0_STATUS;
    	data = UART0_DATA;
    
    	lastRxError = (usr & ( (1<<FE) | 1<<DOR) );
    
    	/*calculate buffer index*/
    	tmphead = (UART_RxHead + 1) & UART_RX_BUFFER_MASK;
    
    	if(tmphead == UART_RxTail)
    	{
    		lastRxError = UART_BUFFER_OVERFLOW >> 8;
    	}
    	else
    	{
    		/*store new index*/
    		UART_RxHead = tmphead;
    		/*store received data in buffer*/
    		UART_RxBuf[tmphead] = data;
    	}
    	UART_LastRxError = lastRxError;
    }
    
    ISR(UART0_TRANSMIT_INTERRUPT)
    /********************************************************************************************************/
    // Function: UART Data Register Empty Int
    // Purpose : called, when the UART is ready to transmit the next byte
    /********************************************************************************************************/
    {
    	unsigned char tmptail;
    
    	if(UART_TxHead != UART_TxTail)
    	{
    		/*calculate and store new buffer index*/
    		tmptail = (UART_TxTail +1) & UART_TX_BUFFER_MASK;
    		UART_TxTail = tmptail;
    		/*get one Byte from buffer and write it to UART*/
    		UART0_DATA = UART_TxBuf[tmptail];					//start transmission
    	}
    	else
    	{
    		/*tx buffer empty, disable UDRE interrupt*/
    		UART0_CONTROL &= ~(1<<UART0_UDRIE);
    	}
    }
    
    void uart_init(unsigned int baudrate)
    /********************************************************************************************************/
    // Function: uart_init()
    // Purpose : initialize UART and set baudrate
    // Input   : baudrate using macro UART_BAUD_SELECT
    // Returns : none
    /********************************************************************************************************/
    {
    	/*first definition of buffer indicies*/
    	UART_TxHead = 0;
    	UART_RxTail = 0;
    	UART_RxHead = 0;
    	UART_TxTail = 0;
    
    	/*set baudrate*/
    	if(baudrate & 0x8000)
    	{
    		UART0_STATUS = (1<<U2X);							//Enable 2x speed
    		baudrate &= ~0x8000;
    	}
    	UBRRH = (unsigned char)(baudrate>>8);
    	UBRRL = (unsigned char)(baudrate);
    		
    	/*Enable UART receiver, transmitter and receive complete interrupt*/
    	UART0_CONTROL = (1<<RXCIE) | (1<<RXEN) | (1<<TXEN);//
    	
    	/*Set frame format: asynchronous, 8databits, no parity, 1Stopbit*/
    	#ifdef URSEL
    		UCSRC = (1<<URSEL) | (3<<UCSZ0);
    	#else
    		UCSRC = (3<<UCSZ0);
    	#endif
    
    	// Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte)
    	do
    		    {
    		        UART0_DATA;
    		    }
    		    while (UART0_STATUS & (1 << RXC));
    }
    
    unsigned int uart_getc(void)
    /********************************************************************************************************/
    // Function: uart_getc()
    // Purpose : returns byte from ringbuffer
    // Input   : none
    // Returns : lower byte: received byte from ringbuffer / higher byte: last receive error
    /********************************************************************************************************/
    {
    	unsigned char tmptail;
    	unsigned char data;
    
    	if(UART_RxHead == UART_RxTail)
    	{
    		return UART_NO_DATA;								//no data available
    	}
    
    	/*calculate and store buffer index*/
    	tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;
    	UART_RxTail = tmptail;
    
    	/*get data from receive buffer*/
    	data = UART_RxBuf[tmptail];
    
    	return (UART_LastRxError<<8) + data;
    }
    
    void uart_putc(unsigned char data)
    /********************************************************************************************************/
    // Function: uart_putc()
    // Purpose : write byte to ringbuffer for transmitting via UART
    // Input   : byte to be transmitted
    // Returns : none
    /********************************************************************************************************/
    {
    	unsigned char tmphead;
    
    	tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
    
    	while(tmphead == UART_TxTail);							//wait for free space in puffer
    
    	UART_TxBuf[tmphead] = data;
    	UART_TxHead = tmphead;
    
    	/*enable UDRE interrupt*/
    	UART0_CONTROL |= (1<<UART0_UDRIE);
    }
    
    void uart_puts(const char *s)
    /********************************************************************************************************/
    // Function: uart_puts()
    // Purpose : transmit string to UART
    // Input   : string to be transmitted
    // Returns : none
    /********************************************************************************************************/
    {
    	while(*s)
    	{
    		uart_putc(*s++);
    	}
    }
    
    void uart_puts_p(const char *progmem_s)
    /********************************************************************************************************/
    // Function: uart_puts_p()
    // Purpose : transmit string from program memory to UART
    // Input   : programm memory string to be transmitted
    // Returns : none
    /********************************************************************************************************/
    {
    	register char c;
    
    	while( (c = pgm_read_byte(progmem_s++)) )
    	{
    		uart_putc(c);
    	}
    }
    
    
    int main(void)
    {
        unsigned int c=0;
        char buffer[7];
        int  num=134;
    	DDRB=0xFF;					//for debugging
    
        
        /*
         *  Initialize UART library, pass baudrate and AVR cpu clock
         *  with the macro 
         *  UART_BAUD_SELECT() (normal speed mode )
         *  or 
         *  UART_BAUD_SELECT_DOUBLE_SPEED() ( double speed mode)
         */
        uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
        
        /*
         * now enable interrupt, since UART library is interrupt controlled
         */
        sei();
        
        /*
         *  Transmit string to UART
         *  The string is buffered by the UART library in a circular buffer
         *  and one character at a time is transmitted to the UART using interrupts.
         *  uart_puts() blocks if it can not write the whole string to the circular 
         *  buffer
         */
        uart_puts("String stored in SRAM\n");
        
        /*
         * Transmit string from program memory to UART
         */
        uart_puts_P("String stored in FLASH\n");
        
            
        /* 
         * Use standard avr-libc functions to convert numbers into string
         * before transmitting via UART
         */     
        itoa( num, buffer, 10);   // convert interger into string (decimal format)         
        uart_puts(buffer);        // and transmit string to UART
    PORTB=0x55;
        
        /*
         * Transmit single character to UART
         */
        uart_putc('>');
        while(!(c = uart_getc()));
        uart_putc( (unsigned char)c );
    	while(1)
        {
            c = uart_getc();
            if ( c & UART_NO_DATA )
            {PORTB=~0x55;//for debugging
            }
            else
            {
                if ( c & UART_FRAME_ERROR )
                {
                    /* Framing Error detected, i.e no stop bit detected */
                    uart_puts_P("UART Frame Error: ");
                }
                if ( c & UART_OVERRUN_ERROR )
                {
                    uart_puts_P("UART Overrun Error: ");
                }
                if ( c & UART_BUFFER_OVERFLOW )
                {
                    uart_puts_P("Buffer overflow error: ");
                }
                /* 
                 * send received character back
                 */
                uart_putc( (unsigned char)c );
            }
        }
    
    }

    Also, hoffe es schaut sich jemand an und schaffts auch noch den fehlenden Hinweis zu geben.

    Danke...

    @Edit Tippfehler in ISR_RXC UART_TxHead = tmphead;<-->UART_RxHead = tmphead;

  2. #2
    Benutzer Stammmitglied
    Registriert seit
    18.01.2005
    Alter
    41
    Beiträge
    61
    Hallo,

    wollte das Problem nochmal aktualisieren.
    In einem anderen Forum hat dankenswerterweise jemand einen Tippfehler gefunden, habe es oben editiert.
    Leider funktioniert es trotzdem immer noch nicht.
    Ich nutze das Programm "HTerm" - dort kann man eine Serie von Zeichen eingeben - erst bei der Betätigung von Enter wird der gesamte String verschickt. Und genau da liegt das Problem.
    Echo von einzelnen Zeichen funktioniert gut. Bei mehreren werden nur die ersten drei und das letzte Zeichen richtig dargestellt.
    Folgende Beispiele (Transmit -- Receive)
    1--1
    12--12
    123--123
    1234--1234
    12345--1235
    123456--1236
    1234567--1237
    12345678--1238
    usw.

    Weiß nicht woran es liegt, vielleicht auch am Terminalprogramm, wäre super wenn es mal jemand probieren könnte und seine Ergebnisse beschreibt.
    So langsam verzweifle ich daran....

  3. #3
    Erfahrener Benutzer Robotik Visionär Avatar von Hubert.G
    Registriert seit
    14.10.2006
    Ort
    Pasching OÖ
    Beiträge
    6.183
    Wenn einzelne Zeichen funktionieren, mehrere aber nicht mehr, dann deutet das auf eine abweichenede Frequenz hin.
    Arbeitest du mit dem internen Oszillator oder einem Quarz.
    Wenn Quarz, wie ist der angeschalten.
    Grüsse Hubert
    ____________

    Meine Projekte findet ihr auf schorsch.at

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von Jaecko
    Registriert seit
    16.10.2006
    Ort
    Lkr. Rottal/Inn
    Alter
    35
    Beiträge
    1.987
    Wie gross ist denn UART_RX_BUFFER_SIZE?
    Die Frequenzabweichung wird bei einem neuen Zeichen "zurückgesetzt", da das Startbit als Synchronisation arbeitet.
    #ifndef MfG
    #define MfG

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von Jaecko
    Registriert seit
    16.10.2006
    Ort
    Lkr. Rottal/Inn
    Alter
    35
    Beiträge
    1.987
    Wie gross ist denn UART_RX_BUFFER_SIZE?
    Die Frequenzabweichung wird bei einem neuen Zeichen "zurückgesetzt", da das Startbit als Synchronisation dient. Sieht eher nach einem überlaufenden Puffer irgendwo aus.
    #ifndef MfG
    #define MfG

  6. #6
    Benutzer Stammmitglied
    Registriert seit
    18.01.2005
    Alter
    41
    Beiträge
    61
    Hallo,
    danke erstmal für eure Bereitschaft helfen zu wollen.
    Da es keine extra Hardware gibt, nutze ich das STK500 als Plattform.
    Darauf arbeitet ein ATMega16 mit externem 8MHz-Quarz. Die Fuse des Taktes ist auf "Ext. Crystal/Resonator High Freq.; Start-up time 16K CK+64ms" gesetzt.
    Ich denke eigentlich auch, dass durch jedes Start/Stopbit bei jedem Byte eine Synchronisation im Asynchronmodus angestoßen wird.

    Die Größe des Buffers wird in der von Peter Fleury mitgelieferten Headerdatei eingestellt. Ich habe diese sowohl für den RX als auch für den TX Buffer auf 128 eingestellt.
    {
    Code:
    #define UART_RX_BUFFER_SIZE 128
    #define UART_TX_BUFFER_SIZE 128
    }

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    21.09.2008
    Beiträge
    5
    Kann man bei STK500 nicht den internen Board-Takt über das AVRStudio variieren? Vielleicht der Takt dort verstellt?!

  8. #8
    Neuer Benutzer Öfters hier
    Registriert seit
    21.09.2008
    Beiträge
    5
    Kann man beim STK500 nicht den internen Board-Takt über das AVRStudio variieren? Vielleicht der Takt dort verstellt?!

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •