Forum: Mikrocontroller und Digitale Elektronik [C] Bibliotheken für z.B. Display, CAN-Controller, (.) portierbar gestalten


von Heiko L. (drcaveman)


Lesenswert?

Hallo!

Ich versuche gerade meine Bibliotheken für externe Bausteine an µCer zu 
überarbeiten, so dass sie portierbar werden (und zwar Projekt- und 
µC-bezogen).

Da kommen dann ja irgendwann so Probleme auf wie z.B. bei einem HD44780, 
der mit vier oder acht Datenleitungen angeschlossen oder nicht immer an 
PortX angeschlossen sein kann (Projektbezogen).

Meine Lösung ist im Moment in den Bibliotheken solche "Schnittstellen" 
als externe Funktionen zu deklarieren.

So muss man diese halt in seinem Prozessorspezifischen teil definieren 
um die Bibliothek zu nutzen.

Ist das so schon die richtige Richtung oder geht das auch eleganter?

Bin gespannt,
Heiko

von Cani (Gast)


Lesenswert?

Hi,

abstrahiere die Hardware in eine low-level Schicht und arbeite dann nur 
noch mit Interfaces. Soetwas nennt man Schichtentrennung oder 
Softwarelayer. Der eigentlichen Application ist es dann egal, welche 
Hardware darunter liegt.
Deiner eigentlichen Application ist es auch egal, ob das Display über 4 
oder 8 Leitungen angeschlossen ist.

Application
|
Interfaces
|
Basis Software
|
Hardware


Bei CAN wäre es dann Funktionen z.B. (C-Pseudo-Code)

can_init(baudrate)
can_transmit(msg)
msg = can_receive()

die low-level Funktionen der einzelnen Targets packt man in eine Libs 
und linkt die passende zur Application.

Grüße

von Stefan F. (Gast)


Lesenswert?

Die Hardware spezifischen Sachen mache ich gerne mit Makros, welche dann 
von meinen Anwendungen und Libraries verwendet werden. Zum Beispiel:

#define POWER_LED_AN PORTA | =8;
#define POWER_LED_AUS PORTA &= ~8;

von Heiko L. (drcaveman)


Lesenswert?

Bleiben wir mal beim CAN- Controller und sagen wir mal, dass er per SPI 
kommuniziert.

Nehmen wir jetzt einmal die Funktion "can_transmit(msg)", die von der 
CAN_IC- Bibliothek bereitgestellt werden soll.

Die Funktion liegt in der Bibliothek, um mit dem Baustein selbst zu 
kommunizieren braucht man aber die "SPI- Kommandos" des µCs.

Mein Ansatz war jetzt eine Funktion, z.B. uc_sendto_can_ic(data), in der 
Bibliothek als extern zu deklarieren.

Auf der Seite die "einbindet" muss man diese Funktion dann definieren 
(das wäre dann das Interface?) und dafür sorgen, dass "data" an den 
CAN-Baustein gesendet wird. Das wäre dann ja quasi nur das low-level 
Zeugs, also der Hardware abhängige Code.

Da wäre dann getrennt Anwendung, µC- Interface, Baustein- "Treiber".

Das wäre also so schon ganz gut oder verstehe ich da etwas immer noch 
nicht?

Mit den Makros wäre das Obige glaube ich etwas zu komplex?

von Tom (Gast)


Lesenswert?

Heiko L. schrieb:
> Das wäre also so schon ganz gut

Ja. Das wäre quasi die Essenz von dependency injection in C umgesetzt. 
Viel eleganter geht es in C nicht.

Wenn Du irgendwann deine Bibliothek auf dem PC testen willst, kannst du 
ihr (vereinfacht) eine uc_sendto_can_ic(data) unterschieben, die data 
nach stdout loggt und eine uc_readfrom_can_ic(), die Testdaten liefert.

von Cani (Gast)


Lesenswert?

Nein, so war das nicht gemeint. Nichts hardwareabhänginges in der 
Application. Deine Lib implementiert die Funktion. Du bindest
nur die H-Datei ein, die für alle Hardwarevarianten gleich ist und baust 
für jede Hardwarevariante eine eigene Lib.

Z.B.

geinsamer Header (Prototype):

extern void CanInit(...);

Für Hardware A (Implementierung):

void CanInit(...) {
   spi_init(...);   /* can over spi */
}

Für Hardware B (Implementierung):

void CanInit(void) {

   CanControllerInit(...);
}

von Steffen R. (steffen_rose)


Lesenswert?

Heiko L. schrieb:
> Da kommen dann ja irgendwann so Probleme auf wie z.B. bei einem HD44780,
> der mit vier oder acht Datenleitungen angeschlossen oder nicht immer an
> PortX angeschlossen sein kann (Projektbezogen).

Ich trenne die allgemeine Peripheriefunktionalität von der 
Hardwareinitialisierung.

Für das hier verwendete CAN Beispiel bedeutet dies:
CanInit()
greift nur auf den CAN selbst zu.
Am besten noch ein variabler Pointer/Handle, wenn dein Controller/deine 
Bibliothek mehrere gleichartige Periperiemodule unterstützt, z.B. 
mehrere CAN Controller.

Heiko L. schrieb:
> Meine Lösung ist im Moment in den Bibliotheken solche "Schnittstellen"
> als externe Funktionen zu deklarieren.

Genau. Auch bei mir gibt es an anderer Stelle die Hardware-Funktionen, 
welche den CAN-Takt und die Alternate-Function Konfiguration einstellen.
Auch die Interrupthandler definiere ich außerhalb und verzweige von dort 
dann in die Lib. Einfach, da die Namensgebung manchmal fest ist.

Innerhalb der Lib nutze ich nur in den seltensten Fällen externe Low 
Level Funktionen. Ich würde es aber machen, wenn die Lib einen Zugriff 
nach außerhalb benötigt.

Cani schrieb:
> abstrahiere die Hardware in eine low-level Schicht und arbeite dann nur
> noch mit Interfaces. Soetwas nennt man Schichtentrennung oder
> Softwarelayer. Der eigentlichen Application ist es dann egal, welche
> Hardware darunter liegt.

Zustimmung. Meine Aussage, welche sich mit dem Vorschlag vom TO deckt, 
legt die Trennung auf einen sehr niedrigen Layer 
(Hardwarekonfiguration).

Cani schrieb:
> nur die H-Datei ein, die für alle Hardwarevarianten gleich ist und baust
> für jede Hardwarevariante eine eigene Lib.

Dies wäre dann eine Ebene höher. Du erstellst z.B. eine Library für ein 
Protokoll (CANopen) und möchtest diese mit den verschiedenen CAN 
Controllern nutzen.

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.