www.mikrocontroller.net

Forum: Compiler & IDEs UART UDRE Interrupt


Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

da ich mich nun doch entschieden habe RS485 zwischen Mega8 und PC zu 
verwenden, möchte ich vor jedem Senden PORTD2 auf high und nach jedem 
Senden PORTD2 auf low schalten.
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>

#include "uart.h"

 
#define UART_BAUD_RATE      57600


#ifndef F_CPU
#define F_CPU 16000000UL
#endif 

unsigned int a = 0;


int main(void)
{
DDRD = 0x04; 

char buffer[10];
unsigned int c;


sei();

uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );

PORTD |= (1 << PD2);  //umschalten auf Senden
uart_puts("\r\n");

PORTD |= (1 << PD2);  //umschalten auf Senden
uart_puts("HALLO" );

itoa( a, buffer, 10);  

uart_puts(buffer); 


    for(;;)
    {
        /*
         * Get received character from ringbuffer
         * uart_getc() returns in the lower byte the received character and
         * in the higher byte (bitmask) the last receive error
         * UART_NO_DATA is returned when no data is available.
         *
         */
       
    c = uart_getc();

    if ( c & UART_NO_DATA )
        {
             //no data available from UART
        }
        else
        {
        PORTD |= (1 << PD2);
     uart_putc( (unsigned int)c );
     
        }
    }

}

Das ist ein Ausschnitt aus der UART.c
/*************************************************************************
Function: UART Data Register Empty interrupt
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 &= ~_BV(UART0_UDRIE);
    PORTD &= ~(1 << PD2);  //umschalten auf Empfangen
    }
}
hier schalte ich den Port wieder auf low. Der Mega springt mir aber nur 
einmal bei uart_puts("\r\n"); rein und dann nie wieder. Außerdem 
überträg er mir das "HALLO" nicht richtig.

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dafür musst du den TXC (Transmission Complete) Interrupt nehmen, denn 
wenn der UDRE Interrupt auftritt, wird noch gesendet (der USART hat 
einen (kleinen) FIFO-Puffer).
Also, wenn dein Ringpuffer leer ist, muss sich der UDRE-Interrupt 
abschalten und der TXC schaltet dann den Pin D2 um.

Hth. Jörg

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das TXC Bit wird bei mir aber nie gesetzt. TXCIE habe ich auf high 
gesetzt. Liegt das an daran dass ich die Lib von Peter Fleury verwende?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Mike (Gast)

>Das TXC Bit wird bei mir aber nie gesetzt. TXCIE habe ich auf high

Doch, das wird immer gesetzt.

>gesetzt. Liegt das an daran dass ich die Lib von Peter Fleury verwende?

Keine Ahnung. Die Frage ist schlicht, wie den Programm gestrickt ist. 
Sinnvollerweise muss das so laufen.

Im UDRE Interrupt werden jeweils die Daten aus einem Puffer ins UDR 
geschrieben. Wenn das letzte Byte geschrieben ist, wird der UDRE 
Interrupt abgeschaltet! Und der TXC Interrupt angeschaltet.

Im TXC Interrupt wird dann der Tranceiver (RS485?) von Senden auf 
Empfangen umgestellt und der TXC Interrupt wieder abgeschaltet.

Eh Voila.

MfG
Falk

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist die Senderoutine.
/*************************************************************************
Function: uart_putc()
Purpose:  write byte to ringbuffer for transmitting via UART
Input:    byte to be transmitted
Returns:  none          
**************************************************************************/
void uart_putc(unsigned char data)
{
    unsigned char tmphead;

    
    tmphead  = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
    
    while ( tmphead == UART_TxTail ){
        ;/* wait for free space in buffer */
    }
    
    UART_TxBuf[tmphead] = data;
    UART_TxHead = tmphead;

    /* enable UDRE interrupt */
    UART0_CONTROL    |= _BV(UART0_UDRIE);

}/* uart_putc */
ich habe das Programm in der Simulation Schritt für Schritt durchlaufen 
lassen aber er springt mir nie in die ISR(USART_TXC_vect). Wenn ich das 
TXC Bit manuell auf high setze dann springt er mir sofort in die 
Interruptschleife rein.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Mike (Gast)

>Das ist die Senderoutine.

Nöö, die Funktion fügt nur Zeichen in einen Softwarepuffer ein. Die 
richtige Senderoutine liegt im UDRE Interrupt.

>ich habe das Programm in der Simulation Schritt für Schritt durchlaufen
>lassen aber er springt mir nie in die ISR(USART_TXC_vect). Wenn ich das
>TXC Bit manuell auf high setze dann springt er mir sofort in die
>Interruptschleife rein.

Du musst den TXC Interrupt auch freischalten (Maskenbit auf 1).

MfG
Falk

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
freigeschalten habe ich ihn. UCSRB |= (1<<TXCIE);
Hier nochmal der ganze Code.
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>

#include "uart.h"

#define UART_BAUD_RATE      57600

#ifndef F_CPU
#define F_CPU 16000000UL
#endif 

unsigned int a = 0;

ISR(USART_TXC_vect)
{
a++;
}


int main(void)
{
DDRD = 0x04; 

char buffer[10];
unsigned int c;


sei();

uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );
UCSRB |= (1<<TXCIE);

PORTD |= (1 << PD2);  //umschalten auf Senden
uart_puts("\r\n");

PORTD |= (1 << PD2);  //umschalten auf Senden
uart_puts("HALLO" );

itoa( a, buffer, 10);  

uart_puts(buffer); 


    for(;;)
    {
        /*
         * Get received character from ringbuffer
         * uart_getc() returns in the lower byte the received character and
         * in the higher byte (bitmask) the last receive error
         * UART_NO_DATA is returned when no data is available.
         *
         */
       
    c = uart_getc();

    if ( c & UART_NO_DATA )
        {
             //no data available from UART
        }
        else
        {
        PORTD |= (1 << PD2);
     uart_putc( (unsigned int)c );
     
        }
    }
}

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nun funktionierts doch. der Interrupt kommt nur nicht wenn man im AVR 
Studio Simuliert.
Danke für die Hilfe

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.