www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Wie kann ich folgenden C-Code mit einer Schleife kürzer machen?


Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

wie das Thema schon sagt, ich möchte gerne meinen C-Code mit einer 
Schleife verkürzen. Aber ich weiß keine Möglichkeit, die Ausgänge PDn 
durch eine Variable zu ersetzen. Wie geht sowas?

Danke ;-)


        PORTD |= (1 << PD0); //  aktivieren 
        _delay_ms(pause); 
        PORTD &= ~(1 << PD0); //  deaktivieren 

        PORTD |= (1 << PD1); //  aktivieren 
        _delay_ms(pause); 
        PORTD &= ~(1 << PD1); //  deaktivieren 

        PORTD |= (1 << PD2); //  aktivieren 
        _delay_ms(pause); 
        PORTD &= ~(1 << PD2); //  deaktivieren 

        PORTD |= (1 << PD3); //  aktivieren 
        _delay_ms(pause); 
        PORTD &= ~(1 << PD3); //  deaktivieren 

        PORTD |= (1 << PD4); //  aktivieren 
        _delay_ms(pause); 
        PORTD &= ~(1 << PD4); //  deaktivieren 

        PORTD |= (1 << PD5); //  aktivieren 
        _delay_ms(pause); 
        PORTD &= ~(1 << PD5); //  deaktivieren 

        PORTD |= (1 << PD6); //  aktivieren 
        _delay_ms(pause); 
        PORTD &= ~(1 << PD6); //  deaktivieren 

        PORTD |= (1 << PD7); //  aktivieren 
        _delay_ms(pause); 
        PORTD &= ~(1 << PD7); //  deaktivieren 

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
void loop()
{
  uint8_t mask = 0x01;

  PORTD = 0;
  do{
    PORTD |= mask;
    _delay_ms( pause );
    PORTD ^= mask;
    mask <<= 1;
  }while( mask );
}


Peter

Autor: Floh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian W. schrieb:
> Wie geht sowas?

Du willst praktisch ein Lauflicht machen?
Dann geht das so ganz gut:

PORTD = (1<<PD0); //erste LED

for(uint8_t i=0; i<8;i++)
{
   _delay_ms(pause);
  PORTD <<= 1;    //eins weiterschieben
}

:-)

Autor: Oliver Ju. (skriptkiddy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Irgendwo im io-header steht:

#define PD0 0
#define PD1 1
#define PD2 2
...

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und zusätzlich, indem du _delay_ms mit einer Konstanten aufrufst. 
Notfalls mit '1' aufrufen und in einer Schleifen ausführen. Steht aber 
auch ausführlich in der Doku.

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke für die zahlreichen nachrichten. ich probiers mal aus ;-)

Skript Kiddy schrieb:
> Irgendwo im io-header steht:
>
> #define PD0 0
> #define PD1 1
> #define PD2 2
> ...

aha, dann kann ich also mit dieser methode jedem I/O pin einen 
beliebigen namen geben?

Autor: Lukas K. (carrotindustries)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Skript Kiddy schrieb:
> Irgendwo im io-header steht:
>
> #define PD0 0
> #define PD1 1
> #define PD2 2
> ...

Nein, es heißt
#define PD0 (1<<0)
#define PD1 (1<<1)
#define PD2 (1<<2)

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

Bewertung
0 lesenswert
nicht lesenswert
Luk4s K. schrieb:
> Skript Kiddy schrieb:
>> Irgendwo im io-header steht:
>>
>> #define PD0 0
>> #define PD1 1
>> #define PD2 2
>> ...
>
> Nein, es heißt
> #define PD0 (1<<0)
> #define PD1 (1<<1)
> #define PD2 (1<<2)


Das wage ich zu bezweifeln :-)

Autor: mampf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stimmt aber.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mampf schrieb:

> Stimmt aber.

Welcher Compiler? Atmels und damit auch GCCs Konvention ist
  #define PD2 2

Autor: Lukas K. (carrotindustries)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Das wage ich zu bezweifeln :-)

Ahh, stimmt ich bin MSP430 geschädigt ;) Da wird man ja noch ganz 
wuschig im Kopf von

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

Bewertung
0 lesenswert
nicht lesenswert
Christian W. schrieb:
> danke für die zahlreichen nachrichten. ich probiers mal aus ;-)
>
> Skript Kiddy schrieb:
>> Irgendwo im io-header steht:
>>
>> #define PD0 0
>> #define PD1 1
>> #define PD2 2
>> ...
>
> aha, dann kann ich also mit dieser methode jedem I/O pin einen
> beliebigen namen geben?

Kannst du. Sollst du sogar.
Also jetzt nicht in deinem Lauflichtbeispiel, da ist das sinnlos. Aber 
im Allgemeinen macht das schon Sinn

zb
#define RED_LED_DDR      DDRD
#define RED_LED_PORT     PORTD
#define RED_LED_BIT      PD1

#define ERROR_LED_DDR    DDRD
#define ERROR_LED_PORT   PORTD
#define ERROR_LED_BIT    PD0


int main()
{
  RED_LED_DDR |= ( 1 << RED_LED_BIT );
  ERROR_LED_DDR |= ( 1 << ERROR_LED_BIT );

  // alle LED aus (auf 1 schalten)
  RED_LED_PORT |= ( 1 << RED_LED_BIT );
  ERROR_LED_PORT |= ( 1 << ERROR_LED_BIT );

  while( 1 ) {

    if( irgendwas ) {
      ERROR_LED_PORT &= ~( 1 << ERROR_LED_BIT );
    }

    RED_LED_PORT ^= ( 1 << RED_LED_BIT );
    _delay_ms( 100 );
  }
}

wenn sich aus irgendeinem Grund die Notwendigkeit ergibt, dass zb die 
rote LED an einen anderen Port wandern muss, dann brauchst du nur bei 
den #define die neue Belegung eintragen und den Rest macht der Compiler.

Ausserdem ist viel klarer, was bei
   RED_LED_PORT |= ( 1 << RED_LED_BIT );
passiert. Im Code steht hier explizit, dass da was mit der roten LED 
(und nicht mit der Error LED) gemacht wird. Bei

   PORTD |= ( 1 << PD1 );

müsste man erst mühsam raussuchen, dass hier etwas mit der roten LED 
unternommen wird.

Autor: mampf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Richtig. Bei PD1 und PD2 ist es ja noch nicht kritisch. Bei PD3 
allerdings wird sicherlich nicht 3 stehen, sondern 4... Das ist doch der 
Witz! ;-)

Autor: Lukas K. (carrotindustries)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mampf schrieb:
> Richtig. Bei PD1 und PD2 ist es ja noch nicht kritisch. Bei PD3
> allerdings wird sicherlich nicht 3 stehen, sondern 4... Das ist doch der
> Witz! ;-)

Falsch. Es wird die Bitnummer bezeichnet, nicht der Wert des Bits.

Autor: mampf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stimmt. Gut. Sorry.

Autor: Lukas K. (carrotindustries)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mampf schrieb:
> Stimmt. Gut. Sorry.

Fassen wir zusammen: Es gibt zwei Varianten Bits zu definieren
AVR-Stil:
Im Header:
#define PD0 0
#define PD1 1
Im Quelltext
#define PD0 0
PORTD |= (1<<PD1);

MSP430-Stil:
Im Header:
#define PD0 0
#define P0 (1<<0)
#define P1 (1<<1)
Im Quelltext:
#define PD0 0P1OUT |= P0;

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

Bewertung
0 lesenswert
nicht lesenswert
Luk4s K. schrieb:
> mampf schrieb:
>> Stimmt. Gut. Sorry.
>
> Fassen wir zusammen: Es gibt zwei Varianten Bits zu definieren

Eigentlich kann man das so nicht sagen.

Der Unterschied ist ganz einfach der

die einen haben Konstanten die die Bitnummer bezeichnen mit der die 
einzelnen BIts angesprochen werden.
die anderen haben KOnstanten für die Werte, die an einen Port 
geschrieben werden müssen um ein bestimmtes Bit zu verändern.

Es ist einfach nur eine andere Sichtweise darüber was wichtig ist:
die Bitnummer oder die Bitmaske

wobei man pikanterweise aus der Bitnummer die Maske leicht generieren 
kann, während es nicht einfach ist aus der Bitmaske auf die Bitnummer zu 
kommen. Wobei man fairerweise auch zugeben muss, dass man die Bitnummer 
als solche eher selten braucht


> AVR-Stil:
> Im Header:
>
#define PD0 0
> #define PD1 1
> Im Quelltext
>
#define PD0 0
> PORTD |= (1<<PD1);
>
> MSP430-Stil:
> Im Header:
>
#define PD0 0
> #define P0 (1<<0)
> #define P1 (1<<1)
> Im Quelltext:
>
#define PD0 0P1OUT |= P0;

Das ist zwar gut gedacht und ich bin überzeugt du meinst auch das 
Richtige, aber wenn man genauer hinsieht hast du da ziemlichen Unsinn 
zusammengeschrieben.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:

> kommen. Wobei man fairerweise auch zugeben muss, dass man die Bitnummer
> als solche eher selten braucht

Da die gleichen Header-Definitionen auch für Assembler verwendet werden, 
und es bei AVRs Befehle mit Bitnummer gibt, ist die Angabe der Nummer an 
Stelle der Maske ziemlich wesentlich.

Bei den STM32 ist es leider üblich, in den Headers Masken zu verwenden. 
Allerdings können die Cortex-M3 über Bitbanding alle Steuerregister 
bitweise ansprechen, wozu man aber an Stelle der Maske die Bitnummer 
benötigt. Die Folge: ein ellenlanger ?: Konvertierungsmakro, der vom 
Compiler wegoptimiert werden muss.

Autor: Lukas K. (carrotindustries)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich verbessere (ist wohl beim copy&paste was schiefgelaufen)
Luk4s K. schrieb:
> mampf schrieb:
>> Stimmt. Gut. Sorry.
>
> Fassen wir zusammen: Es gibt zwei Varianten Bits zu definieren
> AVR-Stil:
> Im Header:
>
#define PD0 0
 #define PD1 1
> Im Quelltext
>
 PORTD |= (1<<PD1);
>
> MSP430-Stil:
> Im Header:
>
 #define P0 (1<<0)
 #define P1 (1<<1)
> Im Quelltext:
P1OUT |= P0;

jetzt passt's aber hoffentlich :)

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
so, damit die verwirrung bei mir nicht allzu groß wird, mach ich selbst 
mal ein beispiel aus den oben genannten vorschlägen, vielleicht ist es 
ja richtig (grins)
#define LED_1_PORT     PORTD
#define LED_1_BIT      PD1

#define LED_2_PORT     PORTB
#define LED_2_BIT      PB6

#define LED_3_PORT     PORTC
#define LED_3_BIT      PC3

#define LED_4_PORT     PORTC
#define LED_4_BIT      PC4

#define LED_5_PORT     PORTC
#define LED_5_BIT      PC5

#define LED_6_PORT     PORTD
#define LED_6_BIT      PC2

#define LED_7_PORT     PORTD
#define LED_7_BIT      PC3

#define LED_8_PORT     PORTD
#define LED_8_BIT      PC4

// Lauflicht-Schleife
for(uint8_t n=0; n<8; n++)
{
   // Strings zusammensetzen
   PORT = "LED" & n & "PORT";
   BIT = "LED" & n & "BIT";

   // Port und Pin ansteuern
   PORT |= (1<<BIT);

   // Warten
   _delay_ms(pause);

   // Port und Pin deaktivieren
   PORT &= ~(1<<BIT);
}


So richtig?

Christian

Autor: Oliver Ju. (skriptkiddy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
autsch...

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Skript Kiddy schrieb:
> autsch...
ja danke auch für die antwort...! (kopfschüttel)

Autor: trallala (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian W. schrieb:
> // Strings zusammensetzen
>    PORT = "LED" & n & "PORT";
>    BIT = "LED" & n & "BIT";

das is ma geil XD

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>    _delay_ms(pause);

Man sieht leider im Codefetzen nicht wie pause definiert ist.

Schau dir das Thema Variablen vs. Konstanten beim Aufruf der 
Delay-Funktionen noch in der avr-libc Doku an.

Die Übergabe von IO-Register und Pinnummer an eine Funktion kannst du in 
diesem Beispiel abschauen:

http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan B. schrieb:
>>    _delay_ms(pause);
>
> Man sieht leider im Codefetzen nicht wie pause definiert ist.
>
> Schau dir das Thema Variablen vs. Konstanten beim Aufruf der
> Delay-Funktionen noch in der avr-libc Doku an.
>
> Die Übergabe von IO-Register und Pinnummer an eine Funktion kannst du in
> diesem Beispiel abschauen:
>
> 
http://www.mikrocontroller.net/articles/AVR-GCC-Tu...


Das ist kein Codefetzen, mehr davon gibt es noch gar nicht, ist nur so 
ein Versuch, ich würde schreiben: uint8_t pause = 100;

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
trallala schrieb:
> Christian W. schrieb:
>> // Strings zusammensetzen
>>    PORT = "LED" & n & "PORT";
>>    BIT = "LED" & n & "BIT";
>
> das is ma geil XD
warum? weils geil ist oder weils nicht geht? ;)

Autor: trallala (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nein nicht bös gemeint .. aber das sieht nunmal bissel krass aus ^^
und ich frage mich wie du auf strings kommst ??

ich sage mal ganz grob so gehts definitiv  nicht !!
aber denk mal selbst nach ...

is die beste schule

Autor: Nico22 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frag mal deinen Compiler. Wie kommst du dazu, dass Variablen Strings 
sind? Oder dass du den Namen einer Variablen per String ändern kannst. 
Und Strings kannst du so auch nicht zusammensetzen, wenn es mit Strings 
ginge.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian W. schrieb:
> vielleicht ist es
> ja richtig (grins)

naja.

1. du definierst LED_... von 1 bis 8, lässt aber die Schleife
   von 0 bis 7 laufen
2. Du hast bei "LED" & n & "PORT" die Tiefstriche vergessen.
3. Das ist kein C, selbst mit den obigen Fehlern korrigiert.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian W. schrieb:

> Das ist kein Codefetzen, mehr davon gibt es noch gar nicht, ist nur so
> ein Versuch, ich würde schreiben: uint8_t pause = 100;

Geht nicht. Kompiliert zwar aber du bekommst prinzipbedingt keine 
genauen Delays. Nimm

#define pause 100
_delay_ms(pause);

oder lesbarer (Geschmackssache, Makros in Großschrift und sinnvoller 
Name):

#define PAUSE_100MS 100
_delay_ms(PAUSE_100MS);

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, hab ne verständnisfrage. warum gehts mit einer variable "pause" 
ungenauer als mit define?

prinzipiell ist es ja schön dass mich einige hier auf meine fehler 
hinweisen, aber leider eine erklärung bzw. ein codebeispiel dann fehlt, 
das würde ich mir eigentlich erwarten und wäre auch sinn der sache, 
ansonsten würde ich hier nicht um hilfe bitten.

sorry

christian

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hab hier mal ein codebeispiel angehängt das soweit funktioniert, ohne 
compilerfehler.

nur was ist, wenn ich wegen des platinenlayouts nicht bei einem port 
bleiben kann, sondern led 1-4 auf portd habe, und led 5-8 auf portc?

außerdem funktioniert das laufen da unten sowieso nicht, da immer nur 
die erste led leuchtet

da weiß ich dann nicht mehr weiter...

christian
#include <avr/io.h> // Grundfunktionen
#define F_CPU 1000000UL // CPU Frequenz
#include <util/delay.h> // Warteschleifen

#define LED_1_PORT PORTD
#define LED_1_BIT PD0
#define LED_2_PORT PORTD
#define LED_2_BIT PD1
#define LED_3_PORT PORTD
#define LED_3_BIT PD2
#define LED_4_PORT PORTD
#define LED_4_BIT PD3
#define LED_5_PORT PORTD
#define LED_5_BIT PD4
#define LED_6_PORT PORTD
#define LED_6_BIT PD5
#define LED_7_PORT PORTD
#define LED_7_BIT PD6
#define LED_8_PORT PORTD
#define LED_8_BIT PD7

int main (void)
{

  DDRD = 0b11111111;

  uint8_t pause = 100;  

  // Lauflicht-Schleife
  while(1)
  {
  
  for(int n=0; n<8; n++)
  {

       // Port und Pin ansteuern
       LED_1_PORT |= (1<<LED_1_BIT);

       // Warten
       _delay_ms(pause);

       // Port und Pin deaktivieren
       LED_1_PORT |= (1<<LED_1_BIT);
  }

  }

  return 0;
}

Autor: Torsten K. (ago)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian W. schrieb:
> ok, hab ne verständnisfrage. warum gehts mit einer variable "pause"
> ungenauer als mit define?

weil _delay_ms() ein Makro ist und eine Konstante "erwartet". Wenn du 
eine Variable nutzt, dann muß der Compiler hier Code einsetzen welcher 
auch mit variablem (veränderlichen) Pausenzeiten läuft. Und dieser Code 
ist per definition ungenauer.

_delay_ms(10) erzeugt eine Verzögerung von exakt 10ms, abgestimmt auf 
den im Projekt angegebenen CPU-Takt (z.B. "#define F_CPU 3686400UL").

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Torsten K. schrieb:
> Christian W. schrieb:
>> ok, hab ne verständnisfrage. warum gehts mit einer variable "pause"
>> ungenauer als mit define?
>
> weil _delay_ms() ein Makro ist und eine Konstante "erwartet". Wenn du
> eine Variable nutzt, dann muß der Compiler hier Code einsetzen welcher
> auch mit variablem (veränderlichen) Pausenzeiten läuft. Und dieser Code
> ist per definition ungenauer.
Ungenauer ist der nicht, kann er ja nicht sein, sonst würde der Compiler 
beim Optimieren ja den Sinn verändern.
Er läuft nur langsamer und dürfte um Faktor 10..20 größer sein, da die 
_delay-Makros mit Fließkomma formuliert sind und damit die ganze 
Mathebibliothek hinterherziehen.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven P. schrieb:

> Ungenauer ist der nicht, kann er ja nicht sein, sonst würde der Compiler
> beim Optimieren ja den Sinn verändern.

Ungenauer nicht im mathematischen Sinn, sehr wohl aber bei dem, was 
damit erreicht werden soll: der Laufzeit.

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
aha deswegen liefen meine früheren delays immer unterschiedlich lange, 
weil ich variablen verwendet habe...

kann mir bei meinem obigen code noch jemand weiterhelfen? ich möchte 
speziell in die for-schleife etwas einbauen, dass dem gerecht wird, wenn 
ich einige leds an portc, und einige an portd habe. mir gehts darum zu 
verstehen wie ich veränderbare variablen, statt "PD5, PD6, usw..." 
verwende.

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sowas macht man, wenn es denn unbedingt sein muss, idealerweise mit 
Arrays.

Die Arrays (mal einfach gesagt, Du hättest zwei stück) sind so groß, wie 
Du Schritte hast. In einem kommt die Portadresse in den anderen die 
verwendete Bitmaske. Jetzt kannst Du mittels Arrayindex die Ports der 
"Reihe nach" ansprechen.

Autor: Lukas K. (carrotindustries)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oder im Falle eines Lauflichtes ein Bit immer wieder durchschieben.

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
durchschieben geht ja nur bedingt, wenn ich 4 leds an port d, und 4 leds 
an port c habe. oder? (grübel...)

hätte da jemand ein kurzes codebeispiel?

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

Bewertung
0 lesenswert
nicht lesenswert
Christian W. schrieb:
> durchschieben geht ja nur bedingt, wenn ich 4 leds an port d, und 4 leds
> an port c habe. oder? (grübel...)
>
> hätte da jemand ein kurzes codebeispiel?

Das Dilemme ist, dass das in diesem Fall nicht mehr so einfach ist, wenn 
man es komplett so formulieren möchte, dass man alles per #define 
variabel halten möchte und möglichst kurz halten will (sprich mit einer 
Schleife arebitet)

Das liegt daran, dass du hier indirekt adressieren musst. Du willst die 
i-te LED leuchten lassen, und aus diesem i muss man irgendwie auf den 
Port und das zu setzende Bit kommen. Das ist aber fundemantal etwas 
anderes als das was man bei der überwiegenden Mehrzahl der Fälle hat, in 
denen der Port bzw die Bitmaske mehr oder weniger fix ist und nicht 
indirekt über ein i adressiert wird.

Eine Möglichkeit ist zb. wie bereits gesagt, mit einem Array zu 
arbeiten. Eigentlich müssten es 3 sein: Eines für das zu konfigurierende 
DDR Register, eines für das Port Register an dem ausgegeben wird und 
eines für die Bitmaske.
#include <avr/io.h> // Grundfunktionen
#define F_CPU 1000000UL // CPU Frequenz
#include <util/delay.h> // Warteschleifen

#define LED_1_DDR  DDRD
#define LED_1_PORT PORTD
#define LED_1_BIT  PD0

#define LED_2_DDR  DDRD
#define LED_2_PORT PORTD
#define LED_2_BIT  PD1

#define LED_3_DDR  DDRD
#define LED_3_PORT PORTD
#define LED_3_BIT PD2

#define LED_4_DDR  DDRD
#define LED_4_PORT PORTD
#define LED_4_BIT  PD3

#define LED_5_DDR  DDRD
#define LED_5_PORT PORTD
#define LED_5_BIT  PD4

#define LED_6_DDR  DDRD
#define LED_6_PORT PORTD
#define LED_6_BIT  PD5

#define LED_7_DDR  DDRD
#define LED_7_PORT PORTD
#define LED_7_BIT  PD6

#define LED_8_DDR  DDRD
#define LED_8_PORT PORTD
#define LED_8_BIT  PD7

volatile uint8_t* Ddr[] = { &LED_1_DDR, &LED_2_DDR, &LED_3_DDR, &LED_4_DDR,
                            &LED_5_DDR, &LED_6_DDR, &LED_7_DDR, &LED_8_DDR };

volatile uint8_t* Port[] = { &LED_1_PORT, &LED_2_PORT, &LED_3_PORT, &LED_4_PORT,
                             &LED_5_PORT, &LED_6_PORT, &LED_7_PORT, &LED_8_PORT };

volatile uint8_t Mask[] = { 1 << LED_1_BIT, 1 << LED_2_BIT, 1 << LED_3_BIT, 1 << LED_4_BIT,
                             1 << LED_5_BIT, 1 << LED_6_BIT, 1 << LED_7_BIT, 1 << LED_8_BIT };

int main (void)
{
  uint8_t i;

  for( i = 0; i < 8; ++i )     // die benötigten Port Bits auf 1 (=Ausgang) schalten
    *Ddr[i] |= Mask;

  while(1)
  {
    for( i = 0; i < 8; i++ )
    {
      *Port[i] |= Mask;
      _delay_ms( 100 );
      *Port[i] &= ~Mask;
    }
  }

  return 0;
}


Das einzige was jetzt noch fix ist, ist die Anzahl der LED. Will man die 
auch noch variabel halten, dann könnte man auch das noch machen.
Aber du siehst schon, der Aufwand ist nicht unbeträchtlich. Deshalb hab 
ich auch weiter oben gesagt, dass das 'Ansprechen einzelner LED' bei 
einem Luaflicht nicht sehr sinnvoll ist, auch wenn es möglich ist.

Wenn du das meiste davon noch nicht verstehst, dann ist das kein 
Beinbruch. Um das im Detail zu verstehen muss man schon ein wenig Übung 
haben. So wie hier geschrieben ist das nichts, was ich von einem Neuling 
erwarten würde.

Was du aber tun solltest: Besorg dir ein C Buch.
Was du hier geschrieben hast
....

#define LED_8_PORT     PORTD
#define LED_8_BIT      PC4

// Lauflicht-Schleife
for(uint8_t n=0; n<8; n++)
{
   // Strings zusammensetzen
   PORT = "LED" & n & "PORT";
   BIT = "LED" & n & "BIT";

  ....

zeigt eigentlich sehr deutlich, dass dir hier viele Grundlagen fehlen 
und dir insbesondere nicht klar ist, was #define eigentlich wirklich 
macht.
Kauf dir ein C-Buch! Du wirst es brauchen. Eine Sprache wie C kann man 
nicht durch Versuch&Irrtum und durch zusammenfragen in Foren lernen. 
Wenn man nicht systematisch an die Feinheiten herangeführt wird, wird 
immer mit seinem Halbwissen auf die Schnauze fallen und in der Situation 
sein, dass einzelne Details in einem Fremdprogramm für einen einfach 
keinen Sinn ergeben, während sie für jemanden mit einem soliden 
Wissensunterbau völlig glasklar sind.

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
zwar funktioniert das codebeispiel wegen vieler compilerfehler nicht, 
aber endlich mal eine brauchbare antwort und eine aussagekräftige 
erklärung der lage.

(error: invalid operands to binary | (have 'int' and 'volatile uint8_t 
*'))

übrigens hab ich schon diverse internetseiten in php programmiert, was 
ja in gewisser weise ähnlichkeit mit c hat, da versuche ich hin und 
wieder, die php logik in den c code zu übertragen, was anscheinend nicht 
100% klappt :-D
weil das zusammensetzen von strings aus mehreren bestandteilen läuft 
seit jahren einwandfrei mit php... (beispiel weiter oben...)

danke ;-)

Autor: trallala (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
typedef struct 
{
  volatile   unsigned char *port;
      unsigned char pin;
}t_port;

t_port  led[]=
{
{ &PORTD , PD0 },
{ &PORTD , PD1 },
{ &PORTD , PD2 },
{ &PORTD , PD3 },
{ &PORTD , PD4 },
{ &PORTD , PD5 },
{ &PORTD , PD6 },
{ &PORTD , PD7 },
};



int main(void)
{
  unsigned char i;

  while(1)
  {
    for( i = 0; i < 8; i++ )
    {
       *led[i].port |= (1<<led[i].pin);
       _delay_ms( 100 );
       *led[i].port &= ~(1<<led[i].pin);
    }
  }
  return 0;
}
geht zumindest auch ...

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

Bewertung
0 lesenswert
nicht lesenswert
Christian W. schrieb:
> zwar funktioniert das codebeispiel wegen vieler compilerfehler nicht,

Das war mein Fehler.
Ich habs nicht durch den Compiler gejagt sondern direkt hier im Forum 
eingetippt.
Mask ist ja auch ein Array, also muss man auch dort natürlich mit dem 
Index ran
...

int main (void)
{
  uint8_t i;

  for( i = 0; i < 8; ++i )     // die benötigten Port Bits auf 1 (=Ausgang) schalten
    *Ddr[i] |= Mask[i];

  while(1)
  {
    for( i = 0; i < 8; i++ )
    {
      *Port[i] |= Mask[i];
      _delay_ms( 100 );
      *Port[i] &= ~Mask[i];
    }
  }

  return 0;
}


> weil das zusammensetzen von strings aus mehreren bestandteilen läuft
> seit jahren einwandfrei mit php... (beispiel weiter oben...)

Tja.
Das Problem ist, dass du erst mal gar keine Strings hast.
Zweitens sind die Variablennamen nach dem Compilieren gar nicht mehr 
vorhanden. Das heißt du kannst dich aus Prinzip in C schon mal gar nicht 
per Programm auf Variablen beziehen, deren Namen du erst zur Laufzeit 
festlegen willst. Wenn du so etwas brauchst, dann führt der Weg immer 
über ein Array.


Wie gesagt: #define macht etwas völlig anderes, als was du vermutest.

Autor: Oliver Ju. (skriptkiddy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian W. schrieb:
> ja danke auch für die antwort...! (kopfschüttel)

Am besten wäre es, wenn du dir ein C-Buch kaufst und das durcharbeitest. 
Dann lernst du C von der Pike auf und musst nicht durch Probieren oder 
Begutachtung Anderer herausfinden, ob etwas funktioneren kann oder 
nicht.

Gruß Skriptkiddy

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wie gesagt: #define macht etwas völlig anderes, als was du vermutest.
Schön und gut... Nur was macht #define? Das es was anderes macht hab ich 
nun schon 2x gehört, aber kein einziges Mal eine Erklärung dazu... ^^
Für euch ist es ein leichtes mal 2 Sätze hinzuschreiben.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian W. schrieb:
> Nur was macht #define?

Reine Textersetzung, bevor der Compiler den Quelltext sieht.

Autor: Floh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian W. schrieb:
> Nur was macht #define?
Ganz kurz gesagt einfach Textersatz, bevor es zum Compiler kommt.
:-)

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
achso! na jetzt versteh ich das auch. ist doch ganz einfach wenn mans 
weiß :-D

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

Bewertung
0 lesenswert
nicht lesenswert
Christian W. schrieb:
> achso! na jetzt versteh ich das auch. ist doch ganz einfach wenn mans
> weiß :-D

Exakt.
Vieles ist in C eigentlich gar nicht so schwer.
Das Problem: Wenn man immer nur Teile vor sich hat und immer nur in 
Einzelteilen lernt, dann hat man viele Einzelteile die scheinbar nicht 
zusammenpassen. Genau aus diesem Grund wirst du immer wieder hören: Kauf 
dir ein C Buch.

Denn ein Buch hat einen enormen Vorteil: Es bringt dich systematisch von 
den einfachen Dingen zu den schwierigeren Dingen. Das Buch ist so 
aufgebaut, dass jedes Kapitel auf dem vorhergehenden beruht und du in 
kleineren Schritten an das Wissen herangeführt wirst.

In einem Forum wird dir die ungeschminkte Wahrheit über C um die Ohren 
geschlagen. Und die ist in C manchmal auf den ersten Blick gar nicht so 
schmeichelhaft. Warum gewisse Dinge in C genau so sind, wie sie sind, 
erschliesst sich einem erst dann, wenn man das große Ganze sieht. Denn 
dann sieht man plötzlich, das das was zunächst unlogisch erschien, 
eigentlich genau so ist, damit eine gewisse Systematik gewahrt bleibt 
und wenn man die Systematik kennt, folgt das vermeintlich Unlogische 
sofort daraus und ist überhaupt nicht mehr unlogisch.

zb #define
oder ganz allgemein alle Zeilen, die mit # anfangen.
Die haben mit C bzw. dem Compiler nur soviel zu tun, dass sie 
Anweisungen an den Preprozessor sind. Der ist zwar ein obligatorischer 
Bestandteil des Compilier-Prozesses, ist aber eigentlich nichts anderes 
als ein Texteditor, der vor dem Compiler läuft und den Programmtext für 
den Compiler aufbereitet. Und dieser Texteditor wird pikanterweise durch 
Kommandos gesteuert (eben jene Zeilen, die mit # beginnen), die im Text 
selber eingebettet sind, den er bearbeiten soll.


Und das alles und noch vieles vieles mehr, steht in jedem noch so 
grindigem C-Buch. Und zwar im Detail. Viel besser und viel 
ausführlicher, mit all den kleinen Details auf die in Foren gerne 
vergessen wird, als irgendjemand dir das in einem Forum beschreiben 
könnte oder auch nur beschreiben wollte.

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

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> http://www.wachtler.de/ck/5_Praeprozessor.html

Hallo Klaus.
Nicht das ich Kritik üben möchte.
Aber könntest du in deinem Tut an dieser Stelle

> Verhindern kann man den Fehler nur, indem man die Parameter nicht
> beim Aufruf manipuliert, sondern gegebenenfalls vorher oder nachher:
>
> #define max(a,b) ( a>b ? a : b );
> /* ... */
>     ++i;
>     gross = max(i,gross);
> /* ... */

noch einen Absatz einfügen. So irgendwas nach diesem Muster:

Aus dem vorgenannten sieht man auch, dass Makros so ihre Tücken haben 
und es daher für denjenigen der ein Makro verwendet unter Umständen sehr 
wichtig sein kann, zu wissen dass er es mit einem Makro zu tun hat.
Unter anderem aus diesem Grund hat es sich schon in den C-Anfängen von 
Anfang an eingebürgert, dass Makronamen immer vollständig in 
Grossbuchstaben geschrieben werden und auch umgekehrt Namen nur in 
Grossbuchstaben ausschliesslich für Makros reserviert sind. Dies ist 
eine der wenigen Konventionen, die sich weltweit durchgesetzt haben und 
es gibt keinen wie auch immer gearteten Grund mit dieser Konvention zu 
brechen. In realem Code würde man daher ein derartiges Makro so 
schreiben
#define MAX(a,b) ( (a)>(b) ? (a) : (b) )

damit an der verwendenden Stelle
    gross = MAX(i,gross);
eindeutig klar ist, dass es sich hier bei MAX um ein Makro handelt und 
nicht etwa um eine reale Funktion und man daher bei den Makroargumenten 
etwas vorsichtig sein muss.



NB: Ach ja. den ; am Makroende besser wegmachen.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> NB: Ach ja. den ; am Makroende besser wegmachen.

Peinlich und erledigt.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> noch einen Absatz einfügen. So irgendwas nach diesem Muster:

Jetzt wo du es sagst, vermisse ich es auch.
Dachte eigentlich, ich hätte es drin stehen.
Erstmal habe ich es nicht direkt eingefügt, sondern auf meine
TODO-Liste gesetzt. Ich muß an dem Ding schon lange mal einiges
renovieren, dann kommt es mit rein.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag: Die Renovierung stagniert, weil ich das früher immer als
LaTeX geschrieben habe und die HTML-Version jeweils mit latex2html
generiert hatte. Das hat aber einige Problemchen und scheint
ziemlich tot zu sein, sodaß ich auf etwas anderes umsteigen will.
Bisher konnte ich mich nicht durchringen, was ich als Ersatz nehmen
soll (auch mangels Druck, solange ich den Stoff nicht brauche).
Vielleicht verzichte ich auch ganz auf HTML und mache nur noch PDF,
da brauche ich nicht viel ändern.

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

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Karl heinz Buchegger schrieb:
>> NB: Ach ja. den ; am Makroende besser wegmachen.
>
> Peinlich und erledigt.

Ach was. Simpler Tippfehler. Kann vorkommen.
Zumal man die Auswirkungen eines ; im Makro nur unter bestimmten 
Bedingungen sieht.
Ich hatte das letzte Woche bei einem Kollegen, der sich bei (sinngemäss)

   if( a < c )
     j = MAX( a, b );
   else
     j = 0;

über ein 'else without if' freuen durfte. Er hats aber selbst in ein 
paar Minuten gefunden. Pikanterweise existiert das Makro (war eine 
Verpackung für strncpy) schon seit mindestens 15 Jahren (weiter reichen 
die SVN Aufzeichnungen nicht zurück) und offenbar hatte noch nie jemand 
Probleme damit. Wir haben dann beschlossen, irgendwann in nächster Zeit, 
wenn der Stress mit der anstehenden Release weg ist, das mal zu 
bereinigen. Solche Dinge im Nachhinein zu ändern ist insbesondere bei 
großem Code gefährlich und das wollen wir jetzt nicht machen. Zum 
Jahreswechsel müssen wir auf den Markt, keine Experimente zum jetzigen 
Zeitpunkt :-) Code der unter Umständen möglicherweise anderen Code in 
seiner Bedeutung verändert, wie das ja bei Makros durchaus möglich ist, 
können wir uns jetzt nicht leisten.

Wir haben die Situation dann mit einem
   if( a < c ) {
     j = MAX( a, b );
   }
   else
     j = 0;

vorerst bereinigt

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Ach was. Simpler Tippfehler. Kann vorkommen.

Kam drunter noch zweimal vor, dank Kopieren :-(

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Wir haben die Situation dann mit einem
>    if( a < c ) {
>      j = MAX( a, b );
>    }
>    else
>      j = 0;

Wobei ich ohnehin mit den Mund fusselig rede, daß man generell
for, if, else und Konsorten mit ganzen Blöcken schreiben sollte.
Dafür scheinst du aber auch nicht empfänglich zu sein...

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Wobei ich ohnehin mit den Mund fusselig rede, daß man generell
> for, if, else und Konsorten mit ganzen Blöcken schreiben sollte.
> Dafür scheinst du aber auch nicht empfänglich zu sein...
Und meine IDE ersetzt "fehlende" Klammern automatisch beim speichern / 
reformatiren von Source, sehr nützlich ;)
Da mag ich es dann doch wenn Programmiersprachen solch ein Konstrukt 
erst gar nicht erlauben :)

Karl heinz Buchegger schrieb:
> eine Experimente zum jetzigen
> Zeitpunkt :-) Code der unter Umständen möglicherweise anderen Code in
> seiner Bedeutung verändert,
Na ist doch kein Problem ihr habt ja bestimmt Unittests die euch sagen 
ob noch alles so klappt wie vorher ;P duck und weg

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
na gut, da ich nun weiß wo meine schlauheit aufhört (grins) hätt ich mal 
ne frage. gibts so einen c-lernkurs im internet oder irgendwo als pdf?

danke

christian

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Viele.

Meiner (ohne daß er der beste sein muß -weil er eigentlich nur
als Begleitung zu einer Vorlesung gedacht war-, aber ich kenne
ihn halt):
http://www.wachtler.de/ck/index.html

Autor: Christian W. (christian_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vielen dank :-)

Autor: Andreas B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> damit an der verwendenden Stelle    gross = MAX(i,gross);
> eindeutig klar ist, dass es sich hier bei MAX um ein Makro handelt und
> nicht etwa um eine reale Funktion und man daher bei den Makroargumenten
> etwas vorsichtig sein muss.

Wenn man auf gcc eingeschossen ist und dessen Erweiterungen verwenden 
kann, kann man min/max Makros auch ohne Nebeneffekte schaffen. Hier mal 
aus dem Linux Kernel zitiert:
/*
 * min()/max()/clamp() macros that also do
 * strict type-checking.. See the
 * "unnecessary" pointer comparison.
 */
#define min(x, y) ({                            \
        typeof(x) _min1 = (x);                  \
        typeof(y) _min2 = (y);                  \
        (void) (&_min1 == &_min2);              \
        _min1 < _min2 ? _min1 : _min2; })

#define max(x, y) ({                            \
        typeof(x) _max1 = (x);                  \
        typeof(y) _max2 = (y);                  \
        (void) (&_max1 == &_max2);              \
        _max1 > _max2 ? _max1 : _max2; })

Dabei werden x und y nur einmal evaluiert, Sachen wie max(x++,y) 
funktionieren wie erwartet. Abgesehen von der zusätzlichen 
Typüberprüfung ist obiges identisch mit dem Beispiel aus der gcc-Doku 
zur Erweiterung "typeof".

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.