Hallo Community, ich möchte bei einem Mikrocontroller mittels einer Funktion einige Register ansprechen. Z.B. C1CTRL und C2CTRL. Jetzt möchte ich aber nicht eine funktion für C1CTRL und eine Funktion für C2CTRL schreiben, sondern eine mit Übergabeparameter welches Register ich ansprechen möchte. Geht das? Wie setzt ich das zusammen das z.B. der Übergabeparameter nicht als "Name" gesehen wird. Gruß Dirk Beispiel: bla (wert) { CwertCTRL = 0x1; } Wert kann 1 oder 2 sein
:
Bearbeitet durch User
In der Regel hast du eine Headerdatei mit defines, sprich du schreibst zwar den Namen als Parameter, es ist aber letztendlich in der Regel eine Zahl bzw. die Adresse des Registers.
Praktisch schaust Du einfach mal nach, wie Identifier wie C1CTRL letztlich deklariert und definiert sind. Das kann unter Umständen über mehrere Preprozessor Makros und weitere C-Konstruktionen gehen. Wenn aber für den fraglichen uC der Compiler Ausdrücke mit C1CTRL als L-Wert akzeptiert muss am Ende gerade ein Typ herauskommen der als L-Wert geeignet ist. Manchmal ist das ein wenig verwickelt, weil noch Hilfsdefinitionen von Makros oder Typen eine Rolle spielen können. CMSIS ist so ein Beispiel. Aber für nen AVR führt die Suche ziemlich schnell zum Ziel. Der Typ ist dann auch der Parameter für die Funktion.
Dirk P. schrieb: > bla (wert) > { > CwertCTRL = 0x1; > } Hast du die letzten Jahrzehnte verpennt? K&R Deklarationen sind seid einem Vierteljahrhundert veraltet.
Mit einer für GCC spezifischen Erweiterung geht das u.U. auch ohne Blick auf das Register:
1 | void bla(typeof C1CTRL *regPtr) |
2 | {
|
3 | *regPtr = 1; |
4 | }
|
und Aufruf per
1 | bla(&C2CTRL); |
Mal vorausgesetzt, die haben beide den gleichen Typ.
:
Bearbeitet durch User
Das verstehe ich nicht ganz. Und wie ändere ich jetzt das je nach Übergabeparameter das C1 oder C2 Register anspreche?
In dem Du die Funktion mit einem Parameter deklarierst, der dem Typ von C1CTRL entspricht. Dieser Funktion kannst Du dann "C1CTRL" als Wert übergeben. Nimm an, C1CTRL sei als char * deklariert. Dann wäre die Funktion:
1 | funktion (registertyp x) { |
2 | |
3 | x = 7; |
4 | }
|
Üblicherweise sind solche Registersymbole als "volatile" definiert, und benutzen irgendeine Compiler-spezifische Magie, um sie an eine feste Adresse zu legen:
1 | volatile uint16_t C1CTRL __an_fester_adresse__(0x1234); |
Für deinen Zeiger brauchst du die Adresse nicht, aber das "volatile" (oder was dort halt benutzt wird):
1 | void funktion(volatile uint16_t *reg) |
2 | {
|
3 | *reg = 0x1; |
4 | }
|
5 | |
6 | ...
|
7 | funktion(&C1CTRL); |
Dirk P. schrieb: > > bla (wert) > { > CwertCTRL = 0x1; > } > > Wert kann 1 oder 2 sein Und was gefällt dir jetzt an
1 | void bla( uint8_t wert ) |
2 | {
|
3 | if( wert == 1 ) |
4 | C1CTRL = 0x1; |
5 | else if( wert == 2 ) |
6 | C2CTRL = 0x1; |
7 | }
|
nicht? Nein. Du kannst nicht einen Variablennamen zur Laufzeit zusammen setzen lassen. Wenn das Programm läuft, existierten Variablennamen nicht mehr. Normalerweise ist der Versuch so etwas machen zu wollen, ein starker Hinweis darauf, dass man eigentlich ein Array einsetzen will
1 | registerPointerDatentyp Output[] = { &C1CTRL, &C2CTRL }; |
2 | |
3 | void bla( uint8_t wert ) |
4 | {
|
5 | Output[wert-1] = 0x1; |
6 | }
|
:
Bearbeitet durch User
Dirk P. schrieb: > Und wie ändere ich jetzt das je nach Übergabeparameter das C1 oder C2 > Register anspreche? bla(&C1CTRL); bla(&C2CTRL); Je nach µC gibt es in den Headern statt vieler Einzelregister (z.B. AVR) oft Strukturen für die I/O-Module (z.B: ARM). Dann geht das z.B. so void initUART(UART_REG_BLOCK *ptr) { ptr->CTRL1 = ...; ptr->STATUS = ...; } und ruft das so auf initUART(&UART1); initUART(&UART2);
:
Bearbeitet durch User
Karl H. schrieb: > Normalerweise ist der Versuch so etwas machen zu wollen, ein starker > Hinweis darauf, dass man eigentlich ein Array einsetzen will Aber dann bitte so oder ähnlich:
1 | void bla( uint8_t wert ) |
2 | {
|
3 | if (wert >= 1 && wert <= 2) |
4 | Output[wert-1] = 0x1; |
5 | }
|
Inlined ist das auch nicht schlechter.
:
Bearbeitet durch User
Klaus schrieb: > Nimm an, C1CTRL sei als char * deklariert. Hast du schon mal ein µC-Register gesehen, das als Pointer deklariert wurde? > Dann wäre die Funktion: > funktion (registertyp x) { > x = 7; > } Also so? funktion (char *x) { x = 7; } Das wär erstens ein Fehler und zweitens einfach nur nix.
:
Bearbeitet durch User
Clemens L. schrieb: > Üblicherweise sind solche Registersymbole als "volatile" definiert, und > benutzen irgendeine Compiler-spezifische Magie, um sie an eine feste > Adresse zu legen Nein, keine Magie sondern ganz normales C.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.