Archiv verlassen und diese Seite im Standarddesign anzeigen : Programm_Anpassungen
helmut_w
24.07.2007, 12:18
Hi!
Da unser Robo z.Zt. zwangs-inaktiv ist, habe ich mir ein wenig Eure tollen und sehr gut
dokumentierten *.h's und *.c's angeschaut; ich kann dabei noch sehr viel in Sachen C,
Asm und AVR lernen!!!
Dabei ist mir das eine oder andere aufgefallen. (Bitte nicht als Kritik verstehen, denn
das soll und will ein Newby wie ich (leider noch bin!:( gar nicht!
Bei der IR-Übertragung ist mir aufgefallen, dass der Sender und auch der Empfänger zwar
immer wieder eingeschaltet wird, jedoch NIE aus! (in print.c und uart.c)
Anpassungsvorschlag: UCSRB = 0x00; // Sender und Empfaenger ausschalten
Beim Senden vom Asuro aus gibt es ähnliche Programme:
void SerWrite (unsigned char *data, unsigned char length)
void UartPutc (unsigned char zeichen) mit void SerPrint (unsigned char *data)
Man könnte mit den "Sahnehäubchen" aus beiden ein Programm basteln:
z.Bsp.
aus*********
void UartPutc (unsigned char zeichen)
{
UCSRB = 0x08; // enable transmitter
UCSRA |= 0x40; // clear transmitter flag
while (!(UCSRA & 0x20)) // wait for empty transmit buffer
;
UDR = zeichen;
while (!(UCSRA & 0x40)) // Wait for transmit complete flag (TXC)
;
}
mit+++++++++
void SerPrint (unsigned char *data)
{
unsigned char i = 0;
while (data [i] != 0x00)
UartPutc (data [i++]);
}
und-------------
void SerWrite (unsigned char *data, unsigned char length)
{
unsigned char i = 0;
UCSRB = 0x08; // Sender einschalten
while (length > 0) // so lange noch Daten da sind
{
if (UCSRA & 0x20)
{ // warten, bis der Sendebuffer leer ist
UDR = data[i++];
length --;
}
}
while (!(UCSRA & 0x40)) // abwarten, bis das letzte Zeichen
; // uebertragen wurde.
for (i = 0; i < 0xFE; i++) // warten auf irgendwas; keiner weiss
for (length = 0; length < 0xFE; length++); // wofuer =>> na, dann weglassen!:))
}
Prog_neu------------
void SerWrite_SerPrint_NEU (unsigned char *data, unsigned char length)
{
unsigned char i = 0;
UCSRB = 0x08; // Sender einschalten
// enable transmitter
UCSRA |= 0x40; // 'clear' transmitter flag
// TXC-flag setzen
// (TXC = transmit complete flag)
while (length && data[i]) // so lange noch Daten da sind *)
{
if (UCSRA & 0x20) // wait for empty transmit buffer
{ // warten, bis der Sendebuffer leer ist
UDR = data[i++];
length --;
}
}
while (!(UCSRA & 0x40)) // abwarten, bis das letzte Zeichen
; // uebertragen wurde.
// Wait for transmit complete flag (TXC)
UCSRB = 0x00; // Sender ausschalten
// disable transmitter
}
------------
*) 2 Fliegen mit einer Klappe schlagen!:))
SerWrite_SerPrint_NEU () funktioniert (besser: SOLLTE!:)
- mit Null-terminierten String data[] und/oder
- mit einer Längenangabe (auch ohne 'End-Null'):
Im ersten Fall muss man (leider als Schönheitsfehler!) als Länge einfach "0xff"
oder eine Zahl angeben, die größer/gleich der tatsächlichen Länge ist,
im zweiten die korrekte Länge des Strings!
Zum Prg.-Namen machen wir einen Wettbewerb!:-)
Prog. leider noch nicht getestet!
********************
Beim Prog. IR-Empfangen versuche ich demnächst 'mal, die Fehlererkennung mit einzubauen.
Bis bald und
cu Helmut
damaltor
24.07.2007, 18:16
hmm.. klingt gar nicht schlecht, aber wenn man alles getrennt lässt bleibt man abwärtskompatibel. vielleicht sendest du mal ne nachricht an waste, der beschäftigt sich mit der lib, vielleicht gibt das ne neuaufnahme...
Sternthaler
24.07.2007, 18:53
Hallo zusammen,
die Warteschleife am Ende der SerWrite()-Funktion ist tatsächlich sehr merkwürdig.
Als einzigen Grund für das Ding kann ich mir nur vorstellen, dass eine Syncronisation mit einem Empfänger besser funktioniert.
Wenn man permanent Daten sendet, dann kann es passieren, dass die Start-Bits in den Daten nicht mehr zum richtigen Zeitpunkt gefunden werden. Macht man ab und zu eine Pause, dann schaffen es die Empfänger wieder das nächste Start-Bit korrekt zu erkennen. Ist mir schon passiert, als ich permanet Daten der Liniensensoren gesendet habe und 'natürlich' auch diese 'Zeitverschwendung' ausgebaut hatte.
Ist waste tatsächlich der richtige Ansprechpartner? Ich würde eher m.a.r.v.i.n sehen. (Oder ich?, OK ich sehe mir das heute Abend mal in Ruhe an, und werden es dann erst hier zur Begutachtung abgeben.)
damaltor
24.07.2007, 21:40
na ich denke ihr seid alle richtig =) nur ich halt nich... ;)
an sich finde ich die idee nicht schlecht, evtl wirds ja was
Sternthaler
25.07.2007, 00:21
So, an alle die richtig und nicht richtig sind ;-) P.S.: damaltor ist immer richtig!
Ich habe den Vorschlag für SerWrite_SerPrint_NEU() mal so umgeschrieben dass ich in lesen kann. (Entspricht jetzt eher den Original-Codestellen zu Vergleichszwecken)
void SerWrite_SerPrint_NEU (unsigned char *data, unsigned char length)
{
unsigned char i = 0;
UCSRB = 0x08; // enable transmitter
UCSRA |= 0x40; // clear transmitter flag
while (length && data[i]) // so lange noch Daten da sind *)
{
while (!(UCSRA & 0x20)) // wait for empty transmit buffer
;
UDR = data[i++];
length --;
}
while (!(UCSRA & 0x40)) // Wait for transmit complete flag (TXC)
;
UCSRB = 0x00; // disable transmitter
}
So sieht das ganze ja recht gut aus.
Es gibt aber folgendes zu bedenken:
1: Ein einzelnes Char-Zeichen ist nur noch umständlich zu senden.
--> charVariable [0] = 'x';
--> SerWrite_SerPrint_NEU (charVariable, 1);
anstatt:
--> UartPutc ('x');
2: gravierender: Ich kann nicht mehr 'alle' Daten einschliesslich 0x00 senden.
Ein Datenarray mit 0x00 als Inhalt an einer Stelle, würde genau dieses Zeichen zum Abbruch der Funktion führen. Die "while (length && data[i])"-Schleife wird ja genau hier abbrechen, ohne dieses verflixte 0x00 gesendet zu haben.
- Somit hat SerWrite() seine Daseinsberechtigung.
- SerPrint() ist fuer die C-String-Sender.
- Und UartPutc() ist nun mal für LowLevel.
Ich glaube also, dass es keine so gute Idee wäre einen Wettbewerb für den Funktionsnamen zu beginnen.
Auf alle Fälle finde ich es klasse, dass du dich so intensiv mit den einzelnen Funktionen und möglichen Sahnehäubchen, äh Optimierungen, beschäftigst. Sonst ist bestimmt nämlich noch niemandem aufgefallen, dass man Energie sparen kann durch das Ausschalten des Senders. Akku und Umwelt werden es danken. -> Wird auf den Weg in die LIB gebracht.
Was ich aber bestehen lasse, ist diese merkwürdige Warteschleife zum Schluss. Da habe ich ehrlich gesagt ein bisschen Bammel vor die auszubauen. (Beim DLR werden die sich da irgendetwas gedacht haben um so ein Rätsel einzubauen.)
damaltor
25.07.2007, 13:52
... ich seh das mal als kompliment =)
aber warum zur hölle sollte ich ein 0x00 senden wollen? =)
void SerWrite_SerPrint_NEU (unsigned char *data, unsigned char length)
Hallo Sternthaler,
könntest Du in der neuen Version den Längenparameter rauswerfen? ](*,)
Buchstaben zählen können Prozessoren besser als der Mensch.
Beste Grüße O:) ,
stochri
m.a.r.v.i.n
25.07.2007, 20:56
Hi,
aber warum zur hölle sollte ich ein 0x00 senden wollen? =)
Wenn man Binärdaten senden will, kommt 0x00 durchaus vor und die Längenangabe in SerWrite braucht man dann natürlich ebenso.
Ganz so einfach geht es also nicht.
Vielleicht vereint man print.c und uart.c auf folgende Weise, indem man SerWrite umschreibt und SerPrint durch ein Define ersetzt:
void SerWrite (unsigned char *data, unsigned char length)
{
if (length)
{
do {
uart_putc(*data++);
}
while (length--);
}
else
{
while (*data)
uart_putc(*data++);
}
}
#define SerPrint SerWrite(unsigned char *data, 0);
Sternthaler
25.07.2007, 23:15
@damaltor
Klar, ist so gemeint. Allerdings wirft dich die Frage nach der Hölle nun etwas zurück ;-) Siehe Antwort von m.a.r.v.i.n
@stochri
Da ist noch nichts eingebaut.
Mit dem Übernehmen in die LIB hatte ich nur im Sinn den Sender auch wieder auszuschalten. In meinem Beitrag hatte ich (wahrscheinlich durch blah, blah, blah verstümmelt) eigendlich für die Daseinsberechtigung aller 3 Funktions-Varianten zum senden plädiert.
Aber m.a.r.v.i.n hat wohl den Nagel auf den Kopf getroffen, und eine perfekte Lösung gefunden.
Kleine Änderung beim define:
#define SerPrint(data) SerWrite(unsigned char *data, 0);
Oder muss das "data" bei einem define auch mit Typeangabe, *-chen oder sonstigem sein?
Auch noch eine weitere Frage zu dem Code, bei der ich absolut unsicher bin was da eigendlich passieren wird.
- Ich mache ne Char-Array-Variable á la "char infos [10];"
- Daten da rein mit "strcpy (infos, "Wichtig");"
- Nun der Aufruf über SerPrint (infos) an SerWrite(infos, 0)
- In SerWrite wird mit "*data++" das zu sendende Zeichen ausgewählt UND der Zeiger auf den übergeben Datenbereich mit ++ erhöht.
Meine Frage ist:
Wenn die Funktion beendet wird, ist dann der Zeiger/Adresse in infos immer noch an der Stelle im Speicher an der ich 10 Byte speichern darf, oder wurde dieser Zeiger/Adresse nun durch das ++ auch beim Aufrufer geändert?
Wenn das der Fall wäre, dann dürfte ich als Aufrufer ja nun nicht mehr davon ausgehen, dass mir der Speicherbereich ab infos mit 10 Byte gehört.
Im Original-Code ist das Adressieren der Daten in infos mit einer eigenen Variablen gelöst: "data[i++]"
damaltor
26.07.2007, 21:41
keine sorge:
du übergibst ja das array (welches technisch gesehen eingentlich nur ein zeiger auf dass erste element ist). dann wird damit gearbeitet, der zeicher wird etwas hin-und hergeschubst usw.
sowie du aber wieder mit dem namen des arrays arbeitest, hat sich das problem erledigt: der NAME des arrays zeigt auf das erste element. grundsätzlich. und wenn innerhalb einer funktion die adresse, auf die der zeiger zeigt, verändert wird, ist das in der aufrufenden funktion nicht geändert. sowie die fnktion verlassen wird, zegt der name wieder auf das erste element.
Sternthaler
27.07.2007, 02:23
Hört sich gut an.
Ich habe immer Probleme, wenn es um 'call bei reference' und 'call by value' geht (bekomme ich nur durch try and error raus). Bei dem einen ändert die aufgerufene Funktion, und der Aufrufer muss leiden, oder freut sich halt über den geänderten Wert. Hier würde ich als Aufrufer die Krise kriegen.
m.a.r.v.i.n
27.07.2007, 11:32
Hi,
#define SerPrint(data) SerWrite(unsigned char *data, 0);
Oder muss das "data" bei einem define auch mit Typeangabe, *-chen oder sonstigem sein?
Stimmt natürlich einmal unsigned char * ist genug. :oops:
Was die Warteschleife am Ende der SerWrite Funktion betrifft: Mir war so, als ob es dann mit anschließendem Aufruf von SerRead Probleme gab, wenn man die Warteschleife weg ließ. Hier im Forum gab es auch mal einen Thread dazu, ich finde den bloß nicht mehr.
damaltor
29.07.2007, 20:06
doch, da kann ich mich auch drann erinnern.
im atmega ist nur ein einziges register (USD) vorhanden, welches die daten hält die gesendet oder empfangen wurden.
wenn man mit serwrite was senden will, muss man nur den wert in das register schieben, und es wird gesendet. da jedoch 2400 baud sehr langsam ist im vergleich zum systemtakt des asuro mit 8000000 hz, passiert es wenn man serread aufruft, dass man versucht, das register USD, in das man gerade geschrieben hat und dessen daten noch nicht abgeschickt wurden, wieder auszulesen. dadurch wird erstens ein frame error ausgelöst, was eine unterbrechung des sendens des aktuellen zeichens zur folge hat, und zweitens werden die daten im USD zerstört.
die warteschleife ist also nur dazu da, um sicherzustellen, dass das USD wieder leer ist, bzw das der letzte sendevorgang sicher beendet ist.
edit: das lässt sich übrigens viel eleganter lösen: es gibt im UART-STATUS-register (UST?? weiss nimmer) ein bit das anzeigtz ob das datenregister leer ist...
Sternthaler
30.07.2007, 02:09
@m.a.r.v.i.n & @damaltor
hmmm, ist ja interessant, das ihr auch schon Thread's vermisst. Ich habe zu Anfang meiner Besuche im Forum so alle Beiträge per Bockmark im Browser festgehalten. Es gibt da mindestens einen, den es definitiv nicht mehr gibt. Der Titel war "Was macht Ihr eigentlich beruflich, was studiert Ihr ?" und war unter Beitragsnummer 12654 zu finden.
Zur Warteschleife:
damaltor führt an, dass man ja auch über ein Register prüfen kann, ob das zu sendende Byte schon weg ist.
Aber genau das wird ja noch VOR der merkwürdigen doppelten for()-Loop gemacht. (Ist im Register UCSRA das Bit 6: TXC 'USART Transmit Complete')
while (!(UCSRA & 0x40)) // abwarten, bis das letzte Zeichen
; // uebertragen wurde.
for (i = 0; i < 0xFE; i++) // warten auf irgendwas; keiner weiss
for (length = 0; length < 0xFE; length++); // wofuer
Das UDR-Register ist im AVR doppelt angelegt. Es hat nur auf der Sende- und Empfangsseite den gleichen Namen, sogar intern die gleiche Adresse. Das wird im ATmega8-Handbuch auf Seite 150 recht gut erklärt.
Das zu sendende Byte kann somit nicht von einem empfangenen Byte übermangelt werden. Sonst könnte ein "Full Duplex Operation (Independent Serial Receive and Transmit Registers)" nicht funktionieren (Seite 130 im Handbuch auf der Asuro-CD)
Tut mir Leid, aber im Moment stehe ich noch auf meiner Vermutung, mit den Synchronisationsproblemen.
damaltor
30.07.2007, 09:13
das bit meinte ich eigentlich nicht... es gibt ein bit welches einfach nur anzeigt ob udr empty ist.
ich habe nicht im datenbaltt nachgesehen, sondern nur in diesem buch nachgesehen:
http://www.amazon.de/Mikrocomputertechnik-Controllern-AVR-RISC-Familie-Programmierung-Assembler/dp/3486580167/ref=sr_1_1/302-5400998-0560004?ie=UTF8&s=books&qid=1185779381&sr=8-1
ich war recht überzeugt davon dass sowas da drin stand, dass sich ein schreib- und ein innerhalb der sendezeit liegender lesevorgang gegenseitig behindern. egal, werde nochmal nachsehen, das full-duplex ist ein sehr gutes argument =) allerdings denke ich es wäre doch vernünftiger, wenn man das register, da es ohnehin doppelt vorhanden ist, auch einzeln ansprechen kann... so könnte man evtl noch einen wert zurücklesen und schnell korrigieren. (sofern TXE noch abgeschaltet ist)
was machst du eigentlich un diese zeit schon im netz?? =)
Sternthaler
30.07.2007, 09:38
Heute bin ich mal dran mit einem freundlichen
hnngggrrr
Der Dachdecker hatte sich für 07:30 angekündigt. Und was macht man im Urlaub, wenn man schon den ersten Kaffee auf hat?
Also mal ein einmaliges: 'Guten Morgen' von mir.
Jetzt bin ich aber gespannt, ob du in dem Buch noch genau Infos zu dem UDR und 'Beiwerk' findest. Wäre bestimmt erhellend, wenn man dann die blöde for()-Konstruktion mal richtig verstehen könnte. (Oder doch löschen?)
Sternthaler
31.07.2007, 01:29
Und endlich wieder meine Zeit.
@m.a.r.v.i.n & @damaltor
Da habe ich doch den 'verlorenen Sohn' wiedergefunden.
Arexx-Henk hat im Beitrag Asuros SerWrite(..) - Verständnisproblem (https://www.roboternetz.de/phpBB2/viewtopic.php?p=182250#182250) berichtet, was da fehlschlägt, wenn man, wie m.a.r.v.i.n schon sagte, nach dem Senden gleich Empfangen möchte.
Es bleibt also tatsächlich die Suche nach dem von damaltor vermissten Bit im AVR. Aber da hat Arexx-Henk in seinem Beitrag auch schon eine Lösung mitgeliefert.
damaltor
31.07.2007, 12:24
so, gefunden:
auf seite 154 im datenblatt wird beschrieben, dass im register UCSRA (Usart Control ans Status) das bit 5 (UDRE, Usart Data Register Empty) immer dann eine eins gibt, wenn das datenregister leer ist UND der empfänger bereit zum empfang neuer daten ist. könnte man damit nicht etwas machen?
helmut_w
31.07.2007, 19:34
Hallo zusammen!
Arexx-Henk meinte in " Asuros SerWrite(..) - Verständnisproblem":
....
Vorbild:
- die Asuro sendet einige Daten mittels den
SerWrite() Funktion
- die Asuro schaltet direkt um nach empfangen mittels den
SerRead() Funktion
ohne diesen Warteschleiffe in die SerWrite() Funktion werden
die letzten drei Karakter vom transmitter nicht mehr
ausgestrahlt.
Warum nicht?
Guck mal in die SerRead() Funktion.
Dort steht u.a.
UCSRB = 0x10; //enable receiver
Mit diesen Kode wird die receiver eingeschaltet ABER
damit wird auch die transmitter direkt AUSgeschaltet.
....
Leider hat Henk _nicht_überall_ Recht! (Mit den 3 letzten Sätzen schon!:)) )
Da könnte man (_etwas_besser_!:)) ) schreiben: "UCSRB |= 0x10; //enable receiver"
... und zum Ausschalten: "UCSRB &= ~0x10; //disable receiver"
Prog.-Teil aus "SerWrite()":
....
}
while (!(UCSRA & 0x40)) // abwarten, bis das _letzte_Zeichen_
; // uebertragen wurde.
// Wait for transmit complete flag (TXC)
// Bis hierher wurde ALLES uebertragen! *************************************
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
for (i = 0; i < 0xFE; i++) // warten auf irgendwas; keiner weiss
for (length = 0; length < 0xFE; length++); // wofuer
}
.....
Was soll da bitte noch übertragen werden, wenn's schon fertig ist??
Und
" if (UCSRA & 0x20) // wait for empty transmit buffer "
===>> "0x20" ist "bit 5"!
cu Helmut
Sternthaler
31.07.2007, 20:07
Hallo zusammen
genau so wie Arexx-Henk in seinem Beitrag schreibt, sollte man es machen.
Leider würde es nicht ausreichen nur auf das UDRE-Bit zu schauen, da das Senden im URART 2-Stufig erfolgt.
1 UDR füllen vom Programm
2 AVR kopiert UDR in internes Schieberegister --> UDR ist wieder leer
3 UDR füllen vom Programm
4 AVR kopiert NICHT
5 AVR baut Transport-Frame um interne Schieberegisterdaten
6 AVR sendet Frame
7 Und weiter bei 2
Wenn also 2 Byte zu senden sind, dann kann man die im Grunde direkt hintereinander in das UDR-Register schreiben. (Natürlich sollte man das nicht so machen)
ABER, das UDR-Register ist immer viel schneller leer als man so denkt.
Genau dies hatte Arexx-Henk beschrieben.
Hier noch der Code (als Ausschnitt) von ihm:
// warte bis UDR und Schieberegister leer sind
while ( ! ( UCSRA | (1<<TXC)))
;
// reset handmassig den TXC bit durch schreiben einen '1' !
UCSRA |= (1<<TXC);
Aber eigendlich ist bis auf das zurücksetzen des TXC-Bits (auf 1 setzen=reset) schon alles in der LIB. Und trotzdem kommt die for()-Schleife noch hinterher.
In der LIB wird das "while ( ! ( UCSRA | (1<<TXC)))" nur mit 0x40 anstatt TXC abgefragt.
Was also ist mit der for()-Schleife?
Wegen der Bits im USART-Register hier mal eine Zusammenfassung:
Bit 7: RXC: USART Receive Complete
Bit 6: TXC: USART Transmit Complete
Bit 5: UDRE: USART Data Register Empty
Bit 4: FE: Frame Error
Bit 3: DOR: Data Overrun
Bit 2: PE: Parity Error
Bit 1: U2X: Double the USART transmition speed
Bit 0: MPCM: Multi-Processor Communication Mode
Zu Bit 6: TXC steht folgendes auf Seite 151:
This Flag ist set when the entire Frame in the Transmit Shift Register has been shifted out and there are no new data ... in the .. UDR. The TXC-Bit is automaticlly cleared when a transmit complete interrupt is executed, or it can be cleared by writing a one to the bit.
Somit scheint also tatsächlich nur das von Arexx-Henk angegebene clear-Bit (setzen auf 1) zu fehlen, so dass die Abfrage mit dem "while ( ! ( UCSRA | (1<<TXC)))" überhaupt erst funktionieren kann im nächsten Durchlauf.
Man sollte somit überlegen, ob man diese Abfrage nicht in die SerWRITE-Funktion verlegt VOR dem Umschalten auf Sendebetrieb.
helmut_w
01.08.2007, 11:39
Hallöchen!
Zuerst - TOP 1: Verschiedene Versionen der ATmega8(L)-Beschreibung von Atmel
Beim ADC ist mir aufgefallen, dass eine Atmel-Beschreibung bei der U-Messung der
Akku-/Batt.-Spg. 8 bit breit sein soll, ich aber einen echten 10 bit-Wert erhielt.
Dann nachgeguckt: auf meiner CD-(Kopie): Rev. 2486M-AVR-12/03
Auf einem schon etwas früher geholten PDF-File: 2486Q-AVR-10/06
(Steht unten auf der ersten Seite!)
Vielleicht gibt es noch 'ne neuere Version! (Da ich auf dem Land, also in der DFÜ-
Diaspora lebe, wäre es nett, wenn ein ADSL-Kollege sich bei Atmel schlau machen könnte!)
TOP 2: Aus der Beschreibung von Atmel:
C Code Example(1)
void USART_Transmit( unsigned char data )
{
/* Wait for empty transmit buffer */
while ( !( UCSRA & (1<<UDRE)) )
;
/* Put data into buffer, sends the data */
UDR = data;
}
[Note: 1. See "About Code Examples" on page 8.]
The function simply waits for the transmit buffer to be empty by checking the UDRE
Flag, before loading it with new data to be transmitted.
If the Data Register Empty Interrupt
is utilized, the interrupt routine writes the data into the buffer.
(Page 140)
------------------------
* Bit 6 - TXC: USART Transmit Complete
This flag bit is set when the entire frame in the Transmit Shift Register has been shifted
out and there are no new data currently present in the transmit buffer (UDR). The TXC
Flag bit is automatically cleared when a transmit complete interrupt is executed, or it can
be cleared by writing a one to its bit location. The TXC Flag can generate a Transmit
Complete interrupt (see description of the TXCIE bit).
* Bit 5 - UDRE: USART Data Register Empty
The UDRE Flag indicates if the transmit buffer (UDR) is ready to receive new data. If
UDRE is one, the buffer is empty, and therefore ready to be written. The UDRE Flag can
generate a Data Register Empty interrupt (see description of the UDRIE bit).
UDRE is set after a reset to indicate that the Transmitter is ready.
(Page 154)
------------------------
<table><tr><td>Bit</td><td>7</td><td>6</td><td>5</td><td>4</td><td>3</td><td>2</td><td>1</td>
<td>0</td><td></td></tr>
<tr><td></td><td>RXC</td><td>TXC</td><td>UDRE</td><td>FE</td><td>DOR</td><td>PE</td>
<td>U2X</td><td>MPCM</td><td>UCSRA</td></tr>
<tr><td>Read/Write </td><td>R</td><td>R/W</td><td>R</td><td>R</td><td>R</td><td>R</td>
<td>R/W</td><td>R/W</td><td></td></tr>
<tr><td>Initial Value </td><td>0</td><td>0</td><td>1</td><td>0</td><td>0</td>
<td>0</td><td>0</td><td>0</td><td></td></tr></table>
(wenn obige HTML-Tabelle nicht funktionieren:
Bit 7 6 5 4 3 2 1 0
RXC TXC UDRE FE DOR PE U2X MPCM UCSRA
Read/Write R R/W R R R R R/W R/W
Initial Value 0 0 1 0 0 0 0 0)
-----------------
Zu * Bit 6 - TXC: USART Transmit Complete -> 1. Satz ist eindeutig!
Das mit dem "cleared" ist es leider nicht, da 'ne "1" so viel wie "gelöscht" bedeutet!
Das Bsp. ganz oben von Atmel zeigt, dass "wir" es hier schon richtig machen! !:))
"or it can be cleared by writing a one to its bit location." machen wir ja auch am Anfang!
(UCSRA=UCSRA | TXC; // clear transmitter flag )
cu Helmut
Sternthaler
02.08.2007, 00:16
Hallo helmut_w,
hast du auch manchmal das Gefühl eines "deja vu"? ;-)
Zum TXC-Flag wird auch noch auf Seite 139, im Kapietel "Transmitter Flags and
Interrupts", geschrieben:
The Transmit Complete (TXC) Flag bit is set one when the entire frame in the transmit
Shift Register has been shifted out and there are no new data currently present in the
transmit buffer. The TXC Flag bit is automatically cleared when a transmit complete
interrupt is executed, or it can be cleared by writing a one to its bit location. The TXC
Flag is useful in half-duplex communication interfaces (like the RS485 standard), where
a transmitting application must enter Receive mode and free the communication bus
immediately after completing the transmission.
Und da wird davon geredet, dass NACH dem letzen Transmit dieses Flag gecleard (also 1 reinschreiben) werden soll. So wie Arexx-Henk es macht.
helmut_w
02.08.2007, 22:19
Hi Sternthaler!
(Wie heißt Du eigentlich mit richtigem Vornamen?)
Ich heiße übrigens Helmut (ohne dem "underscore w"!:))
hast du auch manchmal das Gefühl eines "deja vu"?
Natürlich hast Du mit dem "doppelten Lottchen" Recht! Aber ich wollte das in diesem Thread begackerte Problem insgesamt darstellen, denn es gibt Leute, die sehen nicht ganz den "Zusammenhang der Dinge"!:))
1. Du zitierst leider nicht ganz korrekt:
Zum TXC-Flag wird auch noch auf Seite 139, im Kapitel "Transmitter Flags and
Interrupts", geschrieben: ...
Wenn Du richtig hingeguckt hättest, geht's dabei um "Interrupts", also in 'ner ISP! Aber die haben _wir_ in _unserem_ Programm doch garnicht!
2. Leider muss ich den ganzen Sermon jetzt nochmals darstellen (Ich bitte um Gnade!:))
The Transmit Complete (TXC) Flag bit is set one when the entire frame in the transmit
Shift Register has been shifted out and there are no new data currently present in the
transmit buffer.
Und da steht doch sinngemäß drin:
TXC = 1, wenn
* 1. das gesamte "Versand-Paket" (einschließlich "Start-", "Stopp-" und evtl. "Paritätsbit") hinausgeschoben (=versandt) wurde,
und
* 2. sich keine (weiteren/) neuen Daten im Transmit-Speicher (=UDR) befinden!
((Worauf willst Du noch warten, wenn Du den Sender ausschaltest und den Empfänger ein?))
3. Die nächsten Sätze auf Deiner Seite 151 und auf _meiner_Seite_ 154 (wegen der unterschiedlichen Versionen der Beschreibung "ATmega8") beziehen sich doch wieder auf ISP's!
(Hier wieder wie oben: unwichtig!:))
4. Dein besonders dick markierter Satz
... , or it can be cleared by writing a one to its bit location.
ist 150 % RICHTIG!:)), denn das gibt's ja auch bei uns:
"UCSRA |= 0x40; // clear transmitter flag "
so ziemlich am Anfang der Funktion "UartPutc()" (und der von mir vorgeschlagenen).
Ich hoffe, du bist mir jetzt nicht böse, weil ich diverse Sachen widerlegt bzw. richtig gestellt habe.
Ich bin zwar Newby, aber ich lerne 'halt dazu und mache mir so meine Gedanken!:))
- Und wenn die falsch sind, so bitte ich Dich, sie zu widerlegen!
(Bei einem falschen Gedanken meinerseits lade ich Dich dann auf ein Bierchen ein!:))
cu Helmut
PS: Weiß vielleicht schon einer die neueste Rev.-Nr. der Beschreibung?
Sternthaler
03.08.2007, 01:29
Hallo Helmut (ohne _w) Namen sind Schall und Rauch.
Gnade benötigt keiner. Es ist halt so, dass die eine Frage, eine Antwort mit noch mehr Fragen aufwirft.
Ja, ich habe schon gesehen, dass die Beschreibung auch für die Interrupt-Behandlung vorhanden ist. In deiner Beschreibung hast du dich auf "[Note: 1. See "About Code Examples" " bezogen. Alles OK, nur, dass es zusätzlich eine Interrupt-Beschreibung gibt, die das selbe aussagt, ist von mir dazu gekommen.
In beiden Beschreibungen finde ich aber die gleiche Aussage: "Cleare das Bit nachdem allles gesendet wurde."
In unserer LIB wird das Bit aber in der SerWrite()-Funktion am Anfang gecleard. Deshalb mein Einwand/Vorschlag es a) so zu machen wie Arexx-Henk es beschreibt, oder b) auf alle Fälle vor dem Senden dieses Bit zu clearen.
{
Clear Bit
senden
}
{
empfangen
}
ist anders als
{
senden
clear Bit
}
{
empfangen
}
P.S.: Ich trinke jede Sorte Bier ;-). Vorsicht, ich kann viel. Bei falschen Aussagen aber auch ausgeben!
damaltor
03.08.2007, 16:34
aber das TXC bit wird doch von allein geclearded, sowie der TXC interrupt angenmmen wurden, oder nicht?
Sternthaler
03.08.2007, 18:56
Hallo damaltor,
ja, ist schon richtig, das TXC gecleard wird beim Interrupt. Aber leider eben NUR beim Interrupt. helmut_w hatte mich ja genau auf diesen Umstand oben hingewiesen, da ich ja die Beschreibung aus dem Interrupt-Bereich auch noch aufgeführt hatte.
Ich glaube, dass wir uns mal genauestens um dieses Bit kümmern müssen um rauszubekommen, ob es nun Einfluss nimmt wenn man sendet, bzw. ja schon gesendet hat, und nun sofort empfangen will und dort als erstes der Sender ausgeschaltet wird.
Also meine Frage:
Warum muss ein TXC-Bit, welches von und GELESEN wird um rauszubekommen, ob alles gesendet wurde, noch mal mit 1 BESCHRIEBEN werden um da 'was auch immer' zu clearen? Was wird da eigendlich gecleard?
damaltor
03.08.2007, 19:12
wenn man eine 1 schreibt, wird das bit gelöscht, also auf 0 gesetzt. ich vermute mal dass da was technisches hintersteckt, auch die fusebits sind beim avr umgekehrt. wenn man eine 1 liest, bedeutet dass dass alles gesendet wurde. wenn man dann eine 1 reinschreibt, wird das bit auf 0 zurückgesetzt.
der interrupt könnte aber auch mit einer return-anweisung angenommen werden... dann wäre das bit schnell gecleared.
das mit dem UDRE bit hat sich dann wohl erledigt... ich glaube mich zu erinnern, dass es nur das sendende UDR register betrifft.
aber was haltet ihr davon?
es gibt im gcc eine vordefinierte funktioN:
loop_while_bit_is_clear(REGISTER,BIT);
wenn man da das statusregister und TXC einsetzt, loopt die funktion so lange wie das bit nicht gesetzt ist. würde man diese funktion am ende von serwrite anfügen, müsste die funktion so lange warten, bis der transffer wirklich fertig ist.
Sternthaler
03.08.2007, 20:04
Hai,
das "loop_while_bit_is_clear(REGISTER,BIT);" machen wir ja schon in der Sendefunktion mit:
while (!(UCSRA & 0x40)) ; // Wait for transmit complete flag (TXC)
Eine Interruptfunktion nur mit nichts drin machen, nur um das Bit zu clearen?
Immer noch: Warum das Bit clearen?
(Nicht gefragt, warum ne 1 zum clearen benutzt werde soll.)
damaltor
03.08.2007, 23:16
das bit müsste gecleared werden, damit es für eine auswertung genutzt werden kann. ansonsten bleibt es doch dauerhaft 1, und hat damit eigentlich keinerlei wirkliche funktion. wenn man es immer rechtzeitig cleart, dann kann man sehen ob der aktuelle transfer beendet ist. zb mit einer loopwhilebitisclear schleife, die wartet, bis der transfer beendet ist (bit ist gesetzt), dann das bit cleart (1 schreibt) und dann das senden des nächsten chars zulässt bzw das programm weiterlaufen lässt - zB mit serread, was ja jetzt gefahrlos angewandt werden kann.
Sternthaler
04.08.2007, 03:33
Ohhh, ich glaube wir sollten mehr Leerzeichen benutzen! (Oder lieber 2-3 !!! ;-) )
Unser "while ( ! (UCSRA & 0x40)) ;"-Code dreht ja nun alles auf den Kopf. Das Bit bleibt also nicht dauerhaft auf 1, sondern auf 0. Denn nur dann kommen wir ja wieder aus dem while herraus, wenn es auf 0 gegangen ist.
Also nochmal für mich:
- TXC-Inhalt ist 1 (hier von mir angenommen)
- Unser Programm schreibt nach UDR
- Unser Programm geht zum "while ()" weiter
- AVR moved UDR in's interne Schieberegister
- AVR sendet aus Schieberegister
- AVR setzt TXC auf 0 wenn alles geschoben ist.
- unser "while ( ! ...) sieht dies und while bricht ab
---> wenn wir uns nicht um das TXC-Bit kümmern:
- TXC-Inhalt ist 0
- Unser Programm schreibt nach UDR
- Unser Programm geht zum "while ()" weiter
- AVR moved UDR in's interne Schieberegister
- AVR sendet aus Schieberegister
- AVR setzt TXC auf 0 wenn alles geschoben ist. <--- Ist es aber noch
- unser "while ( ! ...) sieht dies und while bricht vor dem setzen durch AVR ab. Und damit bevor alle Bits das Schieberegister verlassen haben.
---> Wenn nun direkt zum Empfangen gewechselt wird:
- wir schalten den Sender ab
---> Das letzte zu sendende Zeichen ist verloren.
Da es ja nur in einer Interruptfunktion wieder gecleard (also 1) wird, müssen wir es demnach tatsächlich selber machen, wenn wir weitere Zeichen auf komplette Übertragung des zu sendenden Bytes prüfen wollen.
Wann muss das TXC gecleard werden? Vor dem Beschreiben des UDR oder hinterher (wie bei Arexx-Henk)?
Im Kapitel "USART Initialization" ist zu finden:
The USART has to be initialized before any communication can take place. The initialization
process normally consists of setting the baud rate, setting frame format and
enabling the Transmitter or the Receiver depending on the usage. For interrupt driven
USART operation, the Global Interrupt Flag should be cleared (and interrupts globally
disabled) when doing the initialization.
Before doing a re-initialization with changed baud rate or frame format, be sure that
there are no ongoing transmissions during the period the registers are changed.
The TXC Flag can be used to check that the Transmitter has completed all
transfers, and the RXC Flag can be used to check that there are no unread data in
the receive buffer.
Note that the TXC Flag must be cleared before each transmission
(before UDR is written) if it is used for this purpose
--> Sieht so aus, als ob der Code der Asuro-LIB NICHT in Ordnung ist bei SerWrite() in uart.c.
Aber wer hat es richtig gemacht?
stochri mit seiner Funktion UartPutc() aus print.c die von helmut_w mit seinem ersten Eintrag schon gezeigt wurde.
Und wer hat als erster hier auf die Kombination senden/empfangen hingewiesen?
Ein "BRAVO" an m.a.r.v.i.n (kleines bravo an damaltor, der sich auch noch erinnern konnte.)
Also bleibt eigendlich nur noch eine Änderung der Asuro-LIB übrig.
Dann auch gleich die von helmut_w ja eigendlich gewünschten Verbesserungen einbauen und alle sind glücklich :-({|=
Jubel, ich glaube es nun kapiert zu haben.
Sonst noch Fragen zum TXC? Was ist nun mit den Vorschlägen von helmut_w?
- Stom sparen auf alle Fälle
- for()-Schleife in SerWrite() entsorgen
- TXC-Bit vor dem nutzen des UDR auf 1 setzen
- Neue Funktions-"Gruppierung" á la m.a.r.v.i.n's #define ?
- Von helmut_w vorgeschlagene Funktion, da aber ohne Möglichkeit zum senden eines 0x00-Bytes ?
Bis morgen.
damaltor
04.08.2007, 09:48
moment, ich glaub da ist noch ein fehler:
TXC WIRD 1, wenn der transfer beendet ist.
TXC WIRD 0, wenn man es durch schreiben einer 1 (!) cleared.
normalerweise bzw. nach dem einschalten des prozessors ist TXC = 0!!
könnte allerdings sein dass durch den bootloader irgendwas gesendet wird, dann ist es natürlich eins. glaube ich aber nicht, man sieht ja nix in hyperterminal wenn man nicht flasht.
helmut_w
04.08.2007, 12:39
Hi Sternthaler,
nachdem Dein Vorname nur "... Schall und Rauch" ist, (Dein Spruch!:)) muss ich Dir auch noch verkünden, dass Du mit
Unser "while ( ! (UCSRA & 0x40)) ;"-Code dreht ja nun alles auf den Kopf. Das Bit bleibt also nicht dauerhaft auf 1, sondern auf 0. Denn nur dann kommen wir ja wieder aus dem while herraus, wenn es auf 0 gegangen ist.
auch noch FALSCH liegst!:)) (Oh, du dickes Ei!)
Deutsche Spragge, schwere Spragge! English noch viel schwerer!:))
* Bit 6 - TXC: USART Transmit Complete
This flag bit is set when the entire frame in the Transmit Shift Register has been shifted out and there are no new data currently present in the transmit buffer (UDR).
... hatten wir schon: (und schon wieder ein "deja vu-Erlebnis"!)
Und da steht doch sinngemäß drin:
TXC = 1, wenn
* 1. das gesamte "Versand-Paket" (einschließlich "Start-", "Stopp-" und evtl. "Paritätsbit") hinausgeschoben (=versandt) wurde,
und
* 2. sich keine (weiteren/) neuen Daten im Transmit-Speicher (=UDR) befinden!
The TXC Flag bit is automatically cleared when a transmit complete interrupt is executed,
.... ebenso => hier unwichtig!
or it can be cleared by writing a one to its bit location.
Bitte beachten "it can"!
Dass wir das _zur_Sicherheit_ machen, hatte ich ja auch schon geschrieben!
The TXC Flag can generate a Transmit Complete interrupt (see description of the TXCIE bit). Na ja, auch HIER unwichtig!
(Und das Alles steht bei mir auf Seite 154!:-)
Na ja, es war schon ziemlich spät!:))
- AVR setzt TXC auf 0 wenn alles geschoben ist.
- unser "while ( ! ...) sieht dies und while bricht ab
Umgekehrt! "TXC auf 1, wenn alles geschoben ..." und der Speicher UDR leer ist.!
Ich würde, damit alle glücklich sind, alles so lassen, wie es ist! Bis auf
1. m.a.r.v.i.n's #define => ist m.M. nach 'ne gute Ergänzung!
2. Doppel-FOR-Schleife weg => braucht man nicht!
3. Bei TX ein: nicht das ganze Byte setzen "UCSRB = 0x10; //enable receiver", sondern _etwas_besser_ nur das entspechende Bit: "UCSRB |= 0x10; //enable receiver"
... und zum Ausschalten: "UCSRB &= ~0x10; //disable receiver" (dto. clear'en)
4. analog dazu das Gleiche beim Empfänger!
Jeder, der ein wenig "fortgeschrittener" ist, kann sich ja die vorgefertigten Funktionen nach Gusto anpassen!
Hi @damaltor!
TXC WIRD 0, wenn man es durch schreiben einer 1 (!) cleared.
Glaube ich nicht, dass es zu Null wird, sondern es bleibt 1. (Das mit dem "cleared" ist m.M. nach hier etwas verwirrend ausgedrückt!)
Ich wette, dass erst der Schreib-Zugriff auf UDR 'ne Null draus macht! (Denn erst dann fängt der Sendeprozess an!)
So, ich muss jetzt weiterlernen, in dem ich Eure Programme analysiere!!:))
cu Helmut
PS: Schade, dass ich noch keine Antwort auf meine Frage nach dem Zweck der Variablen "tot_count" in Go() bekommen habe! (Vielleicht kann mir hier jemand helfen?)
radbruch
04.08.2007, 12:59
or it can be cleared ...
wenn es die ISR nicht macht! Im Polling-Betrieb kannst es auch nicht löschen und bei der nächsten Abfrage wird ein "Schieberegister leer" erkannt, weil das TXC noch vom letzten beendeten Senden gesetzt war. Das mache ich hier nicht anders:
https://www.roboternetz.de/phpBB2/viewtopic.php?p=302605#302605
mic
damaltor
04.08.2007, 13:33
nein, das stimmt schon. das bit ist clear, wenn es null ist, und es wird gecleared, wenn es mit 1 beschrieben wird. ich arbeite gerade mit der USART auf einem STK200, um die möglichkeiten der Datenübertragung zu testen.
durch das schreiben einer 1 in das bit wird es zu null! ist zwar eigenartig, aber ich vermute einen technischen rund dahinter. vermutlich wurde dadurch etwas platz auf dem silizium gespart.
Sternthaler
04.08.2007, 18:17
Hilfe, ich verblöde! (Oder ist 3:33 doch auch für mich zu spät?)
Natürlich habt ihr alle Recht. "while ( ! (UCSRA & 0x40)) ;" heißt selbstverständlich, dass das TXC-Bit erst 1 werden muss damit die Schleife verlassen wird. Dann passt es auch zur englischen Beschreibung. (Kann ich scheinbar nach 03:00 nur manchmal verstehen)
Trotzdem sollte das Bit "before each transmission (before UDR is written)" gecleard werden. Das aber fehlt trotz meines unverzeihlichen Fehltritt's heute Nacht in uart.c SerWrite().
Und ob da ein Stück Silicium fehlt, oder das Bit halt lieber negativ denkt ist doch eigendlich egal. Hauptsache es wird vorher auf 1 gesetzt, damit es 0 wird.
or it can be cleared by writing a one to its bit location.
Bitte beachten "it can"!
Dass wir das _zur_Sicherheit_ machen, hatte ich ja auch schon geschrieben!
Hier allerdings bin ich immer noch der Meinung, dass es in unserem Fall zwingen notwendig ist., denn der Satz geht weiter mit: "if it is used for this purpose"
(Was habe ich jetzt an Müll geschrieben? Sagt es mir)
damaltor
04.08.2007, 19:59
/me beruhigt sternthaler erstmal und pustet den schall und rauch weg =)
man kann es löschen, wenn man mag. mehr ist dazu nicht zu sagen. ich denke, es ist eine feine sicherheitsabfrage, damit fehler in der übertragung begrenzt werden. leider ist mein asuro gerade in der umbauphase, hat das also mal jemand ausgetestet?
Sternthaler
04.08.2007, 20:12
/me beruhigt sternthaler erstmal ...
... hat das also mal jemand ausgetestet?
Ich zähle schon seit Sunden immer wieder bis 1000. So langsam geht es wieder. ;-)
Nein, ist noch nicht ausprobiert. Oder doch, eigendlich ja schon von Arexx-Henk.
damaltor
04.08.2007, 20:15
iss erstmal einen ja!-doppelkeks...
Sternthaler
05.08.2007, 00:48
Mhhm... lecker, besonders gut mit Kaffee und Rapmusik. Gibt es eigendlich schon ein rappiges Stück für den musizierenden-Asuro? :lol:
damaltor
05.08.2007, 01:16
hmm... hiphop ist ok, aber ich hör lieber musik....
helmut_w
05.08.2007, 19:07
Hallo,
ich habe an Euch eine große Bitte: Kann jemand das folgende Programm (nur kurz!) testen?
Es müsste (besser: sollte!:) ) nach dem Laden blinken, dann 10 Zeilen mit a ... z zum PC senden.
Die Prog.-Frakmente stammen noch von der "Urversion".
/* test.c
Test zum Senden - asuro.h + -.c verkleinert und SerWrite(j) angepasst!
Programm soll 10 Zeilen mit a ... z senden.
SerWrite() enthaelt nur "wenn Speicher leer, dann senden"! */
#include "asuro.h"
int main(void)
{
unsigned char i, j;
Init();
for(i=0;i<200;i++)
{
for(j=0;j<20;j++) Sleep(0xFF);
StatusLED(RED);
for(j=0;j<20;j++) Sleep(0xFF);
StatusLED(GREEN);
}
UCSRB |= 0x08; // Sender ein
UCSRA |= 0x40; // 'clear' transmitter flag
for(i=1;i<11;i++)
{
for(j='a';j<='z';j++)
{
SerWrite(j);
}
SerWrite('\n');
SerWrite('\r');
}
while (!(UCSRA & 0x40))
; // warten bis Uebertragung fertig
UCSRB &= ~0x08; // Sender aus
StatusLED(YELLOW);
while(1)
;
return 0;
}
---------------
/* asuro.c */
#include "asuro.h"
volatile unsigned char count72kHz;
SIGNAL (SIG_OUTPUT_COMPARE2)
{
count72kHz ++;
}
void Init (void)
{
TCCR2 = (1 << WGM21) | (1 << COM20) | (1 << CS20);
OCR2 = 0x6E;
TIMSK |= (1 << OCIE2);
UCSRA = 0x00;
UCSRB = 0x00;
UCSRC = 0x86;
UBRRL = 0xCF;
DDRB = IRTX | LEFT_DIR | PWM | GREEN_LED;
DDRD = RIGHT_DIR | FRONT_LED | ODOMETRIE_LED | RED_LED;
TCCR1A = (1 << WGM10) | (1 << COM1A1) | (1 << COM1B1);
TCCR1B = (1 << CS11);
//ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1);
StatusLED(GREEN);
sei();
}
inline void StatusLED(unsigned char color)
{
if (color == OFF) {GREEN_LED_OFF; RED_LED_OFF;}
if (color == GREEN) {GREEN_LED_ON; RED_LED_OFF;}
if (color == YELLOW) {GREEN_LED_ON; RED_LED_ON;}
if (color == RED) {GREEN_LED_OFF; RED_LED_ON;}
}
void SerWrite(unsigned char data)
{
while(!(UCSRA & 0x20))
;
UDR = data;
}
void Sleep(unsigned char time72kHz)
{
count72kHz = 0;
while (count72kHz < time72kHz);
}
FirstTry.zip (enthält alle files) beigeschlossen!
Auswertung: Kommen _nicht_ alle Zeichen an, dann sollte man 'was ändern!:))
Vielen Dank schon 'mal im voraus!
cu Helmut
PS: Heute morgen konnte ich sehr über diverse Artikel lachen!
radbruch
05.08.2007, 20:55
Hallo
UCSRA |= 0x40; // 'clear' transmitter flag
TXC sollte besser mit = gelöscht werden. Mit |= werden zufällig auch noch gesetzte Flags mitgelöscht!
Gruß
mic
damaltor
05.08.2007, 21:27
nein, gerade nicht! wenn man mit = schreibt, wird das ganze register überschrieben.
oder war das gerade das ziel, weil ja mit ner 1 grlöscht wird? hmm...
wäre btw ein gute grund warum gerade mit ner 1 das bit entfernt wird..
helmut_w
05.08.2007, 22:00
Hi,
interessant ist, dass ich ein ZIP-file mit reingestellt habe, das jetzt weg ist!?
Also nochmals das Ganze!
Vielleicht könnt Ihr bitte das ganz kurze Prog. 'mal testen.
Danke!
cu Helmut
damaltor
05.08.2007, 22:02
das tip file ist noch da (bei mir zumindest). du musst allerdings eingeloggt sein um es zu sehen.
helmut_w
05.08.2007, 22:21
Vielen Dank!
cu Helmut
PS: Man lernt einfach :immer_ noch 'mal was hinzu!:)
Sternthaler
06.08.2007, 02:58
Hallo helmut_w,
ja, ich traue mich noch :roll:
Auch ich konnte aus beiden Beiträgen downloaden. Habe aber noch nichts getestet.
Ich stimme damaltor zu, auch ich würde das |= stehen lassen.
Was ich aber noch in der Doku gefunden habe (ja, das Thema ist gegessen, auch ohne Prinzenrolle!) ist folgendes:
Seite 12/13 Reset and Interrupt Handling
Interrupt Flags can also be cleared by writing a logic one to the flag bit position(s) to be cleared.Dies gilt scheinbar für jedes Flag, welches einen Interrupt auslösen kann. Ausnahme eventuell beim SPIF-Bit.
Seite 22 I/O Memory
Some of the Status Flags are cleared by writing a logical one to them.
Ich habe kein Liste gefunden, welche Flags es denn nun genau sind. Immer nur bei den einzelnen Flags, gibt es einen 'versteckten' textuellen Hinweis.
Seite 46 General Interrupt Control Register - GICR
When the IVSEL bit is cleared (zero), ...Bei diesem Bit ist als einzige Stelle tatsächlich mal mit (zero) ein Hinweis auf ein 'gecleardes' Bit, dass es dann '0' ist gegeben.
BRAVO an damaltor, der sich getraut hat diesen Sachverhalt hier zu posten. (Wer setzt den schon ein Bit auf '1' um es auf '0' zu setzen?)
Seite 283 Register Summary (Continued)
Note:
3. Some of the Status Flags are cleared by writing a logical one to them
Note that the CBI and SBI instructions will operate on all bits in the I/O Register,
writing a one back into any flag read as set, thus clearing the flag.
The CBI and SBI instructions work with registers 0x00 to 0x1F only.Hier hört mein Englisch tatsächlich auf. Die weitere Erklärung von CBI und SBI mit 'read as set' kann ich tatsächlich nicht mehr umsetzen.
damaltor
06.08.2007, 14:00
das bedeutet folgendes:
mit CBI und SBI kann man in assembler einzelne bits setzen (Set BIt) oder löschen (Clear BIt).
das bedeutet allerdings nicht , dass die erforderliche aktion getan wird um es zu löschen, sondern mit sbi wird eine 1 geschrieben, und mit cbi wird eine null geschrieben.
diese beiden befehle funktionieren nur mit den ersten 32 registern (0x00 bis 0x1F), das sind allgemeine statusregister und zB die von den Portpins.
Note that the CBI and SBI instructions will operate on all bits in the I/O Register,
writing a one back into any flag read as set, thus clearing the flag.
das ist extrem wichtig: es bedeutet, wenn du ein register ausliest, und dann wieder an die gleiche stelle schreibst, werden alle interrupt flags gelöscht (wenn du eine 1 liest, und dann an die stelle ne 1 schreibst, wird das bit gelöscht... is klar soweit, aber leicht zu vergessen wenn man zB den inhalt eines registers sichern will un es später zurückschreibt.)
radbruch
06.08.2007, 15:25
Hallo
nein, gerade nicht! wenn man mit = schreibt, wird das ganze register überschrieben.
Wenn man mit = arbeitet, wird nur das angesprochene Bit gelöscht, alle anderen werden mit 0 überschrieben und dadurch nicht beeinflußt. Mit |= werden auch andere Flags mitgelöscht, wenn sie zufällig genau zu diesem Zeitpunkt auch gesetzt(=1) sind!
Gruß
mic
damaltor
06.08.2007, 18:05
aaaaaaaaaaaahhhh... richtig =)
vermutlich ist darum auch das löschen mit 1 eingestellt worden... macht sinn.
Sternthaler
06.08.2007, 21:53
Whow (oder so ähnlich),
dann macht ja auch der von damaltor (extra für mich ;-) ) übersetzte Text tatsächlich Sinn bei dieser Sorte von Registern, sie wirklich mit = zu 'überschreiben' so wie radbruch es sagt.
(Ganz schönes Querdenken!)
damaltor
06.08.2007, 22:44
dieses querdenken scheint bei den avrs üblich zu sein. gelegentlich lieest man was im datenbaltt und denkt nur "wtf?" aber dann wenn mans brraucht scheint es plötzlich ne echt gute sache zu sein
radbruch
06.08.2007, 23:01
Hallo
Das habe ich bei meinem Einstieg in die echte AVR-Programmierung gelernt. Natürlich hier im RN-Forum:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=295989#295989
Gruß
mic
Sternthaler
07.08.2007, 00:26
Es geht eben nichts über diese Forum.
helmut_w
07.08.2007, 10:49
Hi Sternthaler,
ja, ich traue mich noch ...
Tolllll!:)
Auch ich konnte aus beiden Beiträgen downloaden.
Danke für die Rückmeldung! Aber Ihr wisst ja, so'n Newby weiß 'halt noch nicht alles ... !:(
Nun, zu mehr Erstem:
Note:
3. Some of the Status Flags are cleared by writing a logical one to them. *1*
Note that the CBI and SBI instructions will operate on all bits in the I/O Register,
writing a one back into any flag read as set, thus clearing the flag. *2*
The CBI and SBI instructions work with registers 0x00 to 0x1F only.
---------
Hier hört mein Englisch tatsächlich auf. Die weitere Erklärung von CBI und SBI mit 'read as set' kann ich tatsächlich nicht mehr umsetzen.
Zu *1*:
Verstehe ICH so: Normal ist, dass "Clear" *zurücksetzen auf Null bedeutet*, aber es gibt auch
den Fall, dass "Zurücksetzen" einfach *Schreiben einer Eins* bedeutet! (Die Du dann auch als solche lesen kannst: 'read as set'!)
Zu *2*:
CBI und SBI sind Maschinesprache-Befehle Clear - bzw. Set Bit im unteren Bereich (0x00 to 0x1F only) der IO-Register!
Zu *1* habe ich mein kleines Prog. ergänzt und lese das IO-Register "UCSRB" vor und nach dem "Clearen" aus! (Es muss natürlich heißen: "sollte", da ich das Prog. noch nicht testen kann!)
...
void b2h(byte d)
{ byte h=(d/16)+0x30;
if(h>0x39) h+=7;
SerWrite(h);
h=(d & 0x0f)+0x30;
if(h>0x39) h+=7;
SerWrite(h);
}
....
b2h(UCSRA);
SerWrite(' ');
UCSRA |= 0x40; // 'clear' transmitter flag
Sleep(0xFF);
b2h(UCSRA);
....
cu Helmut
Nachtrag:
Sorry, ich habe das Forum nicht besucht und dann gepostet, sondern verkehrt herum! !:(
So muss ich doch noch "nachtarocken"!
zu @damaltor:
hi damaltor,
Du hast das *1* "fast" besser beschrieben, als ich!:)
Das mit dem gelöschten Flag, wusste ich leider (noch!:)) nicht!
Aber mein kleines Prog. müsste das ja auch zeigen! (Ich will's morgen testen!)
zu @radbruch:
hi mic,
Deine Behauptung mit "=" kann ICH _nicht_teilen_: !:(
Wenn Du mit "=" eine Zuweisung machst, so wird die Variable mit diesem Wert belegt!
(Außer bei CBI, ..., also den Bit-Operatoren! Aber das schreibst man je in Assambler anders!)
Wenn man nun "|=" meint, so heißt das, dass die (vordere) Variable mit dem hinteren Wert
"geodert wird". Und wenn da nur ein Bit gesetzt ist, dann wird nur an _dieser_Stelle_ ein
Bit gesetzt! (Bei mehreren natürlich eben diese.)
"&= ~" ist das Gegentum dazu: hier löscht Du das im hinteren Teil als "Eins" gesetzte Bit,
bzw. mehrere!
cu Helmut
PS: bei b2h() (also Byte/Char to hex) sollte/könnte man noch "0x" davor senden.
damaltor
07.08.2007, 11:50
geclearte bits sind null, ich habe es versucht an der USART auszulesen. eins geschrieben, nul,l gelesen.
das READ AS SET hat ne andere bedeutung (die eigentlich verdammt wichtig ist:
benutzt man CBI oder SBI, muss man sehr vorsichtig sein. diese befehle setzen nämlich nicht wirklih nur das eine bit, sondern:
lesen das register
verknüpfen es mit ODER mit dem bit
schreiben das register zurück
dadurch werden die interrupt-flags gelöscht!!!
"Note that the CBI and SBI instructions will operate on all bits in the I/O Register, " -> beachten sie, dass CBI und SBI auf alle bits des registers wirken.
"writing a one back" -> schreiben eine 1 zurück
"into any flag read as set" -> in jedes flag, das als gesetzt gelesen wurde
"thus, clearing the flag" -> und dadurch wird das flag gelöscht
das = ist schon richtig. sagen wir mal, wir haben ein status register, in dem 8 interrupt-flags drin sind:
0b00110101
4 flags sind aktiviert. wir wollen jetzt das bit 4, also die zweite eins von links löschen.
möglichkeit 1:
REG |= 0x10;
was ja das gelice bedeutet wie
REG = REG | 0x10;
also REG = 0b00110101 | 0b00010000
also REG = 0b00110101
jetzt werden 4 einsen geschrieben. und da eine 1 ja zum löschen den interrupt-flags verwendet wird, werden alle 4 interrupt-flags gelöscht, obwohl wir nur eines wollten...
zweite möglichkeit:
REG = 0x10;
also
REG = 0b00010000;
es wird nur eine 1 geschrieben. das bit wird gelöscht, alle anderen bits bleiben unverändert.
helmut_w
07.08.2007, 16:09
Hi damaltor,
danke für Deine prompte Antwort!
Allerdings redet (fast) jeder von was anderem; Gott-sei-Dank habe _ich's_jetzt_ kapiert!!:)
Manchmal ist halt so'ne Leitung ziemlich lang!!:)
1. Das, was ich gepostet habe, bezieht sich ALLGEMEIN auf "|=", "=" und "&= ~", also auf ganz normale Variable!
2. Das was Du und wahrscheinlich auch mic weiter oben meintet, geht in Richtung "IRQ-Flags"! (Denn nur die kann man mit 'ner Eins zurücksetzen! Allerdings ist bei uns hier von ISR sowohl beim Senden, als auch beim Empfangen (noch!?) keine Anwendung da, oder? Folglich dient die Abfrage nur beim Pollen der Antwort auf "ist TX fertig? ja oder nein". Es ist meiner Meinung nach völlig wurscht, ob wir das Flag am Anfang oder am Ende der Funktion "Senden" löschen; und zwar so wie DU richtig geschrieben hast: durch Schreiben einer Eins z.Bsp. mit "="! *)
Wenn wir den Sender wieder ausschalten wollen, dann ist empfehlenswert (übrigens so, wie von mir vorgeschlagen! !:) ) TXC am Anfang sicherheitshalber zu löschen und am Ende nachgucken, ob TXC gesetzt ist und dann erst den Sender aus-/abschalten!
*) Allerdings NUR im Falle, wenn mindestens ein Bit in UCSRA der Nummer 1 und/oder #0 (=U2X, MPCM) gesetzt wäre, ist Dein Vorschlag mit "=" falsch, denn dann setzt Du diese Bits AUCH auf Null!
So jetzt zum Fall UCSRA (= USART Control and Status Register A):
Auf Seite 154 steht, dass nur das Flag TXC (=USART Transmit Complete, Bit #6) von den anwesenden IRQ-Flags les- UND schreibbar ist! (D.h., dass man die anderen {IRQ-}Bits #7, 5 - 2!) durch Schreiben NICHT verändern kann!
==>> Dem zur Folge ist HIER "UCSRA |= 0x40;" bzw. "UCSRA |= (1<<TXC);" AUCH richtig!!:)
Ob der Maschinenbefehl "CBI" hier geht, weiß ich nicht, da ich bisher noch nicht herausgebracht habe, an welcher Position im IO-Bereich sich "UCSRA" befindet, da wie Du ja richtig geschrieben hast, das nur in der unteren Hälfte geht!
So jetzt zur Initialisierung von TX:
Auf Seite 139 ist ÜBERHAUPT KEINE Rede von TXC! (Also weder 'ne Null noch 'ne Eins werden da "offiziell als Bsp." gesetzt! Allerdings steht auf Seite 154, dass man - m.M. nach! - TXC trotzdem _sicherheitshalber_ clearen kann! (Was wir ja machen und was jetzt _neu_ _zum_Ausschalten_ wirklich nötig ist! Früher musste/brauchte man da auf TXC nicht warten! Wenn man's trotzdem gemacht hat, war es sicher nicht FALSCH, jedoch UNNÖTIG!)
... nun zu Deinem Statement von CBI:
Lt. schlauer Beschreibung "Instruction Set" steht auf Seite 48: "Clears an specified bit in an IO Register. ..." Das mit "geODERt" gilt hier nicht!
Du / Ihr habt das möglicherweise mit CBR verbuxelt! Denn da wird - allerdings nur in einem Rd-Register, also noch weiter vorne in dem Speicher als bei IO-Regs! - mit dem Kehrwert "geUNDet"!
So, jetzt habe ich (und hoffentlich auch alle anderen Leser!) wieder 'mal was gelernt!
cu Helmut
damaltor
07.08.2007, 17:26
wenn man den sender abschaltet, wird...
zuerst das noch zu sendende zeichen abgeschickt
dann das zeichen was gerade im UDR ist, eingeschobden und auch noch abgeschickt, falls vorhanden
und dann erst der sender abgeschaltet. ist also recht risikofrei.
txc ist zum ersten dazu da um zu prüfen, ob der transfer fertig ist. deshalb sollte man es besser VOR der übertragung löschen =)
ausserdem wird, wenn dieses bit UND das interrut bit aktiv sind, der TX_READY interrupt ausgelöst.
das mit CBI und SBI habe ich auch gelesen, ich habe nur den text übersetzt wie er da steht. und da steht, dass man aufpassen soll da alle bits des registers mit ihrem eigenen wert beschrieben werden - und dadurch IRQ-flags gelöscht werden. hier nochmal:
"Note that the CBI and SBI instructions will operate on all bits in the I/O Register, " -> beachten sie, dass CBI und SBI auf alle bits des registers wirken.
"writing a one back" -> schreiben eine 1 zurück
"into any flag read as set" -> in jedes flag, das als gesetzt gelesen wurde
"thus, clearing the flag" -> und dadurch wird das flag gelöscht
Sternthaler
07.08.2007, 20:14
Hallo zusammen.
Zum Thema mit dem TXC-Bit bzw. mit der Form vom clearen.
Ich hatte am Sonntag einen Kumpel gefragt, der in seiner Abteilung genau mit diesen AVR's beruflich schon seit Jahren arbeitet. (Was man nicht alles so erfährt bei 2 bis 15 Bier!)
Heute morgen hatte er mal kurz angerufen und mir mitgeteilt, dass es tatsächlich so ist, wenn eine *1* auf das Bit geschrieben wird, dass dieses Bit auf *0* gesetzt wird, und so gelesen wird.
damaltor's Antwort zu diesem Thema wird durch 'Profis' (Siemens) bestätigt.
@damaltor
Woher hast du die Info, dass der Sender auf alle Fälle noch die Bytes aus dem internen Schieberegister UND aus dem UDE noch sendet?
Bleibt die CPU dann an dieser Stelle "UCSRB = Nicht mehr senden" stehen, bis alles gesendet wurde?
damaltor
07.08.2007, 20:29
nein, der prozessor arbeitet weiter. das bit wird bei nächster gelegenheit im hintergrund gecleared.
Datenblatt Seite 142:
"The disabling of the Transmitter (setting the TXEN to zero) will not become effective
until ongoing and pending transmissions are completed (i.e., when the Transmit Shift
Register and Transmit Buffer Register do not contain data to be transmitted). When dis-
abled, the Transmitter will no longer override the TxD pin.
"
helmut_w
08.08.2007, 11:28
Hi damaltor,
nochmals ein großes Dankeschön für Deine "Unterrichtseinheit"!
Mir ist das 'Löschen von IRQ-Flags' heute Nacht im wieder durch den Kopf gegangen!:)
cu Helmut
damaltor
08.08.2007, 12:54
kein problem... dafür ist das forum doch da...
aber wenn du schon davon träumst solltest du dir evl gedanken machen XD
helmut_w
09.08.2007, 14:16
Hallo zusammen!
Gestern haben wir im Club mein "Kurzprogramm" getestet. Dazu mein Erfahrungsbericht:
Zuerst zum Flashen: Trotz _Leuchtstofflampen_-Licht nur 1 'c'-Error und ein paar 't's. Das Reduzieren des Vorwiderstandes von 470 auf 150 Ohm war _absolut_erfolgreich_! Kann ich nur
jeden empfehlen, der Probleme beim Flashen hat! (Vielleicht registriert dies auch AREXX!)
Die Sende-Routine hat mehrfach einwandfrei funktioniert: Deshalb ist KEINE Verzögerungsschleife
notwendig => also heraus damit! Auch das Warten auf TXC nach _jedem_ Zeichen-Senden ist völlig unnötig!
Die beiden hex-Werte (0x60 und 0x00) am Ende zeigten, dass beim Clearen von TXC (Bit 6 von UCRSA) auch das NUR-lesbare Bit 5, also UDRE, gelöscht wird!
Unser Programmier-Profi einer hiesigen Fa., die Industrie-Steuerungen baut, hat auch die Art und Weise bestätigt, wie solche IRQ-Flags allgemein gelöscht werden! (Bei manchen Microcontrollern genügt sogar irgendein Schreibzugriff!)
Bei der Diskussion zur Notwendigkeit der Verwendung der tot_count-Variablen (in Go()) haben wir uns richtig gestritten! Er teilte die Meinung von hier, dass sie notwendig wäre. (Ich trotzdem nicht!:( Also werde ich 'mal versuchen, meinen Standpunkt mit Fakten und Beweisen zu unterbauen!
Auch beim Code von Turn() waren wir sehr unterschiedlicher Meinung!
Zu den beiden letzten Punkten werde ich demnächste 'mal was posten müssen .... !:)
"bis die Tage"
cu Helmut
damaltor
09.08.2007, 18:47
udre.. das müsste doch auch schreibbar sein. es wird doch 1 wenn udr leer ist, und kann manuell wieder gelöscht werden, oder?
helmut_w
09.08.2007, 21:51
Hi damaltor,
udre.. das müsste doch auch schreibbar sein. ...
Nein, siehe mein Beitrag weiter oben:
So jetzt zum Fall UCSRA (= USART Control and Status Register A):
Auf Seite 154 steht, dass nur das Flag TXC (=USART Transmit Complete, Bit #6) von den anwesenden IRQ-Flags les- UND schreibbar ist! (D.h., dass man die anderen {IRQ-}Bits #7, 5 - 2!) durch Schreiben NICHT verändern kann!
Die Bits 1 und 0 sind wieder read/write! Sie haben ja auch nichts mit IRQ's zu tun!
... es wird doch 1, wenn udr leer ist, ...
korrekt! Und das nutzt man dann in der Schleife bei SerWrite aus!
Z.Bsp. in meiner abgespeckten Version:
void SerWrite(unsigned char data)
{ while(!(UCSRA & 0x20));
UDR = data;
}
"0x20" könnte man auch durch "(1<<UDRE)" ersetzen! (Das sieht dann professioneller aus!:))
... und kann manuell wieder gelöscht werden, oder?
NEIN, siehe oben! Das Löschen geht automatisch, d.h. der Controller macht's!:)
Sonst würde ja obiger Code nicht funktionieren!
cu Helmut
damaltor
09.08.2007, 22:20
hmkay...
*textfülller*
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.