Forum: Mikrocontroller und Digitale Elektronik Register ansprechen µC


von Dirk P. (crunso)


Lesenswert?

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
von Manuel (Gast)


Lesenswert?

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.

von Klaus (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

Dirk P. schrieb:
> bla (wert)
> {
>     CwertCTRL = 0x1;
> }

Hast du die letzten Jahrzehnte verpennt? K&R Deklarationen sind seid 
einem Vierteljahrhundert veraltet.

von (prx) A. K. (prx)


Lesenswert?

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
von Dirk P. (crunso)


Lesenswert?

Das verstehe ich nicht ganz.
Und wie ändere ich jetzt das je nach Übergabeparameter das C1 oder C2 
Register anspreche?

von Klaus (Gast)


Lesenswert?

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
}

von Dirk P. (crunso)


Lesenswert?

Ahhh danke :)

von Clemens L. (c_l)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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
von (prx) A. K. (prx)


Lesenswert?

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
von (prx) A. K. (prx)


Lesenswert?

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
von (prx) A. K. (prx)


Lesenswert?

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
von Bernd K. (prof7bit)


Lesenswert?

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
Noch kein Account? Hier anmelden.