Hi, ich zeig euch gleich mal 2 Codevarianten:
Variante 1:
uint8_t temp;
temp = USART_check();
if(temp == 0x01)
{
PORTB = 0x00;
}
Variante 2:
if(USART_check() == 0x01)
{
PORTB = 0x00;
}
Hier noch die dazugehörige Funktion USART_check():
uint8_t USART_check(void)
{
// Sind neue Daten im Buffer? 1 = ja ; 0 = nein
uint8_t temp = (UCSRA & ( 1<<RXC));
if(0b10000000 == temp)
{
return 1; // Daten vorhanden
}
return 0; // Keine Date vorhanden
}
So mein Problem ist jetzt, dass Variante 1 funktioniert und Variante 2
nicht. (unter Funktionieren meine ich, dass man die if Anweisungen
ausführt, also die LEDs an Portb leuchten) Allerdings ist das doch
eigentlich das total gleiche oder? Nur benötigt man bei der 1ten Version
eine Variable mehr... wenn man if(USART_check()) schreibt funktioniert
es auch nicht.
Lass erstmal die ganzen Vergleiche mit "==" weg, das ist schlechter Stil
und kann in die Hose gehen! Also nicht
1
if(USART_check()==0x01)
sondern einfach
1
if(USART_check())
...und in USART_check die überflüssige lokale Variable weglassen und
einfach
1
if(UCSRA&(1<<RXC))
Die Vergleiche sind hier überflüssig, weil hier nicht auf Gleichheit
überprüft werden muss, sondern nur, ob der betreffende Wert von Null
verschieden ist oder nicht.
Warum jetzt konkret die erste Version nicht funktioniert, kann ich
allerdings so auch nicht sagen.
Außerdem solltest Du die Möglichkeiten nutzen, die das Forum zur
Formatierung von Code bietet...
> würde es aber auch tun ;)
Jo, das wäre die (fast) absolute Minimal-Methode. Noch minimaler wird
es, wenn man das ganze nicht als Funktion mit dem dazugehörigen Overhead
implementiert, sondern die Abfrage direkt ins Programm an die
betreffenden Stellen einbaut...
@Johannes M.
überflüssig ok, aber nicht falsch. Aus purer Neugier würde ich auch der
Sache nachgehen.
@GoZu
Du kannst ja, um das Problem einzugrenzen, versuchhalber die
1
uint8_tUSART_check(void)
so abändern:
1
uint8_tUSART_check(void)
2
{
3
return1;
4
}
Wenn dann noch immer ein Unterschied ist, dann liegt es wohl nicht an
der Abfrage des USART.
Kannst Du das Ding im Debugger laufen lassen und temp abfragen?
Logisch ist es in jedem Fall nicht.
Johannes M. wrote:
> Noch minimaler wird> es, wenn man das ganze nicht als Funktion mit dem dazugehörigen Overhead> implementiert, sondern die Abfrage direkt ins Programm an die> betreffenden Stellen einbaut...
Darunter leidet aber die Portabilität des Codes. Vielleicht bringt man
den Compiler dazu, die Funktion inline zu übersetzen.
Severino R. wrote:
> Johannes M. wrote:>> Noch minimaler wird>> es, wenn man das ganze nicht als Funktion mit dem dazugehörigen Overhead>> implementiert, sondern die Abfrage direkt ins Programm an die>> betreffenden Stellen einbaut...>> Darunter leidet aber die Portabilität des Codes. Vielleicht bringt man> den Compiler dazu, die Funktion inline zu übersetzen.
Gängige Compiler (gcc) sollten das sowieso machen, wenn es Sinn macht.
Fabian Ostner wrote:
> Funktioniert nicht , da der return Wert nicht zugewiesen wird.
Das muss der auch nicht. USART_check ist vom Typ uint8_t und hat als
Wert entweder 1 oder 0...
> unsigned char temp;> if((temp = USAT_check()))
Das ist Unsinn.
Severino R. wrote:
> @Johannes M.> überflüssig ok, aber nicht falsch. Aus purer Neugier würde ich auch der> Sache nachgehen.
Nicht direkt falsch, aber fehleranfällig. Wenn ich einen Wahrheitswert
brauche, dann mache ich keine großen Verrenkungen mit irgendwelchen
unnötigen Vergleichen.
Man sollte sich auch eine konsistente Schreibweise angewöhnen (und auch
die Binärschreibweise, die noch zusätzlich die Gefahr mitbringt, dass
man sich bei den 0en und 1en irgendwo verzählt, nach Möglichkeit nicht
verwenden, auch wenn der Compiler sie zur Verfügung stellt).
OK
Also der Code ist deshalb so komisch, weil ich jetzt schon ca. 1 Stunde
daran herumteste. Hatte vorher natürlich auch die minimalvariante von
return (UCSRA & ( 1<<RXC));
Allerdings gibt das 0b10000000 zurück und nicht 0x01.... Das mit
if(USART_check()) hatte ich natürlich auch vorher so, ist ja viel besser
zu lesen so =)
Aber warum es immer noch nicht funktioniert weiß ich selbst nicht :/
Egal, ich lass es jetzt halt einmal unständlich und wenn ich mal wieder
mehr Zeit habe, teste ich es genauer aus
GoZu wrote:
> Aber warum es immer noch nicht funktioniert weiß ich selbst nicht :/> Egal, ich lass es jetzt halt einmal unständlich und wenn ich mal wieder> mehr Zeit habe, teste ich es genauer aus
Hast Du die anderen Varianten, die genannt wurden, wenigstens mal
ausprobiert? Wie schon gesagt, es ist eigentlich unnötig, das als
Funktion zu implementieren. Die Abfrage kann auch direkt in die
if-Bedingung geschrieben werden. Und welchen Wert die Abfrage liefert,
spielt überhaupt keine Rolle, wenn man eben die direkten Vergleiche mit
einem bestimmten Wert weglässt und den Wert einfach als Wahrheitswert
interpretiert.
Vielleicht ist Dir die Funktionsweise nicht ganz klar. Wenn man eine
if-Abfrage macht, z.B.
1
if(Bedingung)
2
Anweisung;
Dann wird Anweisung genau dann ausgeführt, wenn Bedingung wahr (also
nach C-Standard nicht Null) ist. Wenn Du für Bedingung jetzt Dein
"UCSRA & ( 1<<RXC)" einsetzt, dann ist es pupsegal, ob der Wert dieses
Ausdrucks 1, 100, 1245.678 oder -65 ist, Anweisung wird trotzdem
ausgeführt. Nur, wenn der Ausdruck exakt 0 ergibt, wird Anweisung
nicht bearbeitet.
In Deinem Fall wird ein einzelnes Bit maskiert. Der Ausdruck UCSRA &
(1<<RXC) kann also nur genau zwei Zustände annehmen, nämlich 0 (wenn das
Bit nicht gesetzt ist) und (1 << RXC), was aufgelöst 0x80 oder
0b10000000 entspricht. Dieser zweite Zustand ist ungleich 0, weshalb es
nicht erforderlich ist, hier noch mal einen Vergleich zu machen.
Ich weiß auch, dass die Sache mit den Wahrheitswerten für Anfänger nicht
ganz leicht zu verstehen ist, aber wenn man den Dreh einmal raus hat,
merkt man schnell, was dieses Verständnis für Vorteile mitbringt.
Johannes M. wrote:
> Lass erstmal die ganzen Vergleiche mit "==" weg, das ist schlechter Stil> und kann in die Hose gehen! Also nicht>> if(USART_check() == 0x01)>> sondern einfach>> if(USART_check())>
Wenn USART_check als bool definiert worden waere, wuerde ich dir recht
geben. Ist es aber nicht. Also ist es voellig richtig mit dem
definierten Wert zu vergleichen. Nicht umsonst gibt es die implizite
Konvertierung in boolean z.B. in Java nicht...
Peter Stegemann wrote:
> Wenn USART_check als bool definiert worden waere, wuerde ich dir recht> geben. Ist es aber nicht. Also ist es voellig richtig mit dem> definierten Wert zu vergleichen. Nicht umsonst gibt es die implizite> Konvertierung in boolean z.B. in Java nicht...
Wir sind hier aber nicht in Java, sondern in C, und in C gibt es nunmal
standardmäßig keinen Datentyp bool.
Und mit solchen Vergleichen kann man sich auch schnell mal ins Knie
schießen und Fehler verursachen, nach denen man sich dann nen Wolf
sucht. In diesem Zusammenhang ist die Tatsache, dass in C schlicht alles
wahr ist, was nicht falsch (also 0) ist, vorteilhaft verwendbar.
Ich hab ja eh schon 2 mal geschrieben, dass ich normalerweise es eh mit
if(USART_check()) schreibe, allerdings habe ich es später geändert um es
kurz zu testen. Ich programmiere schon länger C/C++ am PC, als nix mit
Anfang, und die genaue Funktionsweise ist mir auch klar =)
Allerdings habe ich jetzt gerade nicht weiter Zeit um das genauer
auszutesten, wenn ich es heute später am Abend austesten werde, werde
ich meine Ergebnisse hier natürlich posten.
Danke schonmal an alle!
Johannes M. wrote:
> Peter Stegemann wrote:>> Wenn USART_check als bool definiert worden waere, wuerde ich dir recht>> geben. Ist es aber nicht. Also ist es voellig richtig mit dem>> definierten Wert zu vergleichen. Nicht umsonst gibt es die implizite>> Konvertierung in boolean z.B. in Java nicht...> Wir sind hier aber nicht in Java, sondern in C,
Ob C oder C++ kann man so nicht sehen und in C++ gibt es bool. Einer der
Gruende, warum man auch fuer C heute den C++-Compiler benutzen kann und
sollte.
> Und mit solchen Vergleichen kann man sich auch schnell mal ins Knie> schießen und Fehler verursachen, nach denen man sich dann nen Wolf> sucht.
Wann? Wenn eine Funktion, fuer die nur die Werte 0 und 1 definiert sind,
andere Werte zurueckgegeben werden?
Viel eher schiesst man sich in den Fuss, wenn man sich auch implizite
Konvertierungen verlaesst. Z.B., wenn als Fehler Werte <= 0 verwendet
werden und der Entwickler aus gewohnheit wieder mal if( doSomething())
schreibt...
Peter Stegemann wrote:
> Ob C oder C++ kann man so nicht sehen und in C++ gibt es bool. Einer der> Gruende, warum man auch fuer C heute den C++-Compiler benutzen kann und> sollte.
Anhand der Register- und Bitnamen handelt es sich vermutlich um einen
AVR, und für AVRs gibt es afaik noch keine "vernünftigen" C++-Compiler.
>> Und mit solchen Vergleichen kann man sich auch schnell mal ins Knie>> schießen und Fehler verursachen, nach denen man sich dann nen Wolf>> sucht.>> Wann? Wenn eine Funktion, fuer die nur die Werte 0 und 1 definiert sind,> andere Werte zurueckgegeben werden?
Es lässt sich aber in diesem Fall auch ohne Funktionen und irgendwelche
Rückgabewerte lösen. Wenn der OP in dem einen Fall anstelle der
Binärzahl wenigstens den Ausdruck mit dem Bitnamen hingeschrieben hätte,
wäre das ja auch schon einen Schritt besser.
Und wenn es wirklich nur zwei Zustände gibt, von denen einer Null ist
(und genau darum geht es hier), dann kann man sich den ganzen Rotz
tatsächlich sparen. Das verwirrt nur.
> Viel eher schiesst man sich in den Fuss, wenn man sich auch implizite> Konvertierungen verlaesst. Z.B., wenn als Fehler Werte <= 0 verwendet> werden und der Entwickler aus gewohnheit wieder mal if( doSomething())> schreibt...
Das ist ein ganz anderes Kapitel, und in dieser Hinsicht gebe ich Dir
Recht. Es geht hier nicht um eine Konvertierung, sondern lediglich um
eine Interpretation eines Wertes. In C wird eben nichts konvertiert,
da es eben auch keinen Datentyp bool gibt, in den man konvertieren
könnte.
Johannes M. wrote:
> Peter Stegemann wrote:>> Ob C oder C++ kann man so nicht sehen und in C++ gibt es bool. Einer der>> Gruende, warum man auch fuer C heute den C++-Compiler benutzen kann und>> sollte.> Anhand der Register- und Bitnamen handelt es sich vermutlich um einen> AVR, und für AVRs gibt es afaik noch keine "vernünftigen" C++-Compiler.
Bei gcc funktioniert zwar noch nicht alles, aber er ist durchaus
vernuenftig - und bool gehoert zu den Teilen, die funktionieren. Von
dem, was nicht funktioniert, vermisse ich nur virtuelle Methoden.
> Es lässt sich aber in diesem Fall auch ohne Funktionen und irgendwelche> Rückgabewerte lösen. Wenn der OP in dem einen Fall anstelle der> Binärzahl wenigstens den Ausdruck mit dem Bitnamen hingeschrieben hätte,> wäre das ja auch schon einen Schritt besser.
Welcher Bitname? Es geht hier um eine Funktion, die 1 oder 0 zurueck
gibt.
Peter Stegemann wrote:
> Welcher Bitname? Es geht hier um eine Funktion, die 1 oder 0 zurueck> gibt.
Es geht um eine Funktion, die man sich sparen kann! Und wenn man anstatt
0b10000000 einfach (1 << RXC) hinschreibt, dann ist das auch schon ein
Stück übersichtlicher...
Und selbst, wenn man die Funktion unbedingt haben und so schreiben will,
dass sie tatsächlich 0 oder 1 zurückgibt, kann man den Vergleich mit
"==" in der Funktion weglassen.
Fabian Ostner wrote:
> @Johannes :>> unsigned char temp;>> if((temp = USAT_check()))>>Das ist Unsinn.>> Warum ?
Die Zuweisung an sich ist kein Unsinn, das kann man in C durchaus so
machen, aber die Konklusio die du gezogen hast, das man das so machen
muss ist Unsinn.
So eine Zuweisung macht man nur dann, wenn man den Wert von temp in
weiterer Folge nochmal benötigt.
zb. sind Einleseschleifen oft so aufgebaut
1
while((c=readchar())!=EOF)
2
mach_irgendwas_mit_c;
die Zuweisung an der Stelle hat einfach nur den Zweck, das Zeichen
gleichzeitig in einer Variablen zu speichern UND
mit EOF zu vergleichen.
Würde man das nicht so machen, dann wäre die (gleichwertige) Alternative
1
c=readchar();
2
while(c!=EOF)
3
{
4
mach_irgendwas_mit_c;
5
c=readchar();
6
}
also deutlich länger UND der Aufruf der eigentlichen Lesefunktion muss
dupliziert werden.
Auch
1
do
2
{
3
c=readchar();
4
if(c!=EOF)
5
{
6
mach_irgendwas_mit_c;
7
}
8
}while(c!=EOF);
hat den Schönheitsfehler, dass hier die Abbruchbedingung doppelt
aufgeführt werden muss.
Warum ist 'doppelt' schlecht?
Weil man Gefahr läuft, dass man bei einer ev. Änderung nur 1 Änderung
macht und die andere Codestelle übersieht.
Eventuell könnte man noch
1
while(1)
2
{
3
c=readchar();
4
if(c==EOF)
5
break;
6
7
mach_irgendwas_mit_c;
8
}
machen. Puristen werden sich jedoch an der vermeintlichen Endlosschleife
stören bzw. daran, dass die Abbruchbedingung der Schleife mitten im
Schleifenrumpf versteckt ist.
Jo,
mit machen muß war auch nit so gemeint. Das mit der Rückgabe ohne eine
Zuweisung war mein Denkfehler.
Allerdings mache ich es grundsätzlich so (Angewohnheit), falls man mal
mehr als 1 oder 0 zurückgeben will (z.B bei else if oder switch
verweisen). Code bleibt eh der selbe.
Gruß
Fabian Ostner wrote:
> Jo,> mit machen muß war auch nit so gemeint. Das mit der Rückgabe ohne eine> Zuweisung war mein Denkfehler.> Allerdings mache ich es grundsätzlich so (Angewohnheit),Was machst du grundsätzlich so?
Ich hoffe jetzt mal, du meinst damit, dass du den expliziten Vergleich
weglässt und nicht dass du Funktionsergebnisse in Vergleichen in
Variablen auffängst.