Forum: Mikrocontroller und Digitale Elektronik AVR C - Rückgabewert von Funktion nicht richtig


von J. B. (jbme)


Lesenswert?

Hallo zusammen,

ich habe folgenden Code, der in der while-Schleife hängen bleibt (auch 
wenn ENFG = 1 ist):
1
void at90can_can_controller_activate(void)
2
{
3
  // -- CAN General Control Register --
4
  CANGCON |= (1 << ENASTB);  // enable mode -> activate CAN controller
5
  //wait for controller to be enabled  
6
        while(at90can_can_controller_get_status() != 1);
7
}
8
9
uint8_t at90can_can_controller_get_status(void)
10
{
11
  return CANGSTA & (1 << ENFG);
12
}
Füge ich jetzt die Abfrage direkt ein, dann funktioniert es:
1
void at90can_can_controller_activate(void)
2
{
3
  // -- CAN General Control Register --
4
  CANGCON |= (1 << ENASTB);  // enable mode -> activate CAN controller
5
  //wait for controller to be enabled  
6
        while(CANGSTA & (1 << ENFG) != 1);
7
}
Hat jemand eine Erklärung dafür?
Danke im vorraus!

von Stefan F. (Gast)


Lesenswert?

Wenn
> ENFG = 1
ist, dann ist
> (1 << ENFG)
gleuch 2, und
> CANGSTA & (1 << ENFG)
ist immer entweder 0 oder 2, so dass
> at90can_can_controller_get_status() != 1
immer wahr ist.

von my2ct (Gast)


Lesenswert?

J. B. schrieb:
> Hat jemand eine Erklärung dafür?

> CANGSTA & (1 << ENFG)

Das ist ein boolscher Ausdruck. Warum vergleichst du den mit 1?
Ist bei die im System true als 1 definiert?
Portierbar ist etwas anderes.

Beitrag #6507018 wurde von einem Moderator gelöscht.
von Stefan F. (Gast)


Lesenswert?

my2ct schrieb:
> Das ist ein boolscher Ausdruck.

Falls du das & meinst: Nein, das ist eine bitweise Verknüpfung:4

1
    CANGSTA = 2 = 0b00000010
2
(1 << ENFG) = 2 = 0b00000010
3
                 ------------
4
Ergebnis von &:   0b00000010

Das Ergebnis ist 2, wenn beide Operanden = 2 sind. Und zwei ist wahr, 
wenn man es in einem booleschen Ausdruck verwendet. Kleiner Test mit 
if():

1
#include <stdio.h>
2
3
int main()
4
{
5
    int ENFG=1;
6
    
7
    int CANGSTA=0;
8
    if (CANGSTA & (1 << ENFG))
9
    {
10
        printf("CANGSTA=0 ist wahr \n");
11
    }
12
    
13
    CANGSTA=1;
14
    if (CANGSTA & (1 << ENFG))
15
    {
16
        printf("CANGSTA=1 ist wahr \n");
17
    }
18
    
19
    CANGSTA=2;
20
    if (CANGSTA & (1 << ENFG))
21
    {
22
        printf("CANGSTA=2 ist wahr \n");
23
    }
24
}

Erzeugt die Ausgabe:
1
CANGSTA=2 ist wahr


Aber: Beim TO ist das kein Boolescher Ausdruck. Er liefert das Ergebnis 
als uint8_t zurück. Deswegen ist sein Ergebnis immer 0 oder 2, also 
niemals 1.

von Peter D. (peda)


Lesenswert?

J. B. schrieb:
> while(CANGSTA & (1 << ENFG) != 1);
> Hat jemand eine Erklärung dafür?

Weil das was völlig anderes macht.
Zuerst wird != ausgeführt, danach erst das &.

https://en.cppreference.com/w/c/language/operator_precedence

von Rolf M. (rmagnus)


Lesenswert?

J. B. schrieb:
> uint8_t at90can_can_controller_get_status(void)

Sinnvoll wäre, den Rückgabetyp in bool zu ändern.

von STK500-Besitzer (Gast)


Lesenswert?

Rolf M. schrieb:
> J. B. schrieb:
>> uint8_t at90can_can_controller_get_status(void)
>
> Sinnvoll wäre, den Rückgabetyp in bool zu ändern.

oder auf != 0 zu testen

von Stefan F. (Gast)


Lesenswert?

STK500-Besitzer schrieb:
> oder auf != 0 zu testen

Das Pendant zu != 1 wäre == 0.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

J. B. schrieb:
> Füge ich jetzt die Abfrage direkt ein, dann funktioniert es:
Wenn du "bleibt nicht hängen" als "funktioniert es" definierst, dann 
schon.

J. B. schrieb:
> auch wenn ENFG = 1 ist
ENFG ist laut Datenblatt das Bit 2 im Register CANGSTA und damit ist der 
#define ENFG auch immer 2.
Du meinst vermutlich den Pegel des Flags ENFG.

Peter D. schrieb:
> Zuerst wird != ausgeführt, danach erst das &.
Und weil 1<<2 = 4 und damit 4 != 1 ist, ist das Ergebnis dieses 
Vergleichs 1. Und deshalb wird mit der Abfrage:
while(CANGSTA & (1 << ENFG) != 1);
tatsächlich das abgefragt:
while(CANGSTA & 1);
und das betrifft das ERRP Bit, das nur dann 1 wird, wenn der Controller 
in den Fehlermodus geht.

@  J. B. (jbme)
Im Grunde musst du deine Abfrage also so schreiben, dann passiert das, 
was du eigentlich wollltest:
while( (CANGSTA&(1<<ENFG)) != (1<<ENFG) );

Und natürlich musst du diese Geschichte auch bei dem 
Funktionsrückgabewert beachten.

my2ct schrieb:
>> CANGSTA & (1 << ENFG)
> Das ist ein boolscher Ausdruck.
Du verwechselst das binäre "&" mit dem logischen "&&"

von J. B. (jbme)


Lesenswert?

Vielen Dank für eure Antworten! Ich habe meinen Code entsprechend 
angepasst:
1
void at90can_can_controller_activate(void)
2
{
3
  // -- CAN General Control Register --
4
  CANGCON |= (1 << ENASTB);  // enable mode -> activate CAN controller
5
  //wait for controller to be enabled  
6
  while(at90can_can_controller_get_status() == false);
7
}
1
bool at90can_can_controller_get_status(void)
2
{
3
  return CANGSTA & (1 << ENFG);
4
}

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

J. B. schrieb:
> return CANGSTA & (1 << ENFG);
Diese Rechung ergibt 4, wenn das ENFG Flag gesetzt ist.
Wenn aber ein bool mit 1=true und 0=false ist, was ist dann mit diesen 
4?

Wenn du also schon einen boolschen Rückgabewert definierst, dann 
solltest du korrekterweise auch einen boolschen Wert für die Rückgabe 
berechnen:
1
return (CANGSTA & (1<<ENFG)) != 0; // gibt true zurück, wenn das Flag gesetzt ist

Und dann liest sich sowas natürlich doof:
1
if (at90can_can_controller_get_status() == false)
Wenn du das nämlich in einem Jahr liest, dann denkst du dir:
Was zum Senkel soll denn an dem Controllerstatus "falsch" oder "wahr" 
sein?

von J. B. (jbme)


Lesenswert?

Tatsächlich habe ich nachdem ich meinen vorherigen Beitrag geschrieben 
habe nochmals umgeändert, weil ich mir genau das, was du erwähnt hast, 
auch gedacht habe...

NOCHMAL EIN DICKES DANKESCHÖN!

von Stefan F. (Gast)


Lesenswert?

>> return CANGSTA & (1 << ENFG);

Lothar M. schrieb:
> Diese Rechung ergibt 4, wenn das ENFG Flag gesetzt ist.
> Wenn aber ein bool mit 1=true und 0=false ist, was ist dann mit diesen
> 4?

Er liefert true zurück, wenn der Ausdruck wahr ist. Und 4 ist wahr.

Das ist eine Besondertheit bei bool.

Beitrag #6507765 wurde von einem Moderator gelöscht.
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Stefan ⛄ F. schrieb:
> Er liefert true zurück, wenn der Ausdruck wahr ist.
Es wird "false" zurückgegeben, wenn der arithmetische Wert == 0 ist.
Und sonst kommt "true" zurück.

> Und 4 ist wahr.
Es ist nicht "falsch". Glück gehabt...  ;-)

von Stefan F. (Gast)


Lesenswert?

Lothar M. schrieb:
> Es ist nicht "falsch". Glück gehabt...  ;-)

Ja. Ich habe mir das so gemerkt: Alle Zahlen die nicht 0 sind, sind 
wahr.

Oder meinetwegen auch "nicht falsch".

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.