Archiv verlassen und diese Seite im Standarddesign anzeigen : UART sendet andauerd
Hallo zusammen,
ich habe versucht den Beispiel über Uart/Fido aus RN-Wissen nach zu programmieren...
Es klappt auch soweit allerdings sendet mein uart an dauernd, anstatt ein Zeichen.
Ich verstehe dass nicht! Benütze ja keine schleifen! Bitte um Hilfe.
int main()
{
uart_init();
sei(); // Wird nur gebraucht bei der Interrupt-Version
uart_putc ('f');
/*uart_puts ("Hallo Welt!" CR);*/
while (1)
{
}
return 0;
}
uart:
/* Senden eines Chars */
int uart_putc (const uint8_t data)
{
int ret = fifo_put (&out_fifo, data);
UCSRB |= (1 << UDRIE);
return ret;
}
fifo_put :
/* Schreibt das nächste Byte "data" in die FIFO.
* Liefer 1 bei Erfolg und 0, falls die FIFO voll ist. */
uint8_t fifo_put (fifo_t *f, const uint8_t data)
{
return _inline_fifo_put (f, data);
}
und _t fifo_put:
/* Schreibt das nächste Byte "data" in die FIFO.
* Liefer 1 bei Erfolg und 0, falls die FIFO voll ist. */
static inline uint8_t _inline_fifo_put (fifo_t *f, const uint8_t data)
{
if (f->count >= f->size)
return 0;
uint8_t * pwrite = f->pwrite;
*(pwrite++) = data;
uint8_t write2end = f->write2end;
if (--write2end == 0)
{
write2end = f->size;
pwrite -= write2end;
}
f->write2end = write2end;
f->pwrite = pwrite;
uint8_t sreg = SREG;
cli();
f->count++;
SREG = sreg;
return 1;
}
dank im voraus
Hallo nochmal,
habe folgende wichtige Punkte vergessen:
Kontroller= ATmega32, auf RBN-FRA1.21
Weis aber nicht ob es diese Daten die Ursache erklären...
Grüße
Khan
Wie sieht denn der Code zu uart_init aus? Aktivierst du da vielleicht interrupts? Wenn du dann die ISR dazu nicht schreibst, dürfte es Probleme(Reset des AVR) geben. Das würde ja genau das Verhalten deines AVRs beschreiben.
Danke für dein Beitrag!
Allerdings habe ich dass was du meintest nicht ganz verstanden...
meinst du ich tue den Kontroller irgend wo resetten?
Dass würde natürlich alles erklären. Allerdings habe ich die Stelle nicht gefunden und arbeite mich grad in Interrupts ein...
Wenn ein Reset stattfindet muss es nach dem ich das Zeichen gesendet habe geschehen, sonnst würde ich ja nichts bekommen wenn ich im uart_init reset machen würde....
Wie du siehst bin ich etwas verwirrt ;-) kannst du mir bitte dies bzgl. den Ort und den Grund für mein Fehler äußern...
Uart_init:
void uart_init()
{
uint8_t sreg = SREG;
UBRRH = UBRR_VAL >> 8;
UBRRL = UBRR_VAL & 0xFF;
cli(); /* Interrupts kurz deaktivieren */
UCSRB |= (1<<TXCIE) | (1<<TXEN); /* TXCompleteInterrupt u. TX einschalten */
UCSRC |= (1<<URSEL)| (1<<UCSZ1) | (1<<UCSZ0); /* Asynchron 8N1 */
/* Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte) */
do
{
/* UDR auslesen (Wert wird nicht verwendet) */
UDR;
}while (UCSRA & (1 << RXC));
/* Rücksetzen von Receive und Transmit Complete-Flags */
UCSRA = (1 << RXC) | (1 << TXC);
/* Global Interrupt-Flag wieder herstellen */
SREG = sreg;
/* FIFOs für Ein- und Ausgabe initialisieren */
fifo_init (&in_fifo, in_buffer, BUF_SIZE_IN);
fifo_init (&out_fifo, out_buffer, BUF_SIZE_OUT);
}
und
/*********************** INTERRUPTS ****************************************/
// Empfangene Zeichen werden in die Eingabgs-FIFO gespeichert und warten dort
SIGNAL (SIG_UART_RECV)
{
_inline_fifo_put (&in_fifo, UDR);
}
// Ein Zeichen aus der Ausgabe-FIFO lesen und ausgeben
// Ist das Zeichen fertig ausgegeben, wird ein neuer SIG_UART_DATA-IRQ getriggert
// Ist die FIFO leer, deaktiviert die ISR ihren eigenen IRQ.
SIGNAL (SIG_UART_DATA)
{
if (out_fifo.count > 0)
UDR = _inline_fifo_get (&out_fifo);
else
UCSRB &= ~(1 << UDRIE);
}
Hallo,
// Ein Zeichen aus der Ausgabe-FIFO lesen und ausgeben
// Ist das Zeichen fertig ausgegeben, wird ein neuer SIG_UART_DATA-IRQ getriggert
// Ist die FIFO leer, deaktiviert die ISR ihren eigenen IRQ.
SIGNAL (SIG_UART_DATA)
{
if (out_fifo.count > 0)
UDR = _inline_fifo_get (&out_fifo);
else
UCSRB &= ~(1 << UDRIE);
}
Wahrscheinlich ist out_fifo.count immer > 0 und _inline_fifo_get (&out_fifo); ergibt immer 'f'.
Gruß
Jens
Das ist doch wieder nicht der komplette code, oder? Wie soll man da wirklich helfen, wenn da immer irgendwo was fehlt.
Hast du das selbst programmiert? Oder hast du das von irgendwo hergenommen? Müsste das funktionieren, falls du es übernommen hast, oder ist es eher was experimentelles?
Was mir aufgefallen ist, ist, dass in der uart_init zwar der TXComplete-Interrupt aktiviert wird, aber da gibts keine ISR dazu und der wird ja dann ausgelöst, wenn was gesendet wurde. Und wenns dann keine ISR dazu gibt, gibts Probleme. Wahrscheinlich ist es das. Es sei denn das findet sich in einem anderen code-Teil...
Hallo Pascal,
Das ist doch wieder nicht der komplette code, oder?
Das wollte ich mit meinem Posting ausdrücken.
Gruß
Jens
Ok,
Eine ISR habe ich nicht.
es wird aber auch nicht vom
https://www.roboternetz.de/wissen/index.php/UART_mit_avr-gcc
explizit erwähnt, oder ich habe es überlesen....
Habe ja auch fast alles von dort kopiert...
Hier der Gesamte Kode:
Main.c
#include <avr/interrupt.h> /* Wird nur gebraucht bei der Interrupt-Version */
#include "uart.h"
/*==================[macros]=================================================*/
/* Ein Zeilenumbruch, abhängig davon, was die Gegenstelle haben will */
/* Windows: "rn" */
/* Linux : "n" */
/* MacOS : "r" */
#define CR "\r\n"
/*==================[type definitions]=======================================*/
/*==================[internal function declarations]=========================*/
/*==================[external constants]=====================================*/
/*==================[internal constants]=====================================*/
/*==================[internal data]==========================================*/
/*==================[external function definitions]==========================*/
/*==================[internal function definitions]==========================*/
int main()
{
uart_init();
sei(); // Wird nur gebraucht bei der Interrupt-Version
uart_putc ('f');
/*uart_puts ("Hallo Welt!" CR);*/
while (1);
return 0;
}
/** @} doxygen end group definition */
/*==================[end of file]============================================*/
uart.h:
#include <avr/io.h>
/*==================[macros]=================================================*/
/*==================[type definitions]=======================================*/
/*==================[external function declarations]=========================*/
extern void uart_init();
extern int uart_putc(const uint8_t);
extern uint8_t uart_getc_wait();
extern int uart_getc_nowait();
extern void uart_puts (char *string_data);
/* Wartet, bis die Übertragung fertig ist. */
static inline void uart_flush()
{
while (UCSRB & (1 << UDRIE));
}
/*==================[external constants]=====================================*/
/*==================[external data]==========================================*/
/** @} doxygen end group definition */
#endif /* _UART_H_ */
/*==================[end of file]============================================*/
uart.c:
#include <avr/io.h>
#include <avr/interrupt.h>
#include "uart.h"
#include "fifo.h"
/*==================[macros]=================================================*/
#ifndef F_CPU
/* In neueren Version der WinAVR/Mfile Makefile-Vorlage kann
F_CPU im Makefile definiert werden, eine nochmalige Definition
hier wuerde zu einer Compilerwarnung fuehren. Daher "Schutz" durch
#ifndef/#endif
Dieser "Schutz" kann zu Debugsessions führen, wenn AVRStudio
verwendet wird und dort eine andere, nicht zur Hardware passende
Taktrate eingestellt ist: Dann wird die folgende Definition
nicht verwendet, sondern stattdessen der Defaultwert (8 MHz?)
von AVRStudio - daher Ausgabe einer Warnung falls F_CPU
noch nicht definiert: */
#warning "F_CPU war noch nicht definiert, wird nun nachgeholt mit 8000000"
#define F_CPU 8000000L // Systemtakt in Hz, das L am Ende ist wichtig, NICHT UL verwenden!
#endif
#define BAUD 9600L // Baudrate, das L am Ende ist wichtig, NICHT UL verwenden!
// Berechnungen
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) /* clever runden */
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1))) /* Reale Baudrate */
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000) /* Fehler in Promille */
/*
#if (((BAUD_ERROR) > (10)) || ((BAUD_ERROR) < (-10)))
#error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
#endif
*/
#define BUF_SIZE_IN 0x40 /* FIFO-Buffergröße */
uint8_t in_buffer[BUF_SIZE_IN];
fifo_t in_fifo;
#define BUF_SIZE_OUT 0x40 /* FIFO-Buffergröße */
uint8_t out_buffer[BUF_SIZE_OUT];
fifo_t out_fifo;
/********* FUNKTIONEN ***********/
void uart_init()
{
uint8_t sreg = SREG;
UBRRH = UBRR_VAL >> 8;
UBRRL = UBRR_VAL & 0xFF;
cli(); /* Interrupts kurz deaktivieren */
UCSRB |= (1<<TXCIE) | (1<<TXEN); /* TXCompleteInterrupt u. TX einschalten */
UCSRC |= (1<<URSEL)| (1<<UCSZ1) | (1<<UCSZ0); /* Asynchron 8N1 */
/* Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte) */
do
{
/* UDR auslesen (Wert wird nicht verwendet) */
UDR;
}while (UCSRA & (1 << RXC));
/* Rücksetzen von Receive und Transmit Complete-Flags */
UCSRA = (1 << RXC) | (1 << TXC);
/* Global Interrupt-Flag wieder herstellen */
SREG = sreg;
/* FIFOs für Ein- und Ausgabe initialisieren */
fifo_init (&in_fifo, in_buffer, BUF_SIZE_IN);
fifo_init (&out_fifo, out_buffer, BUF_SIZE_OUT);
}
/* Senden eines Chars */
int uart_putc (const uint8_t data)
{
int ret = fifo_put (&out_fifo, data);
UCSRB |= (1 << UDRIE);
return ret;
}
/**/
int uart_getc_nowait ()
{
return fifo_get_nowait (&in_fifo);
}
/**/
uint8_t uart_getc_wait ()
{
return fifo_get_wait (&in_fifo);
}
/* Senden eines Strings */
void uart_puts (char *string_data)
{
while (*string_data) /* Wiederhole bis im String '\0' erreicht wurde (*s != '\0') */
{
uart_putc (*string_data); /* Gebe ein Zeichen aus*/
string_data++; /* Erhöhe den String um ein Character */
}
}
/*********************** INTERRUPTS ****************************************/
// Empfangene Zeichen werden in die Eingabgs-FIFO gespeichert und warten dort
SIGNAL (SIG_UART_RECV)
{
_inline_fifo_put (&in_fifo, UDR);
}
// Ein Zeichen aus der Ausgabe-FIFO lesen und ausgeben
// Ist das Zeichen fertig ausgegeben, wird ein neuer SIG_UART_DATA-IRQ getriggert
// Ist die FIFO leer, deaktiviert die ISR ihren eigenen IRQ.
SIGNAL (SIG_UART_DATA)
{
if (out_fifo.count > 0)
UDR = _inline_fifo_get (&out_fifo);
else
UCSRB &= ~(1 << UDRIE);
}
/*********************** ENDE INTERRUPTS ***********************************/
/** @} doxygen end group definition */
/*==================[end of file]============================================*/
fifo.h
#ifndef FIFO_H_
#define FIFO_H_
#include <avr/io.h>
#include <avr/interrupt.h>
typedef struct
{
uint8_t volatile count; // # Zeichen im Puffer
uint8_t size; // Puffer-Größe
uint8_t *pread; // Lesezeiger
uint8_t *pwrite; // Schreibzeiger
uint8_t read2end, write2end; // # Zeichen bis zum Überlauf Lese-/Schreibzeiger
} fifo_t;
extern void fifo_init (fifo_t*, uint8_t* buf, const uint8_t size);
extern uint8_t fifo_put (fifo_t*, const uint8_t data);
extern uint8_t fifo_get_wait (fifo_t*);
extern int fifo_get_nowait (fifo_t*);
/* Schreibt das nächste Byte "data" in die FIFO.
* Liefer 1 bei Erfolg und 0, falls die FIFO voll ist. */
static inline uint8_t _inline_fifo_put (fifo_t *f, const uint8_t data)
{
if (f->count >= f->size)
return 0;
uint8_t * pwrite = f->pwrite;
*(pwrite++) = data;
uint8_t write2end = f->write2end;
if (--write2end == 0)
{
write2end = f->size;
pwrite -= write2end;
}
f->write2end = write2end;
f->pwrite = pwrite;
uint8_t sreg = SREG;
cli();
f->count++;
SREG = sreg;
return 1;
}
/* Liefert das nächste Zeichen aus der FIFO. Ob überhaubt ein Zeichen in der FIFO
* ist, muss vorher extra abgeprüft werden */
static inline uint8_t _inline_fifo_get (fifo_t *f)
{
uint8_t *pread = f->pread;
uint8_t data = *(pread++);
uint8_t read2end = f->read2end;
if (--read2end == 0)
{
read2end = f->size;
pread -= read2end;
}
f->pread = pread;
f->read2end = read2end;
uint8_t sreg = SREG;
cli();
f->count--;
SREG = sreg;
return data;
}
#endif /*FIFO_H_*/
fifo.c:
#include "fifo.h"
/* Initialisiert die FIFO, setzt Lese- und Schreibzeiger, etc.
* Die FIFO verwendet den Puffer "buffer", der "size" Bytes sein muss. */
void fifo_init (fifo_t *f, uint8_t *buffer, const uint8_t size)
{
f->count = 0;
f->pread = f->pwrite = buffer;
f->read2end = f->write2end = f->size = size;
}
/* Schreibt das nächste Byte "data" in die FIFO.
* Liefer 1 bei Erfolg und 0, falls die FIFO voll ist. */
uint8_t fifo_put (fifo_t *f, const uint8_t data)
{
return _inline_fifo_put (f, data);
}
/* Liefert das nächste Byte aus der FIFO, bei leerer FIFO wird gewartet,
* bis das nächste Zeichen eintrift. */
uint8_t fifo_get_wait (fifo_t *f)
{
while (!f->count);
return _inline_fifo_get (f);
}
/* Liefert das nächste Byte aus der FIFO als "int" bzw. -1,
* falls die FIFO leer ist. */
int fifo_get_nowait (fifo_t *f)
{
if (!f->count) return -1;
return (int) _inline_fifo_get (f);
}
Hallo,
schreib mal in der main
while (1){
asm("nop");
}
oder setz die Optimierung auf -O0
BTW Variablen die in ISR's benutzt werden sollten imm er volatile declariert werden.
volatile fifo_t out_fifo;
Gruß
Jens
Hubert.G
20.01.2008, 15:10
Eine ISR habe ich nicht.
Was ist das dann in deiner uart.c ?
Ausserdem sicherst du in deinen Routinen das SREG, warum? In C wird das SREG, wenn notwendig, automatisch gesichert. Wenn du es sonst machen willst, solltest du genau wissen was du tust, du kannst dir da sonst einen schönen pffff... einhandeln.
@ McJenso
habe ich gemacht keine Änderung. ;-(
Irgend wo muss mein Kontroller Reset machen, habe auch mit dem AVR-Studio simuliert kein Fehler...
@Hubert.G
Sreg sichere ich nur weil mir RN-Wissen vorschlägt...
habe aus kommentiert ist immer noch dass gleiche..
bin echt verzweifelt... ;-(
Hubert.G
20.01.2008, 20:21
Schreib mal im main anstelle von deinem
while (1);
return 0; so wie ich es schreibe
for(;;){
}
Bei mir läuft es dann.
Hallo,
du hast doch sicher noch irgendwo einen Pin für eine Testled frei. Vielleicht hast du ja auch eh schon ein LED an einem PIN.
Füg mal folgenden Code ein:
ISR(__vector_default){
//Hier die LED einschalten
}
In diese Funktion werden alle Interrupts geleitet, für die es keine andere ISR gibt. Leider kenne ich keine Möglichkeit außer Ausprobieren, wie man den auslösenden Interruptvector herausfindet.
Du könntest auch mal versuchen, die Testled hinter der Endlosschleife einzuschalten. Sollte nicht gehen. Damit würdest du endgültig beweisen, dass das Programm nicht einfach "durchrennt".
Du kannst den Einschaltbefehl für die LED auch immer weiter duch das Programm schieben und schauen, wann sie nicht mehr angeht.
Halte durch, das wird was. :wink:
Gruß
Jens
In diese Funktion werden alle Interrupts geleitet, für die es keine andere ISR gibt. Leider kenne ich keine Möglichkeit außer Ausprobieren, wie man den auslösenden Interruptvector herausfindet.
Ich hab doch oben schon geschrieben, dass der TXComplete-Interrupt aktiviert wird und ja auch ausgelöst wird, wenn der AVR was sendet. Ich würd den halt einfach mal ausschalten und schauen obs dann geht... :-b :-k
@ Pascal, danke!!
;-) jetzt tut es!!!! :-)
nach dem ich wie Pascal gesagt den TXCIE ausgeschaltet habe ging es!
Dass ist super!
Allerdings weis ich nicht warum? Würde mich freuen wenn ihr dass mal erklären könntet...
Vor allem habe ich den Teil aus RN-Wissen!
Das bedeutet dass die Codes überarbeitet werden müssen!
Ich bin voll rein getappt....
Ich danke euch allen!!! Ohne eure Hilfe wäre ich nie dadrauf gekommen...
Grüße
Khan
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.