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


von Christian W. (christian_w)


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 ;-)

1
        PORTD |= (1 << PD0); //  aktivieren 
2
        _delay_ms(pause); 
3
        PORTD &= ~(1 << PD0); //  deaktivieren 
4
5
        PORTD |= (1 << PD1); //  aktivieren 
6
        _delay_ms(pause); 
7
        PORTD &= ~(1 << PD1); //  deaktivieren 
8
9
        PORTD |= (1 << PD2); //  aktivieren 
10
        _delay_ms(pause); 
11
        PORTD &= ~(1 << PD2); //  deaktivieren 
12
13
        PORTD |= (1 << PD3); //  aktivieren 
14
        _delay_ms(pause); 
15
        PORTD &= ~(1 << PD3); //  deaktivieren 
16
17
        PORTD |= (1 << PD4); //  aktivieren 
18
        _delay_ms(pause); 
19
        PORTD &= ~(1 << PD4); //  deaktivieren 
20
21
        PORTD |= (1 << PD5); //  aktivieren 
22
        _delay_ms(pause); 
23
        PORTD &= ~(1 << PD5); //  deaktivieren 
24
25
        PORTD |= (1 << PD6); //  aktivieren 
26
        _delay_ms(pause); 
27
        PORTD &= ~(1 << PD6); //  deaktivieren 
28
29
        PORTD |= (1 << PD7); //  aktivieren 
30
        _delay_ms(pause); 
31
        PORTD &= ~(1 << PD7); //  deaktivieren

von Peter D. (peda)


Lesenswert?

1
void loop()
2
{
3
  uint8_t mask = 0x01;
4
5
  PORTD = 0;
6
  do{
7
    PORTD |= mask;
8
    _delay_ms( pause );
9
    PORTD ^= mask;
10
    mask <<= 1;
11
  }while( mask );
12
}


Peter

von Floh (Gast)


Lesenswert?

Christian W. schrieb:
> Wie geht sowas?

Du willst praktisch ein Lauflicht machen?
Dann geht das so ganz gut:
1
PORTD = (1<<PD0); //erste LED
2
3
for(uint8_t i=0; i<8;i++)
4
{
5
   _delay_ms(pause);
6
  PORTD <<= 1;    //eins weiterschieben
7
}
:-)

von Oliver J. (skriptkiddy)


Lesenswert?

Irgendwo im io-header steht:

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

von Sven P. (Gast)


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.

von Christian W. (christian_w)


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?

von Lukas K. (carrotindustries)


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)

von Karl H. (kbuchegg)


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 :-)

von mampf (Gast)


Lesenswert?

Stimmt aber.

von (prx) A. K. (prx)


Lesenswert?

mampf schrieb:

> Stimmt aber.

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

von Lukas K. (carrotindustries)


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

von Karl H. (kbuchegg)


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
1
#define RED_LED_DDR      DDRD
2
#define RED_LED_PORT     PORTD
3
#define RED_LED_BIT      PD1
4
5
#define ERROR_LED_DDR    DDRD
6
#define ERROR_LED_PORT   PORTD
7
#define ERROR_LED_BIT    PD0
8
9
10
int main()
11
{
12
  RED_LED_DDR |= ( 1 << RED_LED_BIT );
13
  ERROR_LED_DDR |= ( 1 << ERROR_LED_BIT );
14
15
  // alle LED aus (auf 1 schalten)
16
  RED_LED_PORT |= ( 1 << RED_LED_BIT );
17
  ERROR_LED_PORT |= ( 1 << ERROR_LED_BIT );
18
19
  while( 1 ) {
20
21
    if( irgendwas ) {
22
      ERROR_LED_PORT &= ~( 1 << ERROR_LED_BIT );
23
    }
24
25
    RED_LED_PORT ^= ( 1 << RED_LED_BIT );
26
    _delay_ms( 100 );
27
  }
28
}

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.

von mampf (Gast)


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! ;-)

von Lukas K. (carrotindustries)


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.

von mampf (Gast)


Lesenswert?

Stimmt. Gut. Sorry.

von Lukas K. (carrotindustries)


Lesenswert?

mampf schrieb:
> Stimmt. Gut. Sorry.

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

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

von Karl H. (kbuchegg)


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:
>
1
#define PD0 0
2
> #define PD1 1
> Im Quelltext
>
1
#define PD0 0
2
> PORTD |= (1<<PD1);
>
> MSP430-Stil:
> Im Header:
>
1
#define PD0 0
2
> #define P0 (1<<0)
3
> #define P1 (1<<1)
> Im Quelltext:
>
1
#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.

von (prx) A. K. (prx)


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.

von Lukas K. (carrotindustries)


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

jetzt passt's aber hoffentlich :)

von Christian W. (christian_w)


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)
1
#define LED_1_PORT     PORTD
2
#define LED_1_BIT      PD1
3
4
#define LED_2_PORT     PORTB
5
#define LED_2_BIT      PB6
6
7
#define LED_3_PORT     PORTC
8
#define LED_3_BIT      PC3
9
10
#define LED_4_PORT     PORTC
11
#define LED_4_BIT      PC4
12
13
#define LED_5_PORT     PORTC
14
#define LED_5_BIT      PC5
15
16
#define LED_6_PORT     PORTD
17
#define LED_6_BIT      PC2
18
19
#define LED_7_PORT     PORTD
20
#define LED_7_BIT      PC3
21
22
#define LED_8_PORT     PORTD
23
#define LED_8_BIT      PC4
24
25
// Lauflicht-Schleife
26
for(uint8_t n=0; n<8; n++)
27
{
28
   // Strings zusammensetzen
29
   PORT = "LED" & n & "PORT";
30
   BIT = "LED" & n & "BIT";
31
32
   // Port und Pin ansteuern
33
   PORT |= (1<<BIT);
34
35
   // Warten
36
   _delay_ms(pause);
37
38
   // Port und Pin deaktivieren
39
   PORT &= ~(1<<BIT);
40
}

So richtig?

Christian

von Oliver J. (skriptkiddy)


Lesenswert?

autsch...

von Christian W. (christian_w)


Lesenswert?

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

von trallala (Gast)


Lesenswert?

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

das is ma geil XD

von Stefan B. (stefan) Benutzerseite


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-Tutorial#IO-Register_als_Parameter_und_Variablen

von Christian W. (christian_w)


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-Tutorial#IO-Register_als_Parameter_und_Variablen


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

von Christian W. (christian_w)


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? ;)

von trallala (Gast)


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

von Nico22 (Gast)


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.

von Klaus W. (mfgkw)


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.

von Stefan B. (stefan) Benutzerseite


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);

von Christian W. (christian_w)


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

von Christian W. (christian_w)


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
1
#include <avr/io.h> // Grundfunktionen
2
#define F_CPU 1000000UL // CPU Frequenz
3
#include <util/delay.h> // Warteschleifen
4
5
#define LED_1_PORT PORTD
6
#define LED_1_BIT PD0
7
#define LED_2_PORT PORTD
8
#define LED_2_BIT PD1
9
#define LED_3_PORT PORTD
10
#define LED_3_BIT PD2
11
#define LED_4_PORT PORTD
12
#define LED_4_BIT PD3
13
#define LED_5_PORT PORTD
14
#define LED_5_BIT PD4
15
#define LED_6_PORT PORTD
16
#define LED_6_BIT PD5
17
#define LED_7_PORT PORTD
18
#define LED_7_BIT PD6
19
#define LED_8_PORT PORTD
20
#define LED_8_BIT PD7
21
22
int main (void)
23
{
24
25
  DDRD = 0b11111111;
26
27
  uint8_t pause = 100;  
28
29
  // Lauflicht-Schleife
30
  while(1)
31
  {
32
  
33
  for(int n=0; n<8; n++)
34
  {
35
36
       // Port und Pin ansteuern
37
       LED_1_PORT |= (1<<LED_1_BIT);
38
39
       // Warten
40
       _delay_ms(pause);
41
42
       // Port und Pin deaktivieren
43
       LED_1_PORT |= (1<<LED_1_BIT);
44
  }
45
46
  }
47
48
  return 0;
49
}

von Torsten K. (ago)


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").

von Sven P. (Gast)


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.

von (prx) A. K. (prx)


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.

von Christian W. (christian_w)


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.

von Christian H. (netzwanze) Benutzerseite


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.

von Lukas K. (carrotindustries)


Lesenswert?

Oder im Falle eines Lauflichtes ein Bit immer wieder durchschieben.

von Christian W. (christian_w)


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?

von Karl H. (kbuchegg)


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.
1
#include <avr/io.h> // Grundfunktionen
2
#define F_CPU 1000000UL // CPU Frequenz
3
#include <util/delay.h> // Warteschleifen
4
5
#define LED_1_DDR  DDRD
6
#define LED_1_PORT PORTD
7
#define LED_1_BIT  PD0
8
9
#define LED_2_DDR  DDRD
10
#define LED_2_PORT PORTD
11
#define LED_2_BIT  PD1
12
13
#define LED_3_DDR  DDRD
14
#define LED_3_PORT PORTD
15
#define LED_3_BIT PD2
16
17
#define LED_4_DDR  DDRD
18
#define LED_4_PORT PORTD
19
#define LED_4_BIT  PD3
20
21
#define LED_5_DDR  DDRD
22
#define LED_5_PORT PORTD
23
#define LED_5_BIT  PD4
24
25
#define LED_6_DDR  DDRD
26
#define LED_6_PORT PORTD
27
#define LED_6_BIT  PD5
28
29
#define LED_7_DDR  DDRD
30
#define LED_7_PORT PORTD
31
#define LED_7_BIT  PD6
32
33
#define LED_8_DDR  DDRD
34
#define LED_8_PORT PORTD
35
#define LED_8_BIT  PD7
36
37
volatile uint8_t* Ddr[] = { &LED_1_DDR, &LED_2_DDR, &LED_3_DDR, &LED_4_DDR,
38
                            &LED_5_DDR, &LED_6_DDR, &LED_7_DDR, &LED_8_DDR };
39
40
volatile uint8_t* Port[] = { &LED_1_PORT, &LED_2_PORT, &LED_3_PORT, &LED_4_PORT,
41
                             &LED_5_PORT, &LED_6_PORT, &LED_7_PORT, &LED_8_PORT };
42
43
volatile uint8_t Mask[] = { 1 << LED_1_BIT, 1 << LED_2_BIT, 1 << LED_3_BIT, 1 << LED_4_BIT,
44
                             1 << LED_5_BIT, 1 << LED_6_BIT, 1 << LED_7_BIT, 1 << LED_8_BIT };
45
46
int main (void)
47
{
48
  uint8_t i;
49
50
  for( i = 0; i < 8; ++i )     // die benötigten Port Bits auf 1 (=Ausgang) schalten
51
    *Ddr[i] |= Mask;
52
53
  while(1)
54
  {
55
    for( i = 0; i < 8; i++ )
56
    {
57
      *Port[i] |= Mask;
58
      _delay_ms( 100 );
59
      *Port[i] &= ~Mask;
60
    }
61
  }
62
63
  return 0;
64
}


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
1
....
2
3
#define LED_8_PORT     PORTD
4
#define LED_8_BIT      PC4
5
6
// Lauflicht-Schleife
7
for(uint8_t n=0; n<8; n++)
8
{
9
   // Strings zusammensetzen
10
   PORT = "LED" & n & "PORT";
11
   BIT = "LED" & n & "BIT";
12
13
  ....

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.

von Christian W. (christian_w)


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 ;-)

von trallala (Gast)


Lesenswert?

1
typedef struct 
2
{
3
  volatile   unsigned char *port;
4
      unsigned char pin;
5
}t_port;
6
7
t_port  led[]=
8
{
9
{ &PORTD , PD0 },
10
{ &PORTD , PD1 },
11
{ &PORTD , PD2 },
12
{ &PORTD , PD3 },
13
{ &PORTD , PD4 },
14
{ &PORTD , PD5 },
15
{ &PORTD , PD6 },
16
{ &PORTD , PD7 },
17
};
18
19
20
21
int main(void)
22
{
23
  unsigned char i;
24
25
  while(1)
26
  {
27
    for( i = 0; i < 8; i++ )
28
    {
29
       *led[i].port |= (1<<led[i].pin);
30
       _delay_ms( 100 );
31
       *led[i].port &= ~(1<<led[i].pin);
32
    }
33
  }
34
  return 0;
35
}
geht zumindest auch ...

von Karl H. (kbuchegg)


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
1
...
2
3
int main (void)
4
{
5
  uint8_t i;
6
7
  for( i = 0; i < 8; ++i )     // die benötigten Port Bits auf 1 (=Ausgang) schalten
8
    *Ddr[i] |= Mask[i];
9
10
  while(1)
11
  {
12
    for( i = 0; i < 8; i++ )
13
    {
14
      *Port[i] |= Mask[i];
15
      _delay_ms( 100 );
16
      *Port[i] &= ~Mask[i];
17
    }
18
  }
19
20
  return 0;
21
}


> 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.

von Oliver J. (skriptkiddy)


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

von Christian W. (christian_w)


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.

von Klaus W. (mfgkw)


Lesenswert?

Christian W. schrieb:
> Nur was macht #define?

Reine Textersetzung, bevor der Compiler den Quelltext sieht.

von Floh (Gast)


Lesenswert?

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

von Klaus W. (mfgkw)


Lesenswert?


von Christian W. (christian_w)


Lesenswert?

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

von Karl H. (kbuchegg)


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.

von Karl H. (kbuchegg)


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
1
#define MAX(a,b) ( (a)>(b) ? (a) : (b) )

damit an der verwendenden Stelle
1
    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.

von Klaus W. (mfgkw)


Lesenswert?

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

Peinlich und erledigt.

von Klaus W. (mfgkw)


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.

von Klaus W. (mfgkw)


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.

von Karl H. (kbuchegg)


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

von Klaus W. (mfgkw)


Lesenswert?

Karl heinz Buchegger schrieb:
> Ach was. Simpler Tippfehler. Kann vorkommen.

Kam drunter noch zweimal vor, dank Kopieren :-(

von Klaus W. (mfgkw)


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...

von Läubi .. (laeubi) Benutzerseite


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

von Christian W. (christian_w)


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

von Klaus W. (mfgkw)


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

von Christian W. (christian_w)


Lesenswert?

vielen dank :-)

von Andreas B. (Gast)


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:
1
/*
2
 * min()/max()/clamp() macros that also do
3
 * strict type-checking.. See the
4
 * "unnecessary" pointer comparison.
5
 */
6
#define min(x, y) ({                            \
7
        typeof(x) _min1 = (x);                  \
8
        typeof(y) _min2 = (y);                  \
9
        (void) (&_min1 == &_min2);              \
10
        _min1 < _min2 ? _min1 : _min2; })
11
12
#define max(x, y) ({                            \
13
        typeof(x) _max1 = (x);                  \
14
        typeof(y) _max2 = (y);                  \
15
        (void) (&_max1 == &_max2);              \
16
        _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".

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.