Forum: Compiler & IDEs Anfängerfrage zu µC programierung


von Florian Brand (Gast)


Lesenswert?

Hallo,

ich mache gerade erste experimente mit einem Atmega8 µC, aber kapiere
die programmierung von Ein- und Ausgängen einfach nicht.

Folgende Ausgangssituation:
An Port PD0 ist eine LED + Vorwiderstand gegen Masse angeschlossen. An
Port PB2 ist eine Lichtschranke angeschlossen die ein High Signal
liefert, solange sich nichts zwischen der Lichtschranke befindet.

Das Programm soll folgendes leisten: Wenn die Lichtschranke
unterbrochen wird (Low-Signal an PB2) soll die LED leuchten
(High-Signal an PD0).

Aber ich bekomme die Programmierung des Ein- und Ausgangs einfach nicht
hin.

von Florian Brand (Gast)


Lesenswert?

Nachtrag: Benutzte AVR Studio und programmmiere in C

von SebA (Gast)


Lesenswert?

Hallo Florian,
bei solchen Fragen kann ich dir nur das AVR-GCC-Tutorial oder
http://www.mikrocontroller.net/mc-project/ empfehlen.

Sebastian

von Florian Brand (Gast)


Angehängte Dateien:

Lesenswert?

Auf die Idee bin ich natürlich auch schon gekommen. :-)

Das Ergebnis habe ich mal als Anhang eingefügt. Ist aber eine von
mehreren Varianten die nicht funktioniert hat. Irgend was mache ich mit
der Abfrage des Eingangs falsch, zumindest zeigt dieser nie eine
Reaktion. Ausgang auf 1/0 setzten geht...

von Stefan (Gast)


Lesenswert?

Du setzt voraus, dass im ATMega8 der PORTB nach dem Power-On Reset
bereits als Eingang initialisiert ist. Ich kann jedenfalls keine
derartige Initialisierung in deinem Programm entdecken. Ansonsten sieht
das OK aus. Ein kleiner Schreibfehler bei der 1. PORTD Zuweisung, aber
der ist irrelevant.

Wie ist es auf der Hardwareseite? Alles richtig an die richtigen Pins
angeschlossen?

Hast du die Schaltung schon mit einem Taster plus Pullup-Widerstand
statt der Lichtschranke aufgebaut?

Also eine "Active Low" Beschaltung wie in
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Tasten_und_Schalter

Funktioniert die Lichtschranke am Oszi, hat sie einen sauberen
LOW-Pegel im Bereich der Spezifikation des AtMega8?

von Florian Brand (Gast)


Lesenswert?

Mmmh, dann vermute ich das die fehlende initialisiert des Eingangs das
Problem ist. Kann mir jemand sagen wie die in diesem Beispiel lauten
müsste?

Pinnbelegung sollte stimmen. Die Lichtschranke liefert saubere High/Low
Pegel (ist über einen Pull-Down Widerstand angeschlossen).

von Stefan (Gast)


Lesenswert?

Das steht einen Abschnitt unterhalb des bereits angegebenen Links zum
Tutorial. Die Datenrichtung im DDRx Register setzen (0 für Input) und
je nach Bedarf der externen Beschaltung PORTx die Pull-Up-Widerstände
aktivieren oder deaktivieren.

Du schreibst früher die Lichtschranke liefert ein HIGH Signal. Und
jetzt schreibst du, sie ist über einen Pull-Down Widerstand
angeschlossen. Das verstehe ich nicht. Ist deine Lichtschranke ein
simples "Taster" System aus LED und Fotoelement ohne weitere
Elektronik oder hat sie eine Elektronik zur Erzeugung der HIGH/LOW
Signale?

Ein Datenblatt der Lichtschranke bzw. Schaltbild deiner Schaltung wäre
jetzt nicht schlecht.

von Wolfram (Gast)


Lesenswert?

Was soll das
>PORTD=(1<<PB2);
damit schaltest du auf PortD für den 2. Pin den Pullup an (etwas
fehlerhaft formuliert)
kann es sein das die Lichtschranke einen Opencollector Ausgang hat und
du meintest
PORTB=(1<<PB2);
Pullup an PortB2 ?

von Florian Brand (Gast)


Lesenswert?

@Wolfram:

> Was soll das
>> PORTD=(1<<PB2);

Das war nur ein Tippfehler von mir. Außerdem hatte ich fälschlicher
Weise angenommen dadurch den Port B2 gleichzeitig als Eingang zu
definieren.

Aber wenn ich das richtig verstanden habe müsste die korrekte
Initalisierung lauten:
DDRB=(0<<PB2);

Werde das ganze morgen noch mal testen und berichten ob es geklappt
hat.

@Stefan:
Ich glaube da habe ich Pull-up und -down durcheinander bekommen. Bei
der Lichtschranke handelt es sich in der Tat um ein einfaches Modell
aus LED und Fototransistor (liefert im jetzigen Zustand dauerhaft High
und bei Unterbrechung Low).

Werde jetzt erst noch einmal testen, wenns nicht klappt liefere ich
Schaltpläne nach...

von Karl H. (kbuchegg)


Lesenswert?

> Das war nur ein Tippfehler von mir.

Es sind immer 'nur' die Tippfehler.
Poste immer das Programm, so wie du es kompilierst.
Dann suchen wir nicht nach Tippfehlern, die dir beim
Posten unterlaufen sind.

von Florian Brand (Gast)


Angehängte Dateien:

Lesenswert?

Juhu, jetzt funktionierts. Besten Dank! Scheinbar war das Problem
tatsächlich der nicht initialisierte Eingang.

Falls es jemanden interessiert habe ich das funktionierende Programm
nochmal angehängt.

von Karl heinz B. (kbucheg)


Lesenswert?

Das hier

DDRB=(0<<PB2);

macht gar nichts. So kann man ein Bit in einem
Byte nicht löschen. Daher kannst du dir das auch sparen
und durch

DDRB = 0;

ersetzen. Allerdings ist das im Grunde auch wieder
überflüssig, da die Port-Pins beim Einschalten eines ATMegas
automatisch auf 'Input' konfiguriert werden. Ich würds
allerdings drinnen lassen. Kostet zur Laufzeit nicht
wahnsinnig viel und dokumentiert explizit, dass PortB als
Eingang funktionieren soll.

von Michael D. (nospam2000)


Lesenswert?

Wenn Du das ganze noch eine Kleinigkeit umstellst, dann hilfst Du dem
Compiler das besser zu optimieren:

  while(1)
  {
    uint8_t x = PINB & (1<<PINB2);
    if (x)
    {
      PORTD |= (1<<PD0);
    }
    else
    {
      PORTD &= ~(1<<PD0);
    }
  }

Wenn man das Einlesen des Wertes direkt im if() macht, dann erzeugt der
Compiler deutlich längeren Code, da er 16-Bit Arithmetik verwendet (hier
eigentlich überflüssig). Das explizite Definieren von Variablen mit
möglichst kleinem Typ ist also nützlich.

von Gerd (Gast)


Lesenswert?

"Wenn man das Einlesen des Wertes direkt im if() macht, dann erzeugt
der Compiler deutlich längeren Code, da er 16-Bit Arithmetik verwendet
(hier eigentlich überflüssig). Das explizite Definieren von Variablen
mit möglichst kleinem Typ ist also nützlich."


Ja, das sag ich ja immer. Mir ist vor lanegr Zeit augefallen dass es
C-Programmierer offensichtlich lieben, Ausdrücke so kompakt wie möglich
zu formulieren - also soviel wie nöglich in eine Zeile reinzustopfen.
Das ist zum einen unfreundlich zu lesen und zum anderen macht so
mancher Compiler daraus ungenügend optimierten Kode.
Ausdrücke wie: if( (*StringPtr[e--][a++] )== *muellptr++  ) nicht nur
Augenunfreundlich sind ist nur Kosmetik, was der Compiler daraus macht
möchte ich gar nicht erst wissen. Debuggen möchte ich so ein Konstrukt
auch nicht.
Das Beispiel von Michael Dreher lässt sich im überflug lesen und
verstehen. IHMO, so sollte es sein.
Gerd

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Naja, dass
1
if ( PINB & (1<<PINB2) ) {

unfreundlicher zu lesen sein soll als
1
    uint8_t x = PINB & (1<<PINB2);
2
    if (x)

halte ich für ein Gerücht.

von Roland Schmidt (Gast)


Lesenswert?

Beides kompiliert mit GCC4.1.1.
Ich kann keinen Unterschied im erzeugten Code erkennen.

void mytest1(void) {
  68:  b2 9b         sbis  0x16, 2  ; 22
  6a:  02 c0         rjmp  .+4        ; 0x70 <mytest1+0x8>
  while(1)
    {
         uint8_t x = PINB & (1<<PINB2);
         if (x)
     //if (PINB & (1<<PINB2))
         {
          PORTD |= (1<<PD0);
  6c:  90 9a         sbi  0x12, 0  ; 18
  6e:  fc cf         rjmp  .-8        ; 0x68 <mytest1>
         }
         else
         {
          PORTD &= ~(1<<PD0);
  70:  90 98         cbi  0x12, 0  ; 18
  72:  fa cf         rjmp  .-12       ; 0x68 <mytest1>
         }
    }
}



void mytest1(void) {
  68:  b2 9b         sbis  0x16, 2  ; 22
  6a:  02 c0         rjmp  .+4        ; 0x70 <mytest1+0x8>
  while(1)
    {
          //uint8_t x = PINB & (1<<PINB2);
          //if (x)
      if (PINB & (1<<PINB2))
          {
          PORTD |= (1<<PD0);
  6c:  90 9a         sbi  0x12, 0  ; 18
  6e:  fc cf         rjmp  .-8        ; 0x68 <mytest1>
          }
          else
          {
          PORTD &= ~(1<<PD0);
  70:  90 98         cbi  0x12, 0  ; 18
  72:  fa cf         rjmp  .-12       ; 0x68 <mytest1>
          }
    }
}

von Gerd (Gast)


Lesenswert?

Meine Beobachtung war doch recht allgemein gültig gehalten und ohne
direktem Bezug zu DEINEN KODE. Jedenfalls mögen Compiler auch lieber
weiter aufgelöste Formulierungen. Was in PC Umgeben mit viel Speicher
und leistungsfähigen CPU's kein Problem ist, führt bei Embedded
Systems schnell in die Sackgasse.
Das Beispiel von Michael Dreher sieht jedenfalls recht übersichtlich
aus - nicht nur für den Compiler.

von Michael D. (nospam2000)


Lesenswert?

Mit avr-gcc (GCC) 3.4.6 sieht es mit Optimierung -Os und mit dem if(x)
Konstrukt genauso aus, wie von Roland Schmidt beschrieben:

33:           if (x)
+00000043:   9B82        SBIS    0x10,2           Skip if bit in I/O
+00000044:   C002        RJMP    PC+0x0003        Relative jump
35:             PORTB |= (1<<PB0);
+00000045:   9AC0        SBI     0x18,0           Set bit in I/O
register
+00000046:   CFFB        RJMP    PC-0x0004        Relative jump
39:             PORTB &= ~(1<<PB0);
+00000047:   98C0        CBI     0x18,0           Clear bit in I/O
+00000048:   CFF9        RJMP    PC-0x0006        Relative jump


Leider war die Optimierung der alten gcc Version noch nicht so gut,
daher kam ohne Verwendung der Hilfsvariablen x folgendes raus:
34:           if(PIND & (1<<PIND2))
+00000043:   B380        IN      R24,0x10         In from I/O location
+00000044:   2799        CLR     R25              Clear Register
+00000045:   9596        LSR     R25              Logical shift right
+00000046:   9587        ROR     R24              Rotate right through
carry
+00000047:   9596        LSR     R25              Logical shift right
+00000048:   9587        ROR     R24              Rotate right through
carry
+00000049:   7081        ANDI    R24,0x01         Logical AND with
immediate
+0000004A:   7090        ANDI    R25,0x00         Logical AND with
immediate
+0000004B:   2388        TST     R24              Test for Zero or
Minus
+0000004C:   F011        BREQ    PC+0x03          Branch if equal
36:             PORTB |= (1<<PB0);
+0000004D:   9AC0        SBI     0x18,0           Set bit in I/O
+0000004E:   CFF3        RJMP    PC-0x000C        Relative jump
40:             PORTB &= ~(1<<PB0);
+0000004F:   98C0        CBI     0x18,0           Clear bit in I/O
+00000050:   CFF1        RJMP    PC-0x000E        Relative jump

von Gerd (Gast)


Lesenswert?

Die kleineren Mcontroller Compiler nehmen solche Konstrukte oft übel.
Bei schnellen CPU Kernen mag es nicht auffallen und wird heufig
vernachlässigt. Wenn jedoch um jedes Byte Code gekämpft werden muss da
evtl der Takt nicht so groß ist, der Speicherplatz knapp wird,  können
solche "wirklich unauffällige Stellen" zum Sparen der Resourcen
erheblich beitragen. Nun ist das Beispiel der Debatte nicht gerade
eines der jenigen die sich der Kritk beugen müssen unleserlich zu sein,
jedoch ist gerade dieses simple Beispiel dafür sehr gut geeignet zu
demonstrieren wie unauffällig Konstrukte sein können die ungünstig für
den Compiler sein können.

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.