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) ????????
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.
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!
>> 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! :)
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?
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? ;)
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?
#define schrieb:> Nutze einfach #define und bedingte Compilierung>
1
>#ifdef(PORT_P1)
2
>#defineP1OUTPORT_OUT
3
>#defineP1DIRPORT_DIR
4
>...
5
>#endif
6
>#ifdef(PORT_P2)
7
>#defineP2OUTPORT_OUT
8
>#defineP2DIRPORT_DIR
9
>...
10
>#endif
11
>
12
>intmain(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?
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?
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)
#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.
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.
#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!
#define schrieb:> mmmhhhhh, ....>> Meine Version mal so schnell ins Unsaubere> Projekt A>
1
>#defineSET_C1P2OUT|=C1;
2
>#defineCLR_C1P2OUT&=~C1;
3
>...
4
>
5
>intfoo(void){
6
>...
7
>SET_C1
8
>...
9
>
> Projekt B>
1
>#defineSET_C1P1OUT|=C1;
2
>#defineCLR_C1P1OUT&=~C1;
3
>...
4
>
5
>intfoo(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
>#defineSET_C1P2OUT|=C1;
2
>#defineCLR_C1P2OUT&=~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.
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);
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.
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.
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.
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
>#defineC1_DIRP2DIR
2
>#defineC2_PORTP2OUT
3
>#defineC1_PINC1
4
>
5
>#defineC2_DIRP2DIR
6
>#defineC2_PORTP2OUT
7
>#defineC2_PINC5
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
>#defineSET_BIT(p,b)(p)|=(b)
2
>#defineCLR_BIT(p,b)(p)|=(b)
3
>#defineIS_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
>#defineC1_DIRP2DIR
2
>#defineC1_PORTP2OUT
3
>#defineC1_PINC1
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.