Forum: Compiler & IDEs Data Direction Register per Macro setzen


von Krause (Gast)


Lesenswert?

Hallo,

mit diesen Macros kann man komfortabel Ein-und Ausgänge lesen bzw. 
setzen/rücksetzen:
1
#define SETBIT(ADDRESS, BIT) (ADDRESS |= (1<<BIT))
2
#define CLEARBIT(ADDRESS, BIT) (ADDRESS &= ~(1<<BIT))
3
#define FLIPBIT(ADDRESS, BIT) (ADDRESS ^= (1<<BIT))
4
#define CHECKBIT(ADDRESS,BIT) (ADDRESS & (1<<BIT)) 
5
6
#define ADDRFROMCOMB(x, y) x
7
#define BITFROMCOMB(x, y) y
8
9
#define SET(comb) SETBIT(ADDRFROMCOMB(comb), BITFROMCOMB(comb))
10
#define CLEAR(comb) CLEARBIT(ADDRFROMCOMB(comb), BITFROMCOMB(comb)) 
11
#define TOGGLE(comb) FLIPBIT(ADDRFROMCOMB(comb), BITFROMCOMB(comb))
12
#define CHECK(comb) CHECKBIT(ADDRFROMCOMB(comb), BITFROMCOMB(comb))

z.B. so:
1
#define TestLED  PORTA,0
2
#define TestLED_Ein    SET(TestLED)
3
#define TestLED_Aus    CLEAR(TestLED)

Weiß jemand wie man aus TestLED per Macro auf die Adresse des Data 
Direction Registers kommt? Also soetwas wie:
1
#define INPUT(comb) CLEARBIT(ADDRFROMCOMB(comb) + 1, BITFROMCOMB(comb)) // funktioniert nicht
2
#define OUTPUT(comb) SETBIT(ADDRFROMCOMB(comb) - 1, BITFROMCOMB(comb))  // und das auch nicht

Das Macro würde dann so verwendet werden:
1
OUTPUT(TestLED)

Oder anders gefragt: Wie kann man per Macro von der Adresse von PORTA 1 
subtrahieren bzw. addieren?


Vielen Dank im Voraus.
Krause

von Yalu X. (yalu) (Moderator)


Lesenswert?

So:
1
#define INPUT(comb) CLEARBIT(*(&ADDRFROMCOMB(comb)-1), BITFROMCOMB(comb))
2
#define OUTPUT(comb) SETBIT(*(&ADDRFROMCOMB(comb)-1), BITFROMCOMB(comb))

Du muss beachten, dass PORTA keine Adresse, sondern bereits dereferen-
ziert ist. Die zugehörige Adresse ist &PORTA, die Adresse von DDRA ist
&PORTA-1, DDRA ist damit *(&PORTA-1). Für PORTA kannst du das allgemei-
nere ADDRFROMCOMB(comb) einsetzen, fertig.

von Karl H. (kbuchegg)


Lesenswert?

Krause schrieb:

> Oder anders gefragt: Wie kann man per Macro von der Adresse von PORTA 1
> subtrahieren bzw. addieren?

Wenn du dran denkst, dass ein Makro einfach nur Textersetzungen machst, 
musst du dir nur überlegen, wie die Textersetzung sein muss, damit der 
Compiler, der nachher das Endergebnis compiliert, das richtige tut.

Grundsätzlich ist das schon möglich. Ich bin aber nicht sicher, ob es 
bei allen AVR-µC auf allen Ports so ist, dass das DDR Register 1 vor dem 
Port Register liegt.

Aber grundsätzlich musst du nur dafür sorgen, dass der Compiler vor dem 
Zugriff die Adresse um 1 verringert. Dazu muss man wissen, wie das PORTA 
Makro gemacht ist. Der PortA hat ja letztendlich eine Speicheradresse. 
Also eine Zahl. Die wird in einen volatile unsigned char* umgecastet und 
dann mittels * auf den Wert zugegriffen.

  PORTA = 0xFF;

wird vom Compiler nach all den Ersetzungen für PORTA letztendlich so

  *(volatile uint8_t*)0x23 = 0xFF;

übersetzt (die 0x23 hab ich jetzt erfunden, keine Ahnung welche Zahl das 
wirklich ist.

Um aus den 0x23 eine 0x22 zu machen, genügt es also den * mit einem & 
wieder 'aufzuheben', 1 abzuziehen und erneut dereferenzieren.

   *((&*(volatile uint8_t*)0x23) - 1) = 0xFF;

würde daher den Zugriff über die Adresse 0x22 machen.

Von diesem Ziel ausgehen, ist es nicht schwer zu sehen, dass man vor der 
Ersetzung von PORTA durch den Klimbim

   *(&(PORTA)-1) = 0xFF;

schreiben müsste.

Was jetzt wieder bedeutet, wenn man diese Ersetzung automatisch machen 
lässt

#define DDR(port)  *(&(port)-1)

schreibt man daher

   DDR(PORTA) = 0xFF;

und führt die Textersetzung durch, landet man bei

   *(&(PORTA)-1) = 0xFF;

genau so, wie es sein sollte.

von Peter D. (peda)


Lesenswert?


von Krause (Gast)


Lesenswert?

Dank Euch allen! Funktioniert prima!

Krause

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.