Ein Fehler:
UBRR0H = ((16000000UL/(38400 * 16L)) >> 8);
UBRR0L = (16000000UL/(38400 * 16L)) - 1;
Die Formel sollte in beiden Fällen bis auf das ">>8" gleich sein
(==>Makro verwenden!). Hat aber eher nichts mit deinem Problem zu tun.
Ansonsten finde ich dein Programm etwas wirr, weil du teilweise
Funktionen von hand implementierst, andererseits aber fertige
Funktionen benutzt bzw. Funktionen verwendest, die nicht in deinem
Quellcode vorkommen (sind die Teil der stdio.h?).
hallo,
ja das programm hab ich ja von menem restlichen programm ausgelagert
deswegen ein bisschen schlampig wollte sehen ob der fehler viel an
meinem restlichen programm liegt aber das war es auch nicht.
aber es wundert mich einfach wieso er den interrupt ein bzw 2 mal
ausführt, beim 2 mal wird der interrupt deaktivert ... wird aber wieder
aktiviert wenn in den puffer geschrieben wird... habe mir auch alle
register angeschaut vor dem interrupt und nachdem er wieder aktiviert
wird .. identisch :(
Also ich sehe da einiges unsauberes im Programm
rout,tin müssen nicht volatile sein
r_in & RMASK solltest du ersetzen durch module Arraygrösse bei 2^n wird
das dann auch ein AND ist aber wesentlich Fehlerunabhängiger
>return(r_in - r_out);
du willst doch mit Ringpuffer arbeiten? Da kann das auch negativ
werden!
In putchar und analog getchar machst du einfach r_out++; sicher
maskierst du noch beim Zugriff aber das ist ...
besonders wenn man damit den Abstand im Ringpuffer bestimmen will.
(r_in - r_out)
Ich würde vorschlagen du räumst erstmal in deinem Programmcode mit
diesen Schlampigkeiten auf.
Der interrupt wird 2x ausgeführt aufgrund der Doppelpufferung.
so da is mal der code so wie ich ihn bei mir hab ohne meiner meinung
nach schlampigkeiten. das mit TX_BUF_MASK & tx_in find ich eig ganz
praktisch :)
das empfangen funktioniert auch einwandfrei nur halt beim senden wird
der interrupt nur 2 mal aufgerufen und dann nie wieder obwohl das
register auf empty steht und der interrupt auch aktiviert ist.
das uart_getc ist zu vergessen benutz es eh nicht geh da genau so über
einen interrupt..
uint8_t tx_buff[TX_BUF_SIZE];
uint8_t tx_in = 0;
uint8_t tx_out = 0;
uint8_t rn_buff[RN_BUF_SIZE];
uint8_t rn_in = 0;
uint8_t rn_out = 0;
/* Initialiesierung von Uart */
void uart_init(void){
// Setzen der Baud Rate
UBRR0H = (BAUD_RATE >> 8);
UBRR0L = BAUD_RATE;
// (Empfänger) | (Sender)
UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);
// ( 8 Bit Befehl )
UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
fdevopen(uart_putc, uart_getc);
}
/* Senden aus dem Puffer */
SIGNAL(SIG_USART_DATA){
if(tx_in != tx_out)
UDR0 = tx_buff[tx_out++ & TX_BUF_MASK];
else
/* Sendebuffer ist leer, UDRE Interrupt deaktivieren */
UCSR0B &= ~(1<<UDRIE0);
}
/* Senden eines Zeichen */
void uart_putc(unsigned char c)
{
//Warten bis platz im Zwischenspeicher frei wird
while( (RN_BUF_MASK - tx_in - tx_out) < 1)
;
tx_buff[TX_BUF_MASK & tx_in++] = c;
UCSR0B |= 1<<UDRIE0;
}
1. du hast 2 volatile zu viel weggenommen
2.(RN_BUF_MASK - tx_in - tx_out)
Wie schon erwähnt du erhöhst unsauber (ohne zu maskieren)
die Zeichen gehen schneller in den Puffer als heraus d.h. z.B.
RN_BUF_MASK=31 tx_in=40 (da du nicht maskierst) txout=2
31-40-2=mit sicherheit <1
Hör mit diesem Schlampigkeiten auf oder wiederhole sie nicht noch wenn
du darauf hingewiesen wirst!
verwirr den armen nicht mit deinem volatile das ist meistens unwichtig.
aber wenn man ne variable volatile macht dann schadet es auch nicht,
kostet nur ein bisschen mehr rechenzeit. manche compiler erkennen sogar
selbst wann eine variable volatile sein muss und wann nicht. also zu
viele volatiles schaden nicht, verlängern nur die ausführzeit des
programms
31-40-2=mit sicherheit <1
wenn das kleiner 1 is soll er solange warten bis es >1 dann weis er ja
ob platz frei is oder nicht
ah ich bin schon ganz verwirrt kannst du das den nicht kurz hincoden
wie du es meinst ... steht grad total aufm schlauch
tx_out++ & TX_BUF_MASK
Müsste IMHO auch eher "++tx_out & TX_BUF_MASK" heissen.
(Der Übersicht wegen mache ich das gerne in zwei Zeilen.)
>RN_BUF_MASK - tx_in - tx_out
Dabei geht es doch "nur" darum, festzustellen, ob noch mindestens 1
Byte in den Puffer passt, oder?
"while (tx_in == tx_out);" sollte da sinnvoller sein, da die beiden
Variablen sowieo dauernd mit Puffergrösse-1 verundet werden.
Wolfram hat da schon ein schönes Rechenbeispiel geliefert.
> 31-40-2=mit sicherheit <1>> wenn das kleiner 1 is soll er solange warten bis es >1 dann weis er> ja ob platz frei is oder nicht
Warum soll er da warten?
Wenn der Puffer 40 Zeichen gross ist, mit 31 Zeichen gefüllt
wurde und erst 2 gesendet wurden, dann ist noch jede Menge
Platz im Puffer.
Schnapp dir Papier und Bleistift, mal dir einen Puffer auf
tx_buf
+---+---+---+---+---+---+--- ... ---+---+---+
| | | | | | | | | |
+---+---+---+---+---+---+--- ... ---+---+---+
tx_in
+-----+
| |
+-----+
tx_out
+-----+
| |
+-----+
und spiel ein paar Fälle durch: Du spielst CPU und arbeitest
dein Programm ab. Du darfst nur die Aktionen ausführen, die
dir dein Program ansagt. Wenn dein Programm einen Vergleich
vorschreibt, dann schaust du auf den Zettel, liest die entsprechenden
Variablenwerte an und machst den Vergleich. Wenn dein Programm
eine Zuweisung vorschreibt, dann korrigierst du am Zettel die
entsprechenden Werte (daher Bleistift und nicht Kugelschreiber).
Alles ganz genauso wie es auch dein µC macht.
Und mach den Puffer nicht zu gross. Eine Puffergröße von
4 Byte ist für das Testen am Papier mehr als ausreichend.
Es geht nicht um den Puffer an sich, sondern es geht darum
dass du mal siehst, was dein Programm eigentlich macht.
Du musst dir mal selbst ein paar Definitionen zurechtlegen.
zb
tx_in Index im Ringpuffer an dem das nächste zu schreibende
Zeichen abgelegt wird
tx_out Index im Ringpuffer welches das zuletzt gesendete Zeichen
enthält
/* Senden eines Zeichen */
void uart_putc(unsigned char c)
{
//Warten bis platz im Zwischenspeicher frei wird
while( tx_in == tx_out )
;
tx_buff[ tx_in ] = c;
tx_in = ( tx_in + 1 ) % TX_BUF_MASK;
UCSR0B |= 1<<UDRIE0;
}
Jetzt ist sichergestellt, dass tx_in nur Werte im Bereich
0 bis TX_BUF_MASK enthalten kann.
du musst dafür sorgen, dass tx_in und tx_out niemals den
erlaubten Wertebereich verlassen. Alles andere ist ein
sicherer Weg ins Chaos.
Dann musst du dir natuerlich ueberlegen, wie du rbuflen()
formulierst. Spiels einfach mal mit einer gedachten Buffe-
groesse von 8 Bytes durch. tx_in kann kleiner als tx_out
sein. D.h. aber nicht, dass der Buffer voll ist. Das heist
nur, dass wieder am Anfang dieses Ringbuffers eingefügt
wurde, während noch ein paar Zeichen aufs Senden warten.
Der Buffer ist nur dann voll, wenn tx_in == tx_out
Zumindest solltest du deinen Code dahin hintrimmen, dass
diese Vorgabe immer erfüllt ist
wenn tx_in != tx_out es gibt Platz im Buffer
wenn tx_in == tx_out es gibt keinen Platz im Buffer
Aber das wichtigste ist: Du musst tx_in und tx_out unter
allen Umständen im erlaubten Wertebereich halten.
Ooops. Der letzte Teil haette es nicht mehr ins Forum machen
sollen. Bitte alles nach 'Du musst dir mal selbst ein paar
Definitionen zurecht legen' bitte ignorieren. Ich hab keine
Ahnung ob der Code so jetzt noch zum Rest passt.
> wenn tx_in != tx_out es gibt Platz im Buffer> wenn tx_in == tx_out es gibt keinen Platz im Buffer
Da gibt es aber Start-Probleme: Im ersten Moment sind tx_in und tx_out
gleich (== 0 oder je nach Initialisierung).
Besser ist es, entweder die freien Plätze im Puffer oder die zu
sendenden Bytes zu zählen. Ist die Anzahl der freien Pufferplätze = 0,
ist er voll...
Ansonsten sollte man sich eine Funktion (oder Makro) ausdenken, das die
Anzahl der freien Speicherplätze errechnet:
l = ((tx_in>ty_out) ? (tx_in-tx_out) : (tx_out-tx_in))) & TX_BUF_MASK;
(könnte so funktionieren... ausm Ärmel geschüttelt).
Ist l<RN_BUF_MASK, dann ist (sollte noch) noch Platz vorhanden
(sein)...
ich weis jetzt nicht ob ich meinen code anders sehe als ihr aber meiner
meinung is es so das durch
tx_buff[TX_BUF_MASK & tx_in++] = c;
tx_in immer hochgezzählt wird und somit die gesamtanzahl der bytes die
in den Puffer geschrieben worden sind ausgelesen wird
tx_out wird immer hochgezählt wenn ein byte rausgeschrieben wurde
tx_in: 60
tx_out: 40
=> 20 Byte im puffer
puffer: 30
puffer - (tx_in - tx_out) => 10
=> 10 platz frei
=> fehler im porg das die klammer fählt
=>
//warte bedingung
while( (TX_BUF_MASK - (tx_in - tx_out)) < 1)
;
sehe ich das jetzt so richtig von meinem eigen prog oder sieht ihr das
anders
>> wenn tx_in != tx_out es gibt Platz im Buffer>> wenn tx_in == tx_out es gibt keinen Platz im Buffer> Da gibt es aber Start-Probleme: Im ersten Moment sind tx_in und> tx_out gleich (== 0 oder je nach Initialisierung).
Kommt auf die Initialisierung an. Wenn ich mit tx_out = TX_BUF_MASK
loslege, stimmt obiges.
Ich wollte das auch mal so aus dem Ärmel geschüttelt, hab aber
dann schnell gemerkt, dass ich das nicht hier direkt programmieren
kann. Musste man aufmalen und mal ein Testprogramm auf
nem PC machen (damit man auch mit einem Debugger vernuenftig
ran kommt).
> tx_in immer hochgezzählt wird und somit die gesamtanzahl der> bytes die in den Puffer geschrieben worden sind ausgelesen wird
Und irgendwann ist tx_in so gross (255), dass beim nächsten
Addieren von 1, das Ding zu 0 wird. Dann ist tx_in plötzlich kleiner
als tx_out. Was passiert dann?
Wie gesagt: am Zettel aufmalen, mit Papier und Bleistift
durchspielen.
aber wie gesgat ich hab mehr das problem das er den interrtupt nicht
wieder auslöst er kommt also gar nich wieder da rein
/* Senden aus dem Puffer */
SIGNAL(SIG_USART_DATA){
if(tx_in != tx_out)
UDR0 = tx_buff[tx_out++ & TX_BUF_MASK];
else
/* Sendebuffer ist leer, UDRE Interrupt deaktivieren */
UCSR0B &= ~(1<<UDRIE0);
}
>tx_in immer hochgezzählt wird und somit die gesamtanzahl der bytes >die
in den Puffer geschrieben worden sind ausgelesen wird
>tx_out wird immer hochgezählt wenn ein byte rausgeschrieben wurde
Gute Einwand, wenn tx_in unendlich groß werden könnte. Irgenwann gibt
es aber einen Überlauf, und dann ist tx_in definitiv (für eine gewisse
Zeit) kleiner als tx_out.
Ich meinte mit "aus dem Ärmel gschüttelt" die Berechnung (hab noch
nicht sooo oft mit "= ? :" gearbeitet).
while( (RN_BUF_MASK - tx_in - tx_out) < 1);
Hast du schonmal daüber nachgedacht was passiert wenn txin über läuft
31-0-255 was wird das für ein Datentyp? Ich habe da irgendwie leichte
Probleme. Also wie war das Es wird in den grössten verwendeten Datentyp
konvertiert. defines sind standardmäßig ohne Kennzeichnung int ?
Das heisst wir rechnen mit int 31-0-255=-224
Warum läßt du die Variable durchlaufen und hältst nicht in ihr den
direkten Pufferindex? Das würde auch die Fehlersuche sehr erleichtern.
> Ich meinte mit "aus dem Ärmel gschüttelt" die Berechnung (hab> noch nicht sooo oft mit "= ? :" gearbeitet).
Sieht doch gut aus.
Ich hab mich auch lange gegen ?: gewehrt. Solange man das
nicht übertreibt, ist das aber echt praktisch. zb.
in Argumentlisten:
foo( i > j ? 3 : 1 );
Wenn man sich dran gewöhnt hat, liest sich das genauso leicht,
wie
if( i > j )
foo( 3 );
else
foo( 1 );
Eventuell noch ein paar Klammern um die Bedingung, damit
sie etwas rausleuchtet, und 'passt schon'.
Nur rate ich davon ab, sowas mit komplexeren Bedingung
zu machen. Das wird seeeeehr schnell unübersichtlich.
also ich hab grad rumgespielt
das problem tritt durch das deaktivern und aktivern des interrupts
auf..
wenn ich ein belibiges zeichen sende und den interrupt laufen lasse
geht das ohne probleme sobald ich ihn aber deaktiver und wieder
aktivier wird er nicht mehr ausgeführt .. an was kann das liegen?
SIGNAL(SIG_USART_DATA){
if(tx_in != tx_out){
tx_out = ( tx_out + 1 ) & TX_BUF_MASK;
UDR0 = tx_buff[tx_out];
}else
UDR0 = '.';
//UCSR0B &= ~(1<<UDRIE0);
}