Hallo,
Ich habe ein Problem mit dem USART_RX_vect-Interrupt des ATMega 328p. Das Empfangen funktioniert einwandfrei und ich kann die gesendeten Bits auswerten (es liegt also nicht an der Baudrate), aber jedes Mal, wenn ich ein Bit sende, wird die ISR 4 Mal ausgeführt.
Also eine ISR wie diese:
ISR(USART_RX_vect) {
uart_transmit('t');
uart_flush();
}
Wird {'t', 't', 't', 't'}
übertragen
Ich habe keine Ahnung, warum das passiert, und ich hoffe, Sie können mir helfen.
My main
ist eine leere Schleife (natürlich führe ich aus uart_setup
). Mein ISR ist wie oben. Ich verwende avr-gcc unter Linux.
Dies ist mein UART-Setup:
void uart_setup() {
UBRR0H = (BAUDRATE >> 8);
UBRR0L = BAUDRATE;
// Set 8-Bit mode
setBit(UCSR0C, UCSZ01);
setBit(UCSR0C, UCSZ00);
setBit(UCSR0B, RXEN0); // Receiver enable
setBit(UCSR0B, TXEN0); // Transmitter enable
setBit(UCSR0B, RXCIE0); // Enable RX Interrupt
sei(); // Enable global interrupts
}
void uart_transmit(unsigned char data)
{
while (!( UCSR0A & (1<<UDRE0))); // wait while register is free
UDR0 = data; // load data in the register
}
void uart_flush( void ) {
unsigned char dummy;
while ( UCSR0A & (1<<RXC0) ) dummy = UDR0;
}
Es scheint, dass das Design Ihres Codes so ist, dass Sie, wenn ein Byte im UART empfangen wird, dieses Byte entsorgen und mit der Übertragung eines "t" antworten möchten.
Der UART nutzt ein gemeinsames Empfangs-/Sendepufferregister. Da Ihre UART-Empfangsroutine interruptgesteuert ist, sollten Sie das empfangene Zeichen sofort lesen, bevor Sie die Antwort in den Puffer legen, da Sie sonst den Empfangsinterrupt beim Beenden erneut auslösen.
Es gibt auch keinen Grund, den 'while'-Code in der uart_flush-Routine zu haben, da Sie wissen, dass sich ein Zeichen im Puffer befindet, basierend auf der Tatsache, dass ein Interrupt Sie an diesen Punkt gebracht hat. Lesen Sie einfach das Pufferregister.
Hier ist eine vereinfachte Version eines korrigierten ISR ohne die Funktionen:
ISR(USART_RX_vect) {
unsigned char dummy;
dummy = UDR0; // dump the rcvr buffer
while (!( UCSR0A & (1<<UDRE0))); // wait until the register is free
UDR0 = data; // load xmt data in the register
}
Die Funktion uart_flush()
dient meines Erachtens keinem Zweck, es sei denn, Sie verwenden sie, um auf den Empfang aller Bytes zu warten? Ich denke, Ihr Problem ist, dass Sie die Dinge in umgekehrter Reihenfolge tun, Sie erhalten den Rx-Interrupt und schreiben dann in das UART-Datenregister und lesen dann daraus, ohne Garantie dafür, dass die Übertragung abgeschlossen ist. Ich denke, Sie müssen die Reihenfolge, in der Sie die Übertragung anrufen, tauschen und in Ihrer ISR spülen.