Warum ist das so? (USART)

Gast #1127087
Lesenswert?
• ▲
▼
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.
#1127106
Lesenswert?
• ▲
▼
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...
#1127112
Lesenswert?
• ▲
▼
Läubi Mail@laeubi.de wrote:
>
1
uint8_t USART_check(void)
2
> {
3
>    // Sind neue Daten im Buffer?
4
>    return (UCSRA & ( 1<<RXC));
5
> }
> 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...
#1127127
Lesenswert?
• ▲
▼
@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_t USART_check(void)
so abändern:
1
uint8_t USART_check(void)
2
{
3
    return 1;
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.
#1127135
Lesenswert?
• ▲
▼
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.
#1127140
Lesenswert?
• ▲
▼
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.
#1127168
Lesenswert?
• ▲
▼
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).
Gast #1127180
Lesenswert?
• ▲
▼
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
#1127187
Lesenswert?
• ▲
▼
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.
Gast #1127199
Lesenswert?
• ▲
▼
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...
#1127206
Lesenswert?
• ▲
▼
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.
Gast #1127225
Lesenswert?
• ▲
▼
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!
Gast #1127251
Lesenswert?
• ▲
▼
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...
#1127271
Lesenswert?
• ▲
▼
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.
Gast #1127286
Lesenswert?
• ▲
▼
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.
#1127291
Lesenswert?
• ▲
▼
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.
#1127458
Lesenswert?
• ▲
▼
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.
#1127470
Lesenswert?
• ▲
▼
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ß
#1127475
Lesenswert?
• ▲
▼
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren