Forum: Compiler & IDEs Anfänger sucht Fehler in vereinfachtem C-Code


von R. B. (britzi)


Lesenswert?

Hallo zusammen,

ich möchte meinen C-Code so einfach gestalten, wie möglich, so dass ich 
nur noch Stichwörter für Aktionen nutzen muss.

In folgendem Beispiel funktioniert alles, bis auf den Taster.
Ich habe schon verschiedene Funktionen getestet und weiß nicht, warum er 
nicht funktioniert.

Was ist falsch an meinem Code bzw. wie kann ich ihn korrigieren?


Vielen Dank für die Hilfe :-)


1
#include <avr/io.h>
2
3
#define LED1 PB0
4
#define KEY1 PINB2 
5
6
#define LED1_BIT (1<<LED1)
7
#define KEY1_BIT (1<<KEY1) 
8
9
#define LED1_on() PORTB |= LED1_BIT
10
#define LED1_off() PORTB &= ~LED1_BIT
11
#define LED1_toggle() PORTB ^= LED1_BIT
12
13
#define Test_Key1() (PINB &= KEY1_BIT)
14
#define Test_Key1_0() (PINB &= ~KEY1_BIT)
15
16
17
int main(void)
18
{ 
19
  DDRB = (1 << DDB0) | (1 << DDB1); 
20
  PORTB |= (1<<PB2)| (1<<PB3) ;    
21
while (1)
22
{  
23
  if (Test_Key1_0()) { 
24
    LED1_off();} 
25
  else{
26
    LED1_on(); 
27
}
28
  }
29
return 0;
30
}

von Lamy (Gast)


Lesenswert?

PINB &= ~KEY1_BIT => PINB = PINB  & (~KEY1_BIT)

ist eine Zuweisung und keine Abfrage.

von Lamy (Gast)


Lesenswert?

#define Test_Key1_0() (PINB & (~KEY1_BIT))

von Stefan E. (sternst)


Lesenswert?

Lamy schrieb:
> #define Test_Key1_0() (PINB & (~KEY1_BIT))

Nö, auch nicht. Das testet jetzt, ob irgendein Bit, ausgenommen 
KEY1_BIT, 1 ist.

von Roger (Gast)


Lesenswert?

R. B. schrieb:
> ich möchte meinen C-Code so einfach gestalten, wie möglich, so dass ich
> nur noch Stichwörter für Aktionen nutzen muss.

Halte ich für völlig unsinnig. Aber wenn du es gerne ganz einfach hast 
dann pack doch einfach deinen gesamten Code in ein Define.

von mar IO (Gast)


Lesenswert?

R. B. schrieb:
> #define LED1_BIT (1<<LED1)
> #define KEY1_BIT (1<<KEY1)
>
> #define LED1_on() PORTB |= LED1_BIT
> ...
> #define Test_Key1_0() (PINB &= ~KEY1_BIT)

Wie Taster und LED in einem???

von Peter II (Gast)


Lesenswert?

mar IO schrieb:
> Wie Taster und LED in einem???

beleuchteter Taster eventuell.

von Stefan E. (sternst)


Lesenswert?

mar IO schrieb:
> R. B. schrieb:
>> #define LED1_BIT (1<<LED1)
>> #define KEY1_BIT (1<<KEY1)
>>
>> #define LED1_on() PORTB |= LED1_BIT
>> ...
>> #define Test_Key1_0() (PINB &= ~KEY1_BIT)
>
> Wie Taster und LED in einem???

Wieso "in einem"?
1
#define LED1 PB0
2
#define KEY1 PINB2

von Lamy (Gast)


Lesenswert?

#define Test_Key1() (PINB & KEY1_BIT)

Testen auf 1:
 => Erg muss dann != 0

Testen auf 0:
 => Erg muss dann  = 0

von R. B. (britzi)


Lesenswert?

Ich habe den Fehler erkannt.
Ihr habt recht, die Zuweisung ist natürlich Blödsinn.

Dies ist mein richtiger Erstkontakt mit AVRs und in C bin ich auch 
Einsteiger.
Ich komme gerade leider nicht auf die richtige Lösung.



Roger schrieb:
> R. B. schrieb:
>> ich möchte meinen C-Code so einfach gestalten, wie möglich, so dass ich
>> nur noch Stichwörter für Aktionen nutzen muss.
>
> Halte ich für völlig unsinnig. Aber wenn du es gerne ganz einfach hast
> dann pack doch einfach deinen gesamten Code in ein Define.

Wieso ist es unsinnig, wenn man die Lesbarkeit deutlich erhöht?

von mar IO (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Wieso "in einem"?
> #define LED1 PB0
> #define KEY1 PINB2

Stimmt, da bin ich durcheinander gekommen. Ich hab's zwar gesehen, aber 
iwie. ignoriert. Da stand halt bei beiden eine 1 hinten...

von R. B. (britzi)


Lesenswert?

Lamy schrieb:
> #define Test_Key1() (PINB & KEY1_BIT)
>
> Testen auf 1:
>  => Erg muss dann != 0
>
> Testen auf 0:
>  => Erg muss dann  = 0



Vielen Dank für die Lösung, es funktioniert :-)

von Roger (Gast)


Lesenswert?

R. B. schrieb:
> Wieso ist es unsinnig, wenn man die Lesbarkeit deutlich erhöht?

Die kannst du genauso mit entsprechend benannten Funktionen erhöhen.

von R. B. (britzi)


Lesenswert?

Roger schrieb:
> R. B. schrieb:
>> Wieso ist es unsinnig, wenn man die Lesbarkeit deutlich erhöht?
>
> Die kannst du genauso mit entsprechend benannten Funktionen erhöhen.


Ja ok, ich denke du hast Recht.
Aber ist es nicht gehopst wie gesprungen?

von Dr. Sommer (Gast)


Lesenswert?

Wenn du C Code vereinfachen/eleganter machen willst - wirf C weg und 
nimm C++, damit geht das noch viel besser. Geeignete Implementation 
angenommen, z.B. so etwa:
1
Pin led1Pin (1 /* 1 = Port B */, 0);
2
Pin key1Pin (1 /* 1 = Port B */, 2);
3
4
int main () {
5
  led1Pin.setDirection (Direction::OUTPUT);
6
  key1Pin.setDirection (Direction::INPUT);
7
8
while (1)
9
{  
10
  led1Pin.setOutput (!key1Pin.getInput ());
11
  }
12
return 0;
13
}

von Peter II (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Wenn du C Code vereinfachen/eleganter machen willst - wirf C weg und
> nimm C++, damit geht das noch viel besser. Geeignete Implementation
> angenommen, z.B. so etwa:Pin led1Pin (1 /* 1 = Port B */, 0);
> Pin key1Pin (1 /* 1 = Port B */, 2);
>
> int main () {
>   led1Pin.setDirection (Direction::OUTPUT);
>   key1Pin.setDirection (Direction::INPUT);
>
> while (1)
> {
>   led1Pin.setOutput (!key1Pin.getInput ());
>   }
> return 0;
> }

und in C ist es ja so viel anders
1
struct Pin led1Pin = {1 /* 1 = Port B */, 0}; 
2
struct Pin key1Pin = {1 /* 1 = Port B */, 2}; 
3
4
int main () { 
5
  setDirection(led1Pin, DIR_OUTPUT); 
6
  setDirection(key1Pin, DIR_INPUT); 
7
8
  while (1) 
9
  { 
10
    setOutput(led1Pin, !getInput(key1Pin) ); 
11
  } 
12
return 0; 
13
}

von R. B. (britzi)


Lesenswert?

Dr. Sommer schrieb:
> Wenn du C Code vereinfachen/eleganter machen willst - wirf C weg und
> nimm C++, damit geht das noch viel besser.[/c]


Hatte ich auch überlegt, aber dann müsste ich noch C++ lernen und gerade 
im Bereich AVR gibt es für C++ im Gegensatz zu C nahezu keine 
Beispiele/Bücher/Tutorials oder andere Hilfen.

Von daher weiß ich nicht, was besser ist.
Wobei für mein Studium muss ich mich jetzt eh ein bisschen mit C++ 
beschäftigen.

von Dr. Sommer (Gast)


Lesenswert?

Peter II schrieb:
> und in C ist es ja so viel anders
Okay in dem Fall stimmts... Wobei du hier nicht in den Genuss des 
Typesafen enums kommst ;-)

von Dr. Sommer (Gast)


Lesenswert?

R. B. schrieb:
> Hatte ich auch überlegt, aber dann müsste ich noch C++ lernen und gerade
> im Bereich AVR gibt es für C++ im Gegensatz zu C nahezu keine
> Beispiele/Bücher/Tutorials oder andere Hilfen.
Das macht nix, der AVR-relevante Teil ist gleich zu C, und der C++ Teil 
ist gleich wie am PC, man muss nur ein bisschen mit der 
Speicherverwaltung aufpassen.

R. B. schrieb:
> Von daher weiß ich nicht, was besser ist.
> Wobei für mein Studium muss ich mich jetzt eh ein bisschen mit C++
> beschäftigen.
C++ zu lernen ist auf jeden Fall eine gute Idee, man lernt eine Menge 
abstrakter Konzepte, und darf danach Java-Leute auslachen ;-)

von Karl H. (kbuchegg)


Lesenswert?

R. B. schrieb:

> Wieso ist es unsinnig, wenn man die Lesbarkeit deutlich erhöht?

Es gibt oft einen Punkt, an dem sich die Lesbarkeit nicht mehr erhöht, 
sondern verschlechtert, weil du schon zu viele Details 'versteckt' hast.

spätestens wenn du anfängst, 5 verschiedene Makros zu erfinden, die alle 
eine 'Aktion' als Namenszusatz haben, solltest du dir überlegen, ob du 
den Punkt nicht schon überschritten hast.
Schau dir auch immer die Verwendung im Code an, ob der dann nicht schon 
zu dicht ist. Überleg dir auch, unabhängig davon ob und wie du das 
erreichen kannst, was für dich übersichtlicher Code wäre.

Meine Idealvorstellung würde zb so aussehen
1
int main(void)
2
{ 
3
  DDRB = (1 << DDB0) | (1 << DDB1); 
4
  PORTB |= (1<<PB2)| (1<<PB3) ;    
5
6
  while (1)
7
  {  
8
    if (Is_Key_Pressed( KEY_RED ) { 
9
      TurnOff( LED_RED );
10
    else
11
      TurnOn( LED_RED );
12
13
    if (Is_Key_Pressed( KEY_BLUE ) { 
14
      TurnOff( LED_BLUE );
15
    else
16
      TurnOn( LED_BLUE );
17
  }
18
19
  return 0;
20
}
(ignorier mal das Vorgeplänkel mit DDR)

So würde für mich Code aussehen, der leicht zu erfassen ist.
Und jetzt überleg ich mir, mit welchen Funktionen und/oder Makros ich 
auf dieses Ziel zusteuere.

D.h. ich fang hinten an. Beim Ergebnis. Das soll auf der einen Seite 
leicht zu lesen und zu erfassen sein, auf der anderen Seite aber die 
Sache auch nicht aufblähen. Mit 2 Funktionalitäten, der ich jeweils die 
Led vorgeben kann, kann ich auch 50 LED beackern, ohne mir da im 
Programm eine Makro-Orgie einzuhandeln, weil ich für jede LED einen 
Haufen Spezialmakros für ein/aus brauche.
Dasselbe für die Tasten.
Immer auch daran denken, wie etwas verallgemeinert. Eine Systematik
1
   Test_Key1_0()
verallgemeinert schlecht, ohne dass ich Millionen von Makros anlegen 
muss.

von R. B. (britzi)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Es gibt oft einen Punkt, an dem sich die Lesbarkeit nicht mehr erhöht,
> sondern verschlechtert, weil du schon zu viele Details 'versteckt' hast.
>
> Meine Idealvorstellung würde zb so aussehen...



Stimmt, das sehe ich vollkommen ein.
Auf den ersten Blick scheint mir deine Idealvorstellung nicht viel 
besser zu sein, aber dies liegt nur daran, dass ich nicht weiß, wie du 
die Funktionen definieren würdest und ich wieder auf meine Markos 
zurückgreifen würde.

Wenn du mir das alles als vollständiges Beispiel schreiben würdest, 
verspreche ich, mir genau diesen Stil anzugewöhnen ;)

Das wäre echt nett :-)

Vielen Dank!

von Ralf G. (ralg)


Lesenswert?

R. B. schrieb:
> Auf den ersten Blick scheint mir deine Idealvorstellung nicht viel
> besser zu sein, aber dies liegt nur daran, dass ich nicht weiß, wie du
> die Funktionen definieren würdest und ich wieder auf meine Markos
> zurückgreifen würde.

Warum Makro? Über so einen typischen Makro-Fallstrick bist du doch 
gerade gestolpert! Eine richtige Funktion. Schön übersichtlich. Und 
wenn's nur eine Zeile ist. Der Compiler macht da möglicherweise genau 
dasselbe Ergebnis daraus. Darin ist der ausgebildet ;-)

Edit: Vielleicht musst du ja mal was erweitern?
Funktion: Eine Zeile dazu.
Makro: ... (ob das noch übersichtlich ist?)

von R. B. (britzi)


Lesenswert?

Ja, ich habs verstanden ;-)

Funktionen sind einfacher und schöner.

Ich habe gerade mal probiert eine Funktion zu schreiben, die ein Makro 
nutzt und dann ein Bit setzen soll.

Leider funktioniert es nicht und ich weiß mal wieder nicht, woran es 
liegt.

Dies ist kein vollständiger C-Code, sondern nur die Stellen, die zu 
meinem Problem gehören. Sonst ist der Code wie weiter oben ;)
1
#define LED1 PB0,PORTB
2
3
int Set_On (int Anschluss, int Port)
4
  {Port |= (1<<Anschluss);
5
    }
6
int main(void)
7
{ 
8
Set_On(LED1); 
9
return 0;
10
}


Wo ist hier der Fehler?

Vielen Dank :-)

von Karl H. (kbuchegg)


Lesenswert?

R. B. schrieb:

> int Set_On (int Anschluss, int Port)
>   {Port |= (1<<Anschluss);
>     }

Ein Port Register kannst du nicht so erreichen

void Set_On (uint8_t Anschluss, volatile uint8_t* Port)
{
  *Port |= (1<<Anschluss);
}

> Wo ist hier der Fehler?

Auch wenn ich Funktionen grundsätzlich unterstütze. Wenn du die Namen 
von µC Registern übergeben musst, sind Makros an dieser Stelle 
ausnahmsweise besser.

von R. B. (britzi)


Lesenswert?

Karl Heinz Buchegger schrieb:
> void Set_On (uint8_t Anschluss, volatile uint8_t* Port)
> {
>   *Port |= (1<<Anschluss);
> }
>
> Auch wenn ich Funktionen grundsätzlich unterstütze. Wenn du die Namen
> von µC Registern übergeben musst, sind Makros an dieser Stelle
> ausnahmsweise besser.


Vielen Dank :-)

Ich habe das Sternchen hinter dem unit_8 mal and Port gerückt, aber 
dennoch bekomme ich Fehler beim Aufruf der Funktion, wenn ich sie mit 
LED1 aufrufe:

AVR.cpp:45: error: invalid conversion from 'volatile unsigned char' to 
'volatile uint8_t*'
1>  AVR.cpp:45: error:   initializing argument 2 of 'void 
Set_On(uint8_t, volatile uint8_t*)'


Woran liegt das?

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

R. B. schrieb:
> Woran liegt das?

Steht doch da! Zum Programmieren gehört auch Abstraktionsvermögen, und 
damit sollte man ein Beispiel wohl auf den konkreten Fall abbilden 
können. Sachen per C&P sowie T&E zu übernehmen ist bestenfalls 
frustrierend aber kein Programmieren.

von R. B. (britzi)


Lesenswert?

Läubi .. schrieb:
> R. B. schrieb:
>> Woran liegt das?
>
> Steht doch da! Zum Programmieren gehört auch Abstraktionsvermögen, und
> damit sollte man ein Beispiel wohl auf den konkreten Fall abbilden
> können. Sachen per C&P sowie T&E zu übernehmen ist bestenfalls
> frustrierend aber kein Programmieren.

Sorry,

aber für einen Anfänger, der noch nie was mit Informatik am Hut hatte, 
ist es ab und zu nicht gerade einfach Fehlermeldungen zu interpretieren 
und zum Thema C&P finde ich es ab und zu besser erstmal C&P zu machen, 
weil man so eine richtige Struktur lernt, während man sonst, wie ich es 
vorher gemacht habe, z.B. anfängt erstmal 1000 Makros zu schreiben.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

R. B. schrieb:
> ist es ab und zu nicht gerade einfach Fehlermeldungen zu interpretieren

Na dann ist jetzt der Zeitpunkt es zu lernen, was verstehst du den an 
der Meldung nicht?

R. B. schrieb:
> AVR.cpp

Wieso endet dein C-Code überhaupt auf cpp = i.A. Dateiendung für C++

von R. B. (britzi)


Lesenswert?

Läubi .. schrieb:
> Na dann ist jetzt der Zeitpunkt es zu lernen, was verstehst du den an
> der Meldung nicht?
>
> R. B. schrieb:
>> AVR.cpp
>
> Wieso endet dein C-Code überhaupt auf cpp = i.A. Dateiendung für C++


Ok,
also wenn ich unit8_t zu unsigned char ändere kommt derselbe Fehler nur 
dass es heißt invalid conversion from 'volatile unsigned char' to 
'volatile unsigned char*.

Es muss also was mit dem Sternchen für die Übergabe als Referenz zu tun 
haben. Aber warum ich das mit dem Sternchen hier nicht darf, verstehe 
ich nicht.

Und zu dem Initialisierungsfehler habe ich ehrlich gesagt keine Idee, 
wie er zustande kommt oder wie ich ihn beheben kann.


Und warum das auf .cpp endet und nicht auf .c liegt daran, dass ich nach 
einer Anleitung im Internet Visual Studio so konfiguriert habe, dass ich 
es für AVRs nutzen kann und da war es eben so beschrieben. Da C ja eine 
Untermenge von C++ ist, dürfte das ja nichts machen.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

R. B. schrieb:
> s muss also was mit dem Sternchen für die Übergabe als
> Referenz zu tun haben

Dann schau doch mal hier: 
Beitrag "Re: AVR-GCC "C" Port als Variablenwert ablegen und nutzen - ich komm einfach nicht drauf"

R. B. schrieb:
> Da C ja eine Untermenge von C++ ist

Das stimmt so auch nicht: 
http://stackoverflow.com/questions/1201593/c-subset-of-c-where-not-examples

von R. B. (britzi)


Lesenswert?

Läubi .. schrieb:
> Dann schau doch mal hier:
> Beitrag "Re: AVR-GCC "C" Port als Variablenwert ablegen und nutzen - ich komm einfach nicht drauf"


Ok, vielen Dank.
Ich habe jetzt alles mögliche probiert und mir auch den anderen Beitrag 
angesehen, aber leider keinen Erfolg gehabt.

Nach wie vor möchte ich, dass ich aus dem einen Makro mit dem Bezeichner 
LED die Variablen PB0 und Port übergebe und es klappt einfach hinten und 
vorne nicht.

Bei dem Port muss ja ein & davor und wenn ich das & schon vor den Port 
im Makro schreibe, funktioniert es nicht und wenn ich das & vor das LED1 
schreibe, dann bezeichnet es ja auch das PB0 und das ist ja auch falsch.

So oder so.... ich bekomme nur Fehlermeldungen und weiß nicht, wie ich 
es lösen soll.

Und ob ich nun schreibe
1
void Set_On (uint8_t Anschluss, volatile uint8_t *Port)
2
{Port= &Port;
3
  *Port = (1<<Anschluss);
4
}

oder
1
void Set_On (uint8_t Anschluss, volatile uint8_t *Port)
2
{
3
 *Port |= (1<<Anschluss);
4
}

ist doch im Prinzip dasselbe, oder nicht?

von Stefan R. (srand)


Lesenswert?

R. B. schrieb:
> ist doch im Prinzip dasselbe, oder nicht?

Kompiliers doch mal. Dann siehst du schon, daß Port= &Port; 
offensichtlich nicht funktionieren kann.

Wie soll Port denn zugleich von einem bestimmten Datentyp, und zugleich 
vom Typ "Pointer auf Datentyp" sein?

von R. B. (britzi)


Lesenswert?

Stefan Rand schrieb:
> R. B. schrieb:
>> ist doch im Prinzip dasselbe, oder nicht?
>
> Kompiliers doch mal. Dann siehst du schon, daß Port= &Port;
> offensichtlich nicht funktionieren kann.
>
> Wie soll Port denn zugleich von einem bestimmten Datentyp, und zugleich
> vom Typ "Pointer auf Datentyp" sein?



Ja ok... stimmt!
Ich sag ja, ich bin blutiger Anfänger sowohl mit C als auch mit AVRs ;-)

Gibt es denn nun eine elegante Möglichkeit mein "Problem" zu lösen?

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.