Forum: Compiler & IDEs MSP430: Macro um flexibel direkt Register zu beschreiben


von Tonmeister (Gast)


Lesenswert?

Hallo,

ich bin kein Softwerker und irgendwie zu doof...
...folgenden Code habe ich zusammengestrickt bekommen (und der tut):

void WriteAdress(char ADDRESS, char DATA, char SR)
{
  char *address_ptr;                      // adress pointer

  address_ptr = (char *) ADDRESS;

  switch(SR)
  {
    case  0:
      *address_ptr &= ~DATA;
      break;
    case 1:
      *address_ptr |= DATA;
      break;
    case 2:
      *address_ptr = DATA;
      break;
  }
}

Aufruf mit:

WriteAdress(ADDBASE + BASEOFFSET + X, DATA, SELECT);

--------------------------------------------------------

Nun meine Frage:

Wie kann ich das durch einfache, universelle Macros ersetzen?

Ziel: Direktes Schreiben von Registern inkl. Offset, damit nicht P1OUT, 
P2OUT, P1DIR, P1IE etc. verwendet werden müssen.

Also sinngemäß:

#define REG_SETBITS(ADDRESS,DATA)    ????????
#define REG_CLEARBITS(ADDRESS,DATA)   ????????

von Karl H. (kbuchegg)


Lesenswert?

Tonmeister schrieb:


> Ziel: Direktes Schreiben von Registern inkl. Offset, damit nicht P1OUT,
> P2OUT, P1DIR, P1IE etc. verwendet werden müssen.
>
> Also sinngemäß:
>
> #define REG_SETBITS(ADDRESS,DATA)    ????????
> #define REG_CLEARBITS(ADDRESS,DATA)   ????????

Ist das jetzt eine Fangfrage? Hol dir aus deiner Funktion den Teil raus, 
der beim direkten Setzen ausgeführt wird. Was bleibt übrig?

Und daraus ergibt sich dann:

#define REG_SETBITS( ADRESS, DATA )   *(unsigned char*)(ADRESS) = (DATA)


(du solltest wirklich unsigned char nehmen, wenn du mit Bytes hantierst, 
und nicht char)


> damit nicht P1OUT, P2OUT, P1DIR, P1IE etc. verwendet werden müssen.

Was stört dich daran?
Besser lesbar ist das auch nicht, wenn du das durch die jeweiligen 
Adressen in Zahlenform ersetzt. Dafür ist es fehleranfälliger.

von Tonmeister (Gast)


Lesenswert?

Danke!

...und das war keine Fangfrage!

Das Problem ist immer wieder die Syntax! Was will der Compiler sehen, 
damit er das tut, was ich von ihm will? Ich bastele eben nur in meiner 
Freizeit ein bißchen mit den MSPs rum und kann eigentlich gar nicht 
programmieren!

P.S.: Kennt jemand eine gute Übersicht (max. einige Seiten DIN A4), wo 
alle (wichtigen) Befehle und dazugehörigen Syntaxen übersichtlich 
dargestellt sind? (z.B. wie die PerlRefCard)

P.S.2: Ich hasse Pointer!

von Tonmeister (Gast)


Lesenswert?

>> damit nicht P1OUT, P2OUT, P1DIR, P1IE etc. verwendet werden müssen.

>Was stört dich daran?
>Besser lesbar ist das auch nicht, wenn du das durch die jeweiligen
>Adressen in Zahlenform ersetzt. Dafür ist es fehleranfälliger.


Mein aktuelles Projekt sind kapazitive Taster/Slider. Hierzu sind 8 Caps 
auf zwei Portbänken angebunden. Je nach Layout kann das beim nächsten 
Projekt wieder anders verschaltet sein. Ich habe durch das direkte 
Schreiben der Register EINE Funktion, die immer funktioniert, egal, an 
welche Ports ich die Caps angeschlossen habe und die auch in weiteren 
Projekten ohne Veränderung verwendet werden kann.

Ich kann jetzt einfach:

MeasureCapPair(C1, C1OFFSET, C2, C2OFFSET);
MeasureCapPair(C2, C2OFFSET, C1, C1OFFSET);

schreiben und mit dem OFFSET einstellen, auf welcher PortBank die Caps 
liegen.

So die Idee. Wenn jemand elegantere Lösungen hat: Immer her damit! :)

von Karl H. (kbuchegg)


Lesenswert?

Tonmeister schrieb:

> P.S.: Kennt jemand eine gute Übersicht (max. einige Seiten DIN A4), wo
> alle (wichtigen) Befehle und dazugehörigen Syntaxen übersichtlich
> dargestellt sind? (z.B. wie die PerlRefCard)

Wenn wir schon dabei sind.
Kennt jemand eine gute Übersicht (max ein paar Seiten DIN A4), die ich 
nur lesen muss und dann kann ich fliessend Japanisch?

von Tonmeister (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Tonmeister schrieb:
>
>> P.S.: Kennt jemand eine gute Übersicht (max. einige Seiten DIN A4), wo
>> alle (wichtigen) Befehle und dazugehörigen Syntaxen übersichtlich
>> dargestellt sind? (z.B. wie die PerlRefCard)
>
> Wenn wir schon dabei sind.
> Kennt jemand eine gute Übersicht (max ein paar Seiten DIN A4), die ich
> nur lesen muss und dann kann ich fliessend Japanisch?


FALSCH!

Wenn schon, dann muß es:

Kennt jemand eine gute Übersicht (max ein paar Seiten DIN A4), die ich
nur lesen muss und dann kann ich japanische Grammtik?



Du BIST Softwerker, stimmts? ;)

von #define (Gast)


Lesenswert?

Nutze einfach #define und bedingte Compilierung
1
#ifdef (PORT_P1)
2
  #define P1OUT   PORT_OUT
3
  #define P1DIR   PORT_DIR
4
    ...
5
#endif
6
#ifdef (PORT_P2)
7
  #define P2OUT   PORT_OUT
8
  #define P2DIR   PORT_DIR
9
    ...
10
#endif
11
12
int main (void) {
13
  ...
14
  PORT_OUT = BIT1;
15
  ...
16
}

von Karl H. (kbuchegg)


Lesenswert?

Tonmeister schrieb:

> Kennt jemand eine gute Übersicht (max ein paar Seiten DIN A4), die ich
> nur lesen muss und dann kann ich japanische Grammtik?

Was hilft dir die Grammatik, wenn du sie nicht anwenden kannst.

Ein Pointer schreibt sich in der Deklaration mit einem * zwischen 
Datentyp und Variablennamen.
Beispiel:

    int * myPointer;

Ein Pointer wird dereferenziert, indem man in der Verwendung einer 
Expression, die den Datentyp 'Adresse von Datentyp T' hat, einen * 
voranstellt.

Beispiel:

   i = *myPointer;


Das ist alles, was es an Grammatik zu Pointern zu sagen gibt. (Na, ja 
fast alles. Pointerarithmetik müsste man noch auf Grammatikebene 
definieren und ein paar Details hab ich wahrscheinlich ausgelassen). 
Bist du deswegen perfekt im Umgang mit Pointern?

von Tonmeister (Gast)


Lesenswert?

#define schrieb:
> Nutze einfach #define und bedingte Compilierung

>
1
> #ifdef (PORT_P1)
2
>   #define P1OUT   PORT_OUT
3
>   #define P1DIR   PORT_DIR
4
>     ...
5
> #endif
6
> #ifdef (PORT_P2)
7
>   #define P2OUT   PORT_OUT
8
>   #define P2DIR   PORT_DIR
9
>     ...
10
> #endif
11
> 
12
> int main (void) {
13
>   ...
14
>   PORT_OUT = BIT1;
15
>   ...
16
> }
17
>

Mmmmh...

...das habe ich noch nicht ganz verstanden.

Wenn ich z.B. 3 Caps auf PB1 habe und 5 auf PB2 und beim nächsten 
Projekt
6 auf PB1 und 2 auf PB2, wie kann ich dann mit der bedingten 
Compilierung dafür sorgen, daß ich die CapSense-Funktion nicht ändern 
muß?

Jetzt schreibe ich im Header:

#define Cx BITx
#define CxOFFSET OFFSET

und die Funktion muß nicht geändert werden. Ich habe ja meist Caps auf 
beiden PB's (oder möchte in Zukunft mehr als 8 Caps einsetzen)...


...und noch mal ne ganz andere Frage:

Ich habe jetzt die eine ursprüngliche Implementierung mit Funktion und 
die neue mit Macro.

Welche Implementierung ist den schneller und/oder speichersparender?

von #define (Gast)


Lesenswert?

Tonmeister schrieb:
> Ziel: Direktes Schreiben von Registern inkl. Offset, damit nicht P1OUT,
> P2OUT, P1DIR, P1IE etc. verwendet werden müssen.

Was ist ein Offset beim Port, meinst Du damit ein einzelnes Bit?

von asdf (Gast)


Lesenswert?

http://gcc.gnu.org/onlinedocs/cpp/Macros.html
Da steht eigentlich alles zu Macros was man so wissen muss (gcc 
spezifisch, aber das meiste ist standardisiert)

von Tonmeister (Gast)


Lesenswert?

asdf schrieb:
> http://gcc.gnu.org/onlinedocs/cpp/Macros.html
> Da steht eigentlich alles zu Macros was man so wissen muss (gcc
> spezifisch, aber das meiste ist standardisiert)


SOWAS habe ich gesucht! (aber irgendwie über Google nicht gefunden)

von Tonmeister (Gast)


Lesenswert?

#define schrieb:
> Tonmeister schrieb:
>> Ziel: Direktes Schreiben von Registern inkl. Offset, damit nicht P1OUT,
>> P2OUT, P1DIR, P1IE etc. verwendet werden müssen.
>
> Was ist ein Offset beim Port, meinst Du damit ein einzelnes Bit?

Nein.
1
    // set port direction to output (PxDIR)
2
    REG_SETBITS(ADDBASE + CaOffset + 2,Ca);
3
    REG_SETBITS(ADDBASE + CbOffset + 2,Cb);
4
    // set ports to GND (PxOUT)
5
    REG_CLEARBITS(ADDBASE + CaOffset + 1,Ca);
6
    REG_CLEARBITS(ADDBASE + CbOffset + 1,Cb);

Hier mal ein Codeschnipsel (...und jetzt schon mit Macros!! ;))

Es kann also Ca an PB1 sitzen und Cb an PB2 oder beim nächsten Projekt 
beide an PB1 und trotzdem kann ich PxDIR, PxOUT,PxIE etc. in einer 
Funktion konfigurieren.

Ganz grundsätzlich wollte ich einfach direkt in ein Register schreiben 
und mit Address-Offsets arbeiten, wußte aber die Syntax nicht und war zu 
doof, sie herauszufinden.

von #derfine (Gast)


Lesenswert?

Tonmeister schrieb:
> Ganz grundsätzlich wollte ich einfach direkt in ein Register schreiben
> und mit Address-Offsets arbeiten

Ich verstehe Deine Aufgabenstellung immer noch nicht. Du zeigst die 
Aufrufe Deiner Makros. Könntest Du eine Makrodefinition einstellen?
Was ist ADDBASE? Was ist CxOffset? Wie wird Cx deklariert?

Bitte lass mich nicht unwissend sterben.

von Tonmeister (Gast)


Lesenswert?

#derfine schrieb:
> Tonmeister schrieb:
>> Ganz grundsätzlich wollte ich einfach direkt in ein Register schreiben
>> und mit Address-Offsets arbeiten
>
> Ich verstehe Deine Aufgabenstellung immer noch nicht. Du zeigst die
> Aufrufe Deiner Makros. Könntest Du eine Makrodefinition einstellen?
> Was ist ADDBASE? Was ist CxOffset? Wie wird Cx deklariert?
>
> Bitte lass mich nicht unwissend sterben.

ADDBASE = 0x0020, also Register P1IN

Header-Schnipsel:

.
.
#define REG_SETBITS(ADDRESS, DATA) *(unsigned char*)(ADDRESS) |= (DATA)
#define C1 BIT3
#define C2 BIT2
.
.

...damit ist aber noch nicht definiert, auf welchem Port die Caps 
liegen. also weiter:

#define C1OFFSET 8 // C1 auf P2
#define C2OFFSET 0 // C2 auf P1

Somit entspricht

REG_SETBITS(ADDBASE + C1Offset + 2,C1);

gleich

P2DIR |= C1;


Warum schreibe ich nicht gleich P2DIR |= C1?

Weil ich dann beim nächsten Projekt die Caps genau gleich im Layout
verschalten muß oder den Code ändern muß! So muß ich nur den Header 
ändern!

von #define (Gast)


Lesenswert?

mmmhhhhh, ....

Meine Version mal so schnell ins Unsaubere
Projekt A
1
#define SET_C1  P2OUT |= C1;
2
#define CLR_C1  P2OUT &= ~C1;
3
...
4
5
int foo (void) {
6
...
7
  SET_C1
8
...
Projekt B
1
#define SET_C1  P1OUT |= C1;
2
#define CLR_C1  P1OUT &= ~C1;
3
...
4
5
int foo (void) {
6
...
7
  SET_C1
8
...

von Tonmeister (Gast)


Lesenswert?

#define schrieb:
> mmmhhhhh, ....
>
> Meine Version mal so schnell ins Unsaubere
> Projekt A
>
1
> #define SET_C1  P2OUT |= C1;
2
> #define CLR_C1  P2OUT &= ~C1;
3
> ...
4
> 
5
> int foo (void) {
6
> ...
7
>   SET_C1
8
> ...
9
>
> Projekt B
>
1
> #define SET_C1  P1OUT |= C1;
2
> #define CLR_C1  P1OUT &= ~C1;
3
> ...
4
> 
5
> int foo (void) {
6
> ...
7
>   SET_C1
8
> ...
9
>


Da fehlt noch einiges! Um die Ladezeit und die Entladezeit des Caps zu 
messen, muß zwischen IN/OUT, Interruptquellen, Interuptübergängen L/H, 
H/L etc. umgeschaltet werden.

D.h., man braucht noch zusätzlich:

> Meine Version mal so schnell ins Unsaubere
> Projekt A
1
> #define SET_C1  P2OUT |= C1;
2
> #define CLR_C1  P2OUT &= ~C1;
3
4
#define SetInterruptTransition  P2IES |= C1;
5
#define ClearInterruptTransition  P2IES &= ~C1;
6
#define SetInterruptEnable  P2IE |= C1;
7
#define ClearInterruptEnable  P2IE &= ~C1;

u.s.w.u.s.f.

Das ist mir zu viel Definiererei!

Ich muß nur C1 = BITx und C1OFFSET = Y im Header definieren. Das war's.

von #define (Gast)


Lesenswert?

Tonmeister schrieb:
> Somit entspricht
>
> REG_SETBITS(ADDBASE + C1Offset + 2,C1);
>
> gleich
>
> P2DIR |= C1;

Um das in in ein paar Wochen noch zu verstehen, würde ich mir für die +2 
eine selbstsprechende Ersetzung suchen.

REG_SETBITS(ADDBASE + C1Offset + PDIR_OFS,C1);

von Karl H. (kbuchegg)


Lesenswert?

Tonmeister schrieb:

> gleich
>
> P2DIR |= C1;
>
>
> Warum schreibe ich nicht gleich P2DIR |= C1?
>
> Weil ich dann beim nächsten Projekt die Caps genau gleich im Layout
> verschalten muß oder den Code ändern muß! So muß ich nur den Header
> ändern!

Musst du doch gar nicht.
1
#define CAPS_DIR              P2DIR
2
#define CAPS_WAS_WEIS_ICH     C1
3
4
....
5
6
   CAPS_DIR = CAPS_WAS_WEIS_ICH;
und gut ists.

Und wenn sich beim nächsten Projekt da was ändert, dann änderst du ganz 
einfach die ersten beiden #define

aber deswegen musst du doch nicht in diese 'Niederungen' von Adressen 
und Offsets.

von RAM (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> #define CAPS_DIR              P2DIR
> #define CAPS_WAS_WEIS_ICH     C1
>
> ....
>
>    CAPS_DIR = CAPS_WAS_WEIS_ICH;
> und gut ists.

es werden auch mehrere Ports gemischt.

von Karl H. (kbuchegg)


Lesenswert?

RAM schrieb:
> Karl Heinz Buchegger schrieb:
>> #define CAPS_DIR              P2DIR
>> #define CAPS_WAS_WEIS_ICH     C1
>>
>> ....
>>
>>    CAPS_DIR = CAPS_WAS_WEIS_ICH;
>> und gut ists.
>
> es werden auch mehrere Ports gemischt.

Was willst du mir damit sagen?

Letzten Edes kann man es immer so machen, dass man die 'Information', 
die man änderbar machen will, in einem eigenen Makro rauszieht.

1
#define C1_DIR    P2DIR
2
#define C2_PORT   P2OUT
3
#define C1_PIN    C1
4
5
#define C2_DIR    P2DIR
6
#define C2_PORT   P2OUT
7
#define C2_PIN    C5
8
9
...
10
11
12
13
     C1_DIR |= C1_PIN;
14
     C2_DIR |= C2_PIN;
15
16
....
17
18
19
     C1_PORT |= C1_PIN;       // auf C1 eine 1 geben
20
     C2_PORT &= ~C2_PIN;      // dafür C2 auf 0 schalten

ändert sich was, werden pro Komponente genau 3 define angepasst. Der 
Rest vom Programm wird vom Compiler angepasst.

Wenn man will, kommen noch 3 Makros dazu
1
#define SET_BIT(p,b)  (p) |= (b)
2
#define CLR_BIT(p,b)  (p) |= (b)
3
#define IS_SET(p,b)   (p) & (b)
4
5
6
     SET_BIT( C1_DIR, C1_PIN );
7
     SET_BIT( C2_DIR, C2_PIN );
8
9
...
10
11
     SET_BIT( C1_PORT, C1_PIN );
12
     CLR_BIT( C2_PORT, C2_PIN );


Das Ganze wird auch nicht weniger einfach mit deiner Adresse+Offset 
Rechnerei. Nur unübersichtlicher. Und wenn du das übersichtlich machen 
willst, landest du bei genau wieder dem gleichen Aufwand. Wenn nicht 
sogar mehr. Nur mit dem einen Unterschied, dass du plötzlich selbst für 
die korrekten Adressoffsets zuständig bist und im anderen Fall haben dir 
das die Entwickler deines Compilers bereits abgenommen.

von tonmeister (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> RAM schrieb:
>> Karl Heinz Buchegger schrieb:
>>> #define CAPS_DIR              P2DIR
>>> #define CAPS_WAS_WEIS_ICH     C1
>>>
>>> ....
>>>
>>>    CAPS_DIR = CAPS_WAS_WEIS_ICH;
>>> und gut ists.
>>
>> es werden auch mehrere Ports gemischt.
>
> Was willst du mir damit sagen?
>
> Letzten Edes kann man es immer so machen, dass man die 'Information',
> die man änderbar machen will, in einem eigenen Makro rauszieht.
>
>
>
1
> #define C1_DIR    P2DIR
2
> #define C2_PORT   P2OUT
3
> #define C1_PIN    C1
4
> 
5
> #define C2_DIR    P2DIR
6
> #define C2_PORT   P2OUT
7
> #define C2_PIN    C5
8
> 
9
> ...
10
> 
11
> 
12
> 
13
>      C1_DIR |= C1_PIN;
14
>      C2_DIR |= C2_PIN;
15
> 
16
> ....
17
> 
18
> 
19
>      C1_PORT |= C1_PIN;       // auf C1 eine 1 geben
20
>      C2_PORT &= ~C2_PIN;      // dafür C2 auf 0 schalten
21
>
>
> ändert sich was, werden pro Komponente genau 3 define angepasst. Der
> Rest vom Programm wird vom Compiler angepasst.
>
> Wenn man will, kommen noch 3 Makros dazu
>
1
> #define SET_BIT(p,b)  (p) |= (b)
2
> #define CLR_BIT(p,b)  (p) |= (b)
3
> #define IS_SET(p,b)   (p) & (b)
4
> 
5
> 
6
>      SET_BIT( C1_DIR, C1_PIN );
7
>      SET_BIT( C2_DIR, C2_PIN );
8
> 
9
> ...
10
> 
11
>      SET_BIT( C1_PORT, C1_PIN );
12
>      CLR_BIT( C2_PORT, C2_PIN );
13
>
>
>
> Das Ganze wird auch nicht weniger einfach mit deiner Adresse+Offset
> Rechnerei. Nur unübersichtlicher. Und wenn du das übersichtlich machen
> willst, landest du bei genau wieder dem gleichen Aufwand. Wenn nicht
> sogar mehr. Nur mit dem einen Unterschied, dass du plötzlich selbst für
> die korrekten Adressoffsets zuständig bist und im anderen Fall haben dir
> das die Entwickler deines Compilers bereits abgenommen.

Ich bin nicht RAM!

Aber das ist ja gar nicht das Thema!


Ich muß nicht nur PxOUT in der Funktion verändern, sondern auch 
PxDIR,PxIE und PxIES, d.h. es wären für einen Cap
1
> #define C1_DIR    P2DIR
2
> #define C1_PORT   P2OUT
3
> #define C1_PIN    C1
4
5
#define C1_PIE    P2IE
6
#define C1_IE    P2IE

fünf #defines nötig, das macht bei 8 Caps 40 #defines. Mein Ziel ist 
aber EINE Funktion für alle möglichen Kombinationen und Layouts von 
Cap-PärchenZ.

Selbst wenn ich o.g. #defines setzte, brauche ich 4 Funktionen für die 4 
Cap-PärchenZ. Und beim nächsten Layout (wo ja bekanntlich alles anders 
ist) muß ich im WC 40 #defines ändern und habe immer noch 4 Funktionen.

von RAM (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
>> es werden auch mehrere Ports gemischt.
>
> Was willst du mir damit sagen?

Das wurde schon durchgekaut:

Beitrag "Re: MSP430: Macro um flexibel direkt Register zu beschreiben"

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.