mikrocontroller.net

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


Autor: Florian Brand (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Florian Brand (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag: Benutzte AVR Studio und programmmiere in C

Autor: SebA (Gast)
Datum:

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

Sebastian

Autor: Florian Brand (Gast)
Datum:
Angehängte Dateien:
  • led.txt (252 Bytes, 99 Downloads)

Bewertung
0 lesenswert
nicht 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...

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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-Tu...

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

Autor: Florian Brand (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: Florian Brand (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Florian Brand (Gast)
Datum:
Angehängte Dateien:
  • led.txt (258 Bytes, 98 Downloads)

Bewertung
0 lesenswert
nicht 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.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Michael Dreher (nospam2000)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Gerd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, dass
if ( PINB & (1<<PINB2) ) {

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

halte ich für ein Gerücht.

Autor: Roland Schmidt (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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>
          }
    }
}

Autor: Gerd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Michael Dreher (nospam2000)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Gerd (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.