Salut Achim,
wir haben ein grundsätzliches Missverständniss:
Fremdboard: Das Board, das das ganze Sensorsystem nutzt. Das kann ein Arduino, ein chipKIT, ein Raspberry PI, PC oder irgendetwas anderes sein, was I2C oder UART spricht.
Sensor Management Board: Dieses Board beantwortet Sensoranfragen entsprechend der API Befehlsdefinitionen und führt diese aus. Zu den Aufgaben gehören die Auslese des eigentlichen Sensors, die Periodizität der Auslese und die Datenaufbereitung (Mittelwert über bestimmt Zeiträume, beschreibende Statistik wie Standardabweichung, Perzentile etc). Das Sensor Management Board kann (wird wahrscheinlich) ein EEPROM und/oder ein SD Kartenslot haben, um Daten und Einstellungen zu speichern. Alles das ist aber dem Fremdboard herzlich egal, da es nur die Informationen über den Befehlssatz der API abfragt. Das hat den Vorteil, dass ich mich am Fremdboard weder um die Auslese des Sensors noch um die Analyse der Daten kümmern muss. Daher ist die Programmierung des Sensor Management Boards eine Firmware, die ich am besten nicht anfasse und wenn, dann nur um Fehler zu korrigieren oder falls ich den angeschlossenen Sensor ändere.
Der PIC32MX hat ZWEI I2C Busse.
- DTWI0 (der erste I2C-Bus) redet mit dem Fremdboard. der Adressraum diese Busses wird nur von der Masteradresse des Fremdboards und den Slaveadressen des oder der Sensor Management Board(s) sowie weiterer an das Fremdboard angeschlossenen I2C Geräte genutzt
- DTWI1 (der zweite I2C-Bus) redet mit Sensoren, die über I2C ausgelesen werden. Hier ist das Sensor Management Board der Master und alle I2C-Sensoren sind Slaves
Der PIC32MX hat zwei UART Anschlüsse.
- UART0 redet mit dem Fremdboard
- UART1 redet mit Sensoren, die über UART ausgelesen werden
Was soll das Ganze? Nehmen wir eine Analogie: Ich will eine Datenbank benutzen um darin eine Reihe von Tabellen abzulegen. Ich will aber die Tabellenwerte bearbeiten und nicht in die Tiefen der Datenbank abtauchen. Dazu greife ich auf eine generische Datenbank-API zurück, die generalisierte Tabellenzugriffe erlaubt. Die Umsetzung dieser virtuellen, generischen Datenbank auf MS_SQL, ORACLE, MySQL, SQLite, DB2 wird von eben dieser API ausgeführt. So führt die Anforderung einer neuen Tabelle dazu, dass unter Oracle ein Tablespace generiert oder erweitert wird und die Tabelle dort abgelegt wird, während in DB2 die Tabelle in ihrem eigenen File abgelegt wird.
Genauso gehst Du auch vor, wenn Du in einem Programm den Befehl File->New ausführst. Auch hier verwendest Du ein einfaches API um eine komplexe Aktion im Hintergrund auszuführen. Und dabei interessiert es Dich nicht, wie die Datei angelegt wird, dass der Befehl auf SSD anders ausgeführt wird als auf HDD oder Cloud. An deinem Ende der API ist immer das gleiche Ergebnis: Ein Datei neu geöffnet und bereit.
Analog will ich das auf der Welt der Sensoren realisieren: Ich arbeite mit meinem Fremdboard und habe einen Satz von Sensor Management Boards mit angeschlossenen Sensoren, z.B. Temperatur, CCD-Lichtsensor, x/y/z Beschleunigungssensor). Wenn ich diese Sensoren an mein Fremdboard direkt anschließe, muss ich nun alle notwendigen Libraries für mein Fremdboard finden und auf die jeweilige Anschlussart anpassen. Dann muss ich die Auslese programmieren und die Werte speichern. Alles das frisst Speicher und CPU auf meinem Fremdboard. Und mit dem Wechsel auf ein anderes Fremdboard (von Arduino auf MSP430 Launchpad) beginnt alles von neuem.
Mit der API könnte das ganze aber so aussehen:
#include SensorManager.h
SensorManager SMB(I2C, 99); // baue ein Objekt SMB, verwende I2C und Adresse 99
temp = SMB.query(TempSens, SingleQuery); // Anfrage, den aktuellen Temperaturwert zu liefern
result = SMB.set(TempSens, Period, Millis, 1000, 20); // Setze die Messperiode auf 1 Sekunde (1000 Millis), Auslese alle 20 Millis), Fehler werde mit negativen Werten übergeben
tempavg = SMB.query(TempSens, PeriodAvgQuery); // Mittelwert der Messungen
tempstd = SMB.query(TempSens, PeriodStdQuery); // Standardabweichung der Messung
result = SMB.set(XYZaccel, getValues); // Synchrones Auslese der x,y,z Werte
xVal = SMB.query(XYZaccel, xValue); // Abfrage des x Wertes
yVal = SMB.query(XYZaccel, yValue); // Abfrage des y Wertes
result = SMB.set(CCDlight, BinWidth, 100); // Setze die Binweite des Spektrums auf 100 ns
rgbPeak = SMB.query(CCDlight, BinValue, 123); // Lese den Binwert für Bin 123 aus
Diese Befehle kann ich dann auf jedem Fremdboard verwenden. Ich könnte (werde wahrscheinlich) auch die API parallel in Python aufbauen, wäre also nicht mehr an C++ gebunden.
Das Beispiel CCD zeigt besonders die Vorteile der API: Ein CCD (Charge Coupling Device) besteht aus eine Reihe von Lichtsensoren, typischerweise 128-4096. Dieser werden nach dem "Eimerkettenverfahren" ausgelesen. Diese Auslese erfordert ein sehr präzises Timing und muss für jedes Ausleseboard genau eingestellt werden und hängt vom Prozessor und seiner Taktfrequenz ab. Wenn ich das auf meinem Fremdboard realisiere, stehen mir heimelige Stunden im fahlen Licht des Oszilloskops bevor. Dann will ich den Arduino gegen einen MSP430 tauschen - und den gibt es dann auch noch in 8MHz, 16MHz und 25MHz. Mit dem Sensor Management Board interessiert mich das nicht, der Befehl ist der gleiche.
Als Analyse kann ich zum Beispiel einen FFT auf das Frequenzspektrum anwenden oder andere komplexe Analysen programmieren, bis der Speicher von 128 bzw. 256 kB des PIC voll ist. In der Zukunft kann ich mir auch aufwändiger Sensor Management Boards vorstellen, die auf der PIC32MZ Serie aufgebaut sind (200 MHz, 2 MB Speicher) aber das ist ferne Zukunftsmusik.
Für einen einfachen Temperatur-NTC ist die API und das Sensor Management fast schon Overkill. Sobald die Sensoren etwas anspruchsvoller werden, spielt die API ihre Vorzüge aus. Wenn dann noch die Statistikfunktionen dazu kommen, ist selbst ein einfacher Temperatursensor besser über die API ausgelesen. Außerdem möchte ich gerne meine Zeit auf mein Programm verwenden, statt herauszufinden wie ich den allseits bekannten LM75 auslese.
Ich hoffe, diese (leider recht lange) Exkurs hat Dir etwas geholfen. Es ist immer schwer, seine Ideen so zu formulieren, dass sie von Anderen verstanden werden. Diese Bringschuld liegt bei mir.
Ciao, Mathias