Ich suche nach C++-Abstraktionen für Hardware-E/A-Punkte oder Pins. Dinge wie in_pin, out_pin, inout_pin, vielleicht open_collector_pin usw.
Ich kann sicherlich selbst mit einer solchen Reihe von Abstraktionen aufwarten, also suche ich nicht nach Antworten der Art „Hey, Sie könnten es so machen“, sondern eher nach „Schauen Sie sich diese Bibliothek an, die in diesem und diesem und verwendet wurde dieses Projekt'.
Google hat nichts gefunden, vielleicht weil ich nicht weiß, wie andere das nennen würden.
Mein Ziel ist es, E / A-Bibliotheken zu erstellen, die auf solchen Punkten basieren, aber auch solche Punkte bereitstellen, sodass es beispielsweise einfach wäre, ein HD44780-LCd entweder an die E / A-Pins des Chips oder an ein I2C (oder SPI) anzuschließen. E/A-Extender oder jeder andere Punkt, der irgendwie gesteuert werden kann, ohne dass sich die LCD-Klasse ändert.
Ich weiß, dass dies am Elektronik-/Software-Rand liegt, tut mir leid, wenn es nicht hierher gehört.
@leon: Verkabelung Das ist eine große Tüte Software, ich muss genauer hinsehen. Aber es scheint, dass sie keine Pin-Abstraktion verwenden, wie ich es möchte. Zum Beispiel in der Tastaturimplementierung, die ich sehe
digitalWrite(columnPins[c], LOW); // Activate the current column.
Dies impliziert, dass es eine Funktion (digitalWrite) gibt, die weiß, wie auf einen I/O-Pin zu schreiben ist. Dies macht es unmöglich, einen neuen I/O-Pin-Typ hinzuzufügen (z. B. einen, der sich auf einem MCP23017 befindet und daher über I2C geschrieben werden muss), ohne die DigitalWrite-Funktion neu zu schreiben.
@Oli: Ich habe ein Arduino IO-Beispiel gegoogelt, aber das scheint ungefähr den gleichen Ansatz zu verwenden wie die Wiring-Bibliothek:
int ledPin = 13; // LED connected to digital pin 13
void setup(){
pinMode(ledPin, OUTPUT); // sets the digital pin as output
}
Kurze Antwort: Leider gibt es keine Bibliothek, die das macht, was Sie wollen. Ich habe es selbst viele Male gemacht, aber immer in Nicht-Open-Source-Projekten. Ich erwäge, etwas auf GitHub zu veröffentlichen, bin mir aber nicht sicher, wann ich das kann.
Warum C++?
Erlauben Sie mir, mein Open-Source-Projekt https://Kvasir.io schamlos anzuschließen . Der Kvasir::Io-Teil bietet Pin-Manipulationsfunktionen. Sie müssen zuerst Ihren Pin mit einer Kvasir::Io::PinLocation wie folgt definieren:
constexpr PinLocation<0,4> led1; //port 0 pin 4
constexpr PinLOcation<0,8> led2;
Beachten Sie, dass dies nicht wirklich RAM verwendet, da es sich um constexpr-Variablen handelt.
In Ihrem gesamten Code können Sie diese Pin-Positionen in „Action Factory“-Funktionen wie makeOpenDrain, set, clear, makeOutput usw. verwenden. Eine 'Action Factory' führt die Aktion nicht wirklich aus, sondern gibt eine Kvasir::Register::Action zurück, die mit Kvasir::Register::apply() ausgeführt werden kann. Der Grund dafür ist, dass apply() die ihm übergebenen Aktionen zusammenführt, wenn sie auf ein und dasselbe Register wirken, so dass ein Effizienzgewinn entsteht.
apply(makeOutput(led1),
makeOutput(led2),
makeOpenDrain(led1),
makeOpenDrain(led2));
Da das Erstellen und Zusammenführen von Aktionen zur Kompilierzeit erfolgt, sollte dies denselben Assembler-Code wie das typische handcodierte Äquivalent ergeben:
PORT0DIR |= (1<<4) | (1<<8);
PORT0OD |= (1<<4) | (1<<8);
Das Wiring-Projekt verwendet eine solche Abstraktion:
und der Compiler ist in C++ geschrieben. Sie sollten viele Beispiele im Quellcode finden. Die Arduino-Software basiert auf Wiring.
In C++ ist es möglich, eine Klasse zu schreiben, sodass Sie E/A-Ports verwenden können, als wären sie Variablen, z
PORTB = 0x12; /* Auf einen 8-Bit-Port schreiben */ wenn (RB3) LATB4 = 1; /* Ein E/A-Bit lesen und ein anderes bedingt schreiben */
ohne Rücksicht auf die zugrunde liegende Implementierung. Wenn man beispielsweise eine Hardwareplattform verwendet, die keine Operationen auf Bitebene, aber Registeroperationen auf Byteebene unterstützt, könnte man (wahrscheinlich mit Hilfe einiger Makros) eine statische Klasse IO_PORTS mit einem Inline-Lesen-Schreiben definieren Eigenschaften namens bbRB3 und bbLATB4, so dass die letzte obige Anweisung zu werden würde
Wenn (IO_PORTS.bbRB3) IO_PORTS.bbLATB4 = 1;
was wiederum zu so etwas verarbeitet würde:
if (!!(PORTB & 8)) (1 ? (PORTB |= 16) : (PORTB &= ~16));
Ein Compiler sollte in der Lage sein, den konstanten Ausdruck im ?:-Operator zu bemerken und einfach den "wahren" Teil einzufügen. Es ist möglicherweise möglich, die Anzahl der erstellten Eigenschaften zu reduzieren, indem die Makros auf etwas wie das folgende erweitert werden:
Wenn (IO_PORTS.ppPORTB[3]) IO_PORTS.ppPORTB[4] = 1;
oder
Wenn (IO_PORTS.bb(addrPORTB,3)) IO_PORTS.bbPORTB(addrPORTB,4) = 1;
aber ich bin mir nicht sicher, ob ein Compiler in der Lage wäre, den Code so gut einzufügen.
Ich möchte auf keinen Fall andeuten, dass es unbedingt eine gute Idee ist, E/A-Ports so zu verwenden, als wären sie Variablen, aber da Sie C++ erwähnen, ist es ein nützlicher Trick, es zu wissen. Meine eigene Vorliebe in C oder C++ wäre, wenn die Kompatibilität mit Code, der den oben genannten Stil verwendet, nicht erforderlich wäre, wahrscheinlich eine Art Makro für jedes E/A-Bit zu definieren und dann Makros für "readBit", "writeBit", "setBit" und "clearBit" mit der Maßgabe, dass das an diese Makros übergebene Bit-identifizierende Argument der Name eines E/A-Ports sein muss, der für die Verwendung mit solchen Makros vorgesehen ist. Das obige Beispiel würde beispielsweise geschrieben werden als
if (readBit(RB3)) setBit(LATB4);
und übersetzt als
if (!!(_PORT_RB3 & _BITMASK_RB3)) _PORT_LATB4 |= _BITMASK_LATB4;
Das wäre ein bisschen mehr Arbeit für den Präprozessor als der C++-Stil, aber es wäre weniger Arbeit für den Compiler. Es würde auch eine optimale Codegenerierung für viele E/A-Implementierungen und eine anständige Codeimplementierung für fast alle ermöglichen.
Wenn Sie nach etwas wirklich Großartigem suchen, um die Hardware zu abstrahieren, und Sie sich auf Ihre C++-Kenntnisse verlassen können, sollten Sie dieses Muster ausprobieren:
https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
Ich habe es in einem Versuch verwendet, Hardware für einen Cortex-M0-Chip zu abstrahieren. Ich habe noch nichts über diese Erfahrung geschrieben (ich werde es eines Tages tun), aber glauben Sie mir, dass es wegen seiner statischen polymorphen Natur sehr nützlich war: dieselbe Methode für verschiedene Chips, kostenlos (im Vergleich zu dynamischer Polymorphie).
Majenko
Wouter van Ooijen
Oli Glaser
Majenko
Majenko
sternenblau
Wouter van Ooijen
Wouter van Ooijen
Wouter van Ooijen