Forum: Mikrocontroller und Digitale Elektronik Struct gut so?


von Stephan R. (Gast)


Lesenswert?

Moin!

Anfänger mit Atmega8 am Heulen:

PortB.0 soll TASTER, PortC.0 ne LED darstellen und auch so heissen. 
(Aufs Minimum reduziert)
Aus zahlreichen Treats habe ich folgendes zusammengestellt:

struct bits
{
  uint8_t b0:1;
  uint8_t b1:1;
  uint8_t b2:1;
  uint8_t b3:1;
  uint8_t b4:1;
  uint8_t b5:1;
  uint8_t b6:1;
  uint8_t b7:1;
};

#define BIT(r,n) (((volatile struct bits *)&r)->b##n)
#define TASTER BIT(PORTB, 0)
#define LED BIT(PORTC, 0)

DDRB = 0b00000000;     // PORTB als Eingang
DDRC = 0b11111111;     // PortB als Ausgang
PORTB = 0b11111111;           // PortB auf high schalten
PORTC = 0b00000000;           // PortB auf low schalten

int main(void)
{
        while (TASTER1)
  {
  LED = on;
  }
return 0;
}

Es funzt aber nicht. Wo könnte der Fehler liegen?

von Silvan K. (silvan) Benutzerseite


Lesenswert?

rofl. Dabei war der 1. April doch erst ;)
Spaß beiseite -- Welche Sprache soll das sein? C?
Schon ins AVR-GCC-Tutorial geschaut?

von holger (Gast)


Lesenswert?

>#define TASTER BIT(PORTB, 0)

#define TASTER BIT(PINB, 0)

von Stephan R. (Gast)


Lesenswert?

Japp, das soll 1A ANSI-C sein. Oder mal werden.
Im Moment ist Hauptsache, dass es funktioniert. Wenn es denn mal 
funktioniert.

@Holger: Danke für den PIN- Tipp!!

Prost!

von Silvan K. (silvan) Benutzerseite


Lesenswert?

Die Frage nach dem AVR-GCC-Tutorial bleibt offen...
Da wird das mit den Ports/Pins wie folgt gelöst:
1
int main(void) {
2
DDRB = 0x00    //Alle Eingänge (tut eigentlich nicht nötig!!)
3
DDRC = (1<<PC7)|(1<<PC6)|(1<<PC5)|(1<<PC4)|(1<<PC3)|(1<<PC2)|(1<<PC1)|(1<<PC0);
4
5
return 0;
6
}

^das schafft (mit ein paar Leerzeichen) viel Übersichtlichkeit, das 
solltest du dir angewöhnen!

oder so:
1
#define sbi(PORT, BIT) PORT=(1<<BIT)
2
3
int main(void) {
4
sbi(DDRC,PB1);
5
sbi(PORTC,PB1);
6
7
return 0;
8
}

von holger (Gast)


Lesenswert?

>oder so:
>
>#define sbi(PORT, BIT) PORT=(1<<BIT)

Fein, gleich mal den kompletten Port plattmachen;)

So geht das:

#define sbi(PORT, BIT) PORT |= (1<<BIT)

von Silvan K. (silvan) Benutzerseite


Lesenswert?

holger schrieb:
> Fein, gleich mal den kompletten Port plattmachen;)

Alta, es ist schon spät ;-D

von Stephan R. (Gast)


Lesenswert?

Scheiss Jägermeister. Hirn ist schon bissel träge..

Wo/wie benenne ich denn da ein PIN mit TASTER?

von Silvan K. (silvan) Benutzerseite


Lesenswert?

Jetzt kannst du aber auch mal ins AVR-GCC-Tutorial gucken. Oder müssen 
wir dir vorbeten, was Tausende vor dir schon fragten?

von holger (Gast)


Lesenswert?

>Wo/wie benenne ich denn da ein PIN mit TASTER?

#define TASTER (PINB &  1 << PB0)

von Stephan R. (Gast)


Lesenswert?

Ich hab´s ja quasi mit Hilfe des structs schon hinbekommen. Bei LED= on 
ging´s Lämpchen an...

Nur jetzt, wo ich mit Ein- UND Ausgängen arbeiten möchte, treten 
Probleme auf.
Werd mir wohl morgen wirklich mal das Tutorial eingehend vornehmen 
müssen...

von Stephan R. (Gast)


Lesenswert?

Holger, was heisst

sbi(DDRC,PB1);  ??

Setze Bit PortB1 im DDRC?

von Stephan R. (Gast)


Lesenswert?

Jägermeister alle :(

von holger (Gast)


Lesenswert?

>Holger, was heisst
>
>sbi(DDRC,PB1);  ??
>
>Setze Bit PortB1 im DDRC?


Nö, setze in DDRC das Bit das mit der Konstanten
PB1 definiert ist.

Aufgelöst:

DDRC |= 1<<1;

oder

DDRC |= 2;

von Stephan R. (Gast)


Lesenswert?

Was habt ihr alten Hasen nur dagegen, einem Bit einen Namen zu geben und 
ihm zu sagen "Du, Bit, bist jetzt ne 1!" ?!

Ich pick es nicht :(

von Silvan K. (silvan) Benutzerseite


Lesenswert?

Alter Hase? Ich bin 16!
Das hat Performance Gründe. Zudem ist es in ANSI-C (ich bin nicht 
sicher) nicht vorgeschrieben, dass das Struct auch nur den einen Bit 
verwendet. Für 8 Bit verpulverst du mal eben 8 Byte... Das ist aufm AVR 
ne Hausnummer.
Aber wie gesagt: ich bin nicht sicher!

von Stephan R. (Gast)


Lesenswert?

Für 8 Bit verpulvert Mann 8 Byte? (?)
Ich dachte, man kreiert extra einen 1-Bit-Datentyp, um Platz zu sparen!

von holger (Gast)


Lesenswert?

>Was habt ihr alten Hasen nur dagegen, einem Bit einen Namen zu geben und
>ihm zu sagen "Du, Bit, bist jetzt ne 1!" ?!

Nichts, viele Wege führen nach Rom.

#define LED_ON   sbi(PORTC, 0)
#define LED_OFF  cbi(PORTC, 0)

Da kannste auch ganz schnell wechseln wenn die LED an Plus hängt;)

#define LED_ON   cbi(PORTC, 0)
#define LED_OFF  sbi(PORTC, 0)

von Stephan R. (Gast)


Lesenswert?

Ein Lichtblick!!
Ja warum sagst Du das denn nicht gleich?

Aber zum Abschluss noch mal ne richtig doofe Frage. Achtung, festhalten!
Sie lautet:
Muss ich LED_ON wie eine Funktion aufrufen?

(Ich verstand #define bisher nur in der Art "#define PI 3.14159")

von ... (Gast)


Lesenswert?

1
int main(void)
2
{
3
  while (TASTER1)
4
  {
5
    LED = on;
6
  }
7
  return 0;
8
}

1) 'TASTER1' gibts nicht, wenn Dein Compiler Dir das nicht um die Ohren 
haut, schmeiß ihn weg

2) Preisfrage: Was macht Dein Programm wohl, wenn der Taster nicht 
gedrückt ist?

von Silvan K. (silvan) Benutzerseite


Lesenswert?

Jein. Bei einer Funktion siehts so aus:
1
function();

Bei #define kann es auch so aussehen:
1
#define LED_ON   sbi(PORTC, 0)
2
3
LED_ON;

oder mit anderen Worten: Bei einer Funktion folgt dem Bezeichner IMMER 
ein Klammer!!

von Stephan R. (Gast)


Lesenswert?

1) Warum gibts TASTER1 nicht?? (Ich hab sogar zwei!) Wenn er doch 
definiert ist?!

2) Denke, dein Miniprogramm berücksichtigt keine Nichtgedrückt..

von Silvan K. (silvan) Benutzerseite


Lesenswert?

Silvan König schrieb:
> 2) Preisfrage: Was macht Dein Programm wohl, wenn der Taster nicht
> gedrückt ist?

lol.

von Silvan K. (silvan) Benutzerseite


Lesenswert?

Silvan König schrieb:
> 1) Warum gibts TASTER1 nicht?? (Ich hab sogar zwei!) Wenn er doch
> definiert ist?!

Du hast TASTER definiert, aber nicht TASTER1.
Der Compiler ist pingelich!

von ... (Gast)


Lesenswert?

Stephan R. schrieb:
> 1) Warum gibts TASTER1 nicht?? (Ich hab sogar zwei!) Wenn er doch
> definiert ist?!

Wo ist er denn definiert? In Deinem ersten Post jedenfalls nicht! Und 
auch in keinem anderen.

Stephan R. schrieb:
> 2) Denke, dein Miniprogramm berücksichtigt keine Nichtgedrückt..

Das ist DEIN Programm nicht meins! Kennst Du Deine eigenen Posts nicht?

von Stephan R. (Gast)


Lesenswert?

Ich dreh gleich durch!
Was passt Mr. Compiler an

main (void)
{
  DDRC=  0xff;
  PORTC= 0xff;
  sbi (PORTC,0);
return 0;
}


nicht?? (undefined reference to sbi)

von ... (Gast)


Lesenswert?

Woher soll der Compiler wissen was 'sbi' ist? Hast Du ihm schließlich 
nicht gesagt.

von Stephan R. (Gast)


Lesenswert?

Ich hab ihm auch nicht gesagt was return ist!

von ... (Gast)


Lesenswert?

OK, wenn man es ganz genau nimmt ists dem Compiler eigentlich egal, der 
sollte nur eine Warnung ausspucken. Die Fehlermeldung stammt vom Linker, 
der nicht weis wo er die Implementation der Funktion sbi finden soll.

von Stephan R. (Gast)


Lesenswert?

Hab das sbi- Problem gelöst, hängt wohl mit dem Alter (/Neuer) meines 
Compilers zu tun.

Folgendes gefällt mir sehr gut und läuft auch:
#define led_on sbi(PORTC,1)


Nun möchte ich noch in der Art auch einen Eingang anfragen können.
#define led (PORTC,1)
funzt leider nicht. Was möchte Mr. Compiler da hören?

von ... (Gast)


Lesenswert?

Du solltest vielleicht erst mal ein gutes C-Buch lesen!
'return' ist ein im C-Sprachstandard definiertes Schlüsselwort, 'sbi' 
nicht!

von Stephan R. (Gast)


Lesenswert?

syntax error:

meinte #define taster (PINC, 0)

von ... (Gast)


Lesenswert?

An der Zeile ist erstmal nichts verkehrt. Ist absolut korrekter C-Code.

von Stephan R. (Gast)


Lesenswert?

Das finde ich -soweit beurteilbar- auch.
Hier mein gesamtes Programm:

#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>


#define led (PORTC, 1)
#define taster (PINC, 0)

void main (void)
{
  DDRC =  0b00000010;
  PORTC = 0x00000010;

  if (taster == 1)
  led = 1;
}

aber:   lvalue required as left operand of assignment

Ist er müde?

von ... (Gast)


Lesenswert?

1) Du solltest lernen hier im Forum Code-Tags zu verwenden
2) Du solltest Dir angewöhnen Deinen Sourcecode korrekt einzurücken

Spiel doch einfach mal selbst Präprozessor.
Du hast da ein "#define taster (PINC, 0)" stehen, also ersetzt Du in 
Deinem restlichen Code überall das Wort "taster" durch die Zeichenkette 
"(PINC, 0)" (ohne die Anführungsstriche). Und dann siehst Du auch was da 
rauskommt und was der Compiler dann nicht versteht.

von ... (Gast)


Lesenswert?

Noch vergessen:

3) Hier im Forum: NIEMALS Sourcecode abtippen! IMMER Copy&Paste 
benutzen!

von Silvan K. (silvan) Benutzerseite


Lesenswert?

Stephan R. schrieb:
> if (taster == 1)

An der Stelle setzt der Compiler (eigentlich der Präprozessor, aber wir 
wollns nicht übertreiben)
(PINC,0) ein.

Sieht also so aus:
1
if ( (PINC,0) == 1)

Das geht nicht!

Guck ins AVR-GCC-Tutorial!!!!
1
if ( bit_is_set(PORTC,0) )
2
{
3
  //tue dies und das
4
}

PS: ich müsste nachlesen, wie bit_is_set definiert ist. So wird der 
Compiler es aber nicht nehmen!!

von Stephan R. (Gast)


Lesenswert?

Hier, ein Paste (nicht abgetippt):

void main (void)
{
  DDRC =  0b11111110;
  PORTC = 0b00000000;

  if ((PINC, 0) == 0)
         sbi (PORTC, 1);

  if ((PINC, 0) == 1)
         cbi (PORTC,1);
}


Einziges Prob: Es läuft nix. LED ist an. Immer.

von Stephan R. (Gast)


Lesenswert?

mit bit_is_set läufts!! (Ein bissel erstmal)
Hab Dank!

von Stephan R. (Gast)


Lesenswert?

Wen´s interesiert, hier meine Lösung.

void main (void)
{
  DDRC =  0b11111110;
  PORTC = 0b00000001;

  while (1)
  {
  if (bit_is_set(PINC, 0))
  cbi (PORTC, 1);

  if (bit_is_clear(PINC,0))
  sbi (PORTC,1);
  }

}

Gute Nacht!

von ... (Gast)


Lesenswert?

Stephan R. schrieb:
> Einziges Prob: Es läuft nix. LED ist an. Immer.

Genau das, was Du progrmmiert hast.
OK wenn man ganz pingellig ist hängt das auch noch von der 
Compilerversion ab, entweder die LED ist tatsächlich immer an oder der 
µC wird ständig resettet und die LED flimmert (unsichtbar, da zu schnell 
fürs Auge).
1
((PINC, 0) == 0)
Dieser Ausdruck ist immer wahr!
1
((PINC, 0) == 1)
Dieser Ausdruck ist immer falsch!

Nachdem der Optimizer Dein Programm in der Fingenr hatte, bleibt davon 
nur noch folgendes übrig:
1
void main (void)
2
{
3
  DDRC =  0b11111110;
4
  PORTC = 0b00000000;
5
  sbi (PORTC, 1);
6
}
Und jetzt sollte Dir auch klar werden, warum Deine LED immer leuchtet.

von ... (Gast)


Lesenswert?

Huch, da war ich wohl zu langsam.
Das letzte sieht schon besser aus (bis auf die fehlenden Code-Tags hier 
fürs Forum und die mißratenen Einrückungen).

Das mit bit_is_set/bit_is_clear ist aber etwas doppelt gemoppelt. Wenn 
ein Bit gesetzt ist, ist es auf keinen Fall 'clear' und umgekehrt.
Anders gesagt, eins der beiden 'if's kann man sich sparen:
1
#include <avr/io.h>
2
#include <compat/deprecated.h>
3
4
void main (void)
5
{
6
  DDRC =  0b11111110;
7
  PORTC = 0b00000001;
8
9
  while (1)
10
  {
11
    if (bit_is_set(PINC, 0))
12
    {
13
      cbi (PORTC, 1);
14
    }
15
    else
16
    {
17
      sbi (PORTC,1);
18
    }
19
  }
20
}

von mal ne Frage (Gast)


Lesenswert?

Hi,

ich hätte da mal 'ne Frage zu:
>#define led_on sbi(PORTC,1)

spricht eigentlich was gegen leere Klammern? So wie das da:
#define LED_AN() sbi(PORTC, 1)

so mach ich das nämlich immer, dann kann ich die defines wie Funktionen 
aufrufen:

if (TASTET_IST_GEDRUECKT())
  LED_AN();
else
  LED_AUS();




...ok meist übertreibe ich etwas, dann sieht's etwa so aus:

#define PORT_LED_AUS PORTC
#define PORT_LED_EIN PINC
#define PORT_LED_OE  DDRC

#define BIT_LED_ROT   0
#define BIT_LED_GELB  1
#define BIT_LED_GRUEN 2


#define LED_AN()  SET_BIT(PORT_LED_AUS, BIT_LED_ROT)

von mal ne Frage (Gast)


Lesenswert?

oh Mist, 10-mal durchgelesen und doch noch Fehler:


TASTET_IST_GEDRUECKT() ist gedrückt sollte TASTER_IST_GEDRUECKT() 
heissen

SET_BIT(...) ist natürlich auch eine Definition:
#define SETBIT(XREG,XBIT)  XREG |= (1<<XBIT)


sorry

von mal ne Frage (Gast)


Lesenswert?

nee nee,

jetzt korrigiere ich nichts mehr!!!

von Silvan K. (silvan) Benutzerseite


Lesenswert?

Ich persönlich finde es übertrieben, aber ich habe gesehen, dass das in 
libs z.B. für das LCD des Nokia3310 genauso gemacht wird.

Daher würd ich sagen, es ist nicht übertrieben, sondern eine 
Notwendigkeit. Damit kannst du deine LEDs schneller neu sortieren.

von bla (Gast)


Lesenswert?

"spricht eigentlich was gegen leere Klammern? So wie das da:
#define LED_AN() sbi(PORTC, 1)"

Mault den der Compiler rum? Nein? Dann wirds wohl gehen.

von bla (Gast)


Lesenswert?

"Zudem ist es in ANSI-C (ich bin nicht
sicher) nicht vorgeschrieben, dass das Struct auch nur den einen Bit
verwendet. Für 8 Bit verpulverst du mal eben 8 Byte... Das ist aufm AVR
ne Hausnummer."

Gibt ja noch __attribute__((packed)). Ist zwar kein ANSI-C, aber der 
AVR-GCC-Compiler machts trotzdem.

von bla (Gast)


Lesenswert?

"Das hat Performance Gründe."

Wenn du mal in die Situation kommst, das du ein 60 seitiges Programm 
(ausgedruckt) von nem 8051 auf einen AVR übertragen musst, wird dir 
dieser Grund sicherlich recht schnell egal sein. Durch die Struktur sind 
dann 8051 übliche sbit Konstrukte wie:

 if(UEBERNAHME_PC_MC){ ... }

 TAKT_MC_PC=1;
 ...
 TAKT_MC_PC=0;

etc.

Möglich, ohne das du alle entsprechenden Stellen mit Makros wie 
TAKT_MC_PC_ON bzw TAKT_MC_PC_OFF ändern musst. Das macht nämlich nach 10 
Seiten keinen Spass mehr. Performance hin oder her.

Ansonsten stimme ich dir zu. Bei Programmen, die direkt für den AVR 
entwickelt werden sind Makros mit cbi() und sbi() definitiv die bessere 
Wahl.

von Thisamplifierisloud (Gast)


Lesenswert?

Ohne nahetreten zu wollen, empfehle ich Dir,
mal die Grundlagen in C draufzuschaffen,
statt punktuell Problemchen rauszupicken,
die dann irgendwie mit Hilfe eines Forums gelöst werden.

Gruß

TAIL

von Thisamplifierisloud (Gast)


Lesenswert?

bla schrieb:
> "spricht eigentlich was gegen leere Klammern? So wie das da:
> #define LED_AN() sbi(PORTC, 1)"
>
> Mault den der Compiler rum? Nein? Dann wirds wohl gehen.


Warum probierst Du´s nicht einfach aus ?
Geht schneller als auf ne Antwort zu warten.

:-)

von dagger (Gast)


Lesenswert?

bla schrieb:
>> Zudem ist es in ANSI-C (ich bin nicht
>> sicher) nicht vorgeschrieben, dass das Struct auch nur den einen Bit
>> verwendet. Für 8 Bit verpulverst du mal eben 8 Byte... Das ist aufm AVR
>> ne Hausnummer.
> Gibt ja noch __attribute__((packed)). Ist zwar kein ANSI-C, aber der
> AVR-GCC-Compiler machts trotzdem.
Das ist auch eine der vielen Gimmicks die der GCC mit sich bringt.
Manche Compiler kennen #pragma pack(n) siehe auch [1].

Wenn ich mich nicht irre, ignorieren Compiler unbekannte pragmas und ich 
weiß nicht, wie verbindlich _attribute_ und pragmas sind. Vielleicht 
sind das nur Empfehlungen für den Compiler und er kann sie, ähnlich wie 
inline bei Funktionen, ignorieren??

[1] 
http://www.hs-augsburg.de/~sandman/c_von_a_bis_z/c_017_011.htm#RxxobKap017011040029B21F01F18C

von bla (Gast)


Lesenswert?

dagger:

Ehrlich gesagt: Keine Ahnung. Ich habe zwar Vorlesungen wie 
Programmieren 1, Programmieren 2, und Microprozessortechnik gehört, aber 
auf µC spezifische Programmierung in C sind diese Vorlesungen leider 
nicht eingegangen. In Micorprozessortechnik haben wir 8051 in Assembler 
geproggt. Viel gebracht hat mir das nicht, weil ich voher schon mit dem 
8085 umgehen konnte.
Ich habe mich zusammen mit einem Mitschüler in den letzten 
Wochen/Monaten (Er: ca. 3 Monate. Ich: ca. 6 Wochen) eigenständig in das 
Thema eingearbeitet, da wir es beide für notwendig erachteten. Hier 
nochmal ein dickes Lob an die Autoren dieser Seite für ihre hilfreichen 
Tutorials!

Ich werde mich aber noch tiefer reinarbeiten. C von A bis Z steht hier 
im Regal nebem Kerningham/Ritchie. Danke für den Hinweis.

von Juergen (Gast)


Lesenswert?

Bitte keine C Bitfields benutzen, das macht auf die Dauer nur Probleme:

- Genaues Layout ist implementierungsabhängig, erschwert Portierung auf 
anderen Compiler / Prozessor

- Ein Sprachfeature mehr, dessen Feinheiten man sich merken muss und mit 
dem Neulinge Probleme bekommen

- Indizierter Zugriff ist nicht möglich (kein Array von 5 bits in einem 
Byte)

Benutzt Shift und Bitoperationen, da wisst ihr genau, was passiert.

von bla (Gast)


Lesenswert?

Juergen:

Stichhaltige Argumente, die auch richtig sind. Aber ich sehe das ganze 
so:

Man sollte schon wissen was Bitfelder sind, welche Vor- und Nachteile 
sie besitzen und wie man mit ihnen umgeht. Ihren Einsatz sollte man aber 
ähnlich sorgfältig durchdenken wie den Einsatz von goto oder globalen 
Variablen, denn manchmal können sie durchaus elegante und effektive 
Lösungen für Probleme sein.

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.