Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial Internet of Things >> Eingebettet

Anbindung an moderne Sensoren:Abgefragte ADC-Treiber

Im letzten Beitrag haben wir untersucht, wie ein Entwickler in einer modernen eingebetteten Anwendung eine Schnittstelle erstellen sollte, die die Low-Level-Treiberimplementierungsdetails vom Anwendungscode entkoppelt. Diese Schnittstelle bietet eine architektonische Abstraktion, die die Skalierbarkeit und Portabilität des Anwendungscodes erhöht, indem sie weniger abhängig von der Hardware wird.

Jetzt werden wir uns verschiedene Möglichkeiten ansehen, wie ein Entwickler einen ADC-Treiber implementieren kann, basierend auf den Techniken, die wir in 3 Treiberdesigntechniken für Mikrocontroller besprochen haben. In diesem Artikel werden wir genauer untersuchen, wie wir die Polling-Technik verwenden können und den Unterschied zwischen blockierenden und nicht blockierenden Treibern diskutieren.

Blockieren oder nicht blockieren, das ist die Frage

Bei der Entwicklung eines Treibers für einen Mikrocontroller muss ein Entwickler entscheiden, ob sein Treiber blockierend oder nicht blockierend ist. Ein blockierender Treiber hält die Codeausführung im Wesentlichen an, bis der Treiber seine Aufgabe abgeschlossen hat. Die typische Implementierung für printf, die einem UART zugeordnet ist, ist beispielsweise das Blockieren.

Wenn Sie einen Anruf tätigen wie:

printf("Hallo Welt!");

Ein Entwickler weiß, dass jede Codezeile, die dieser Anweisung folgt, nicht ausgeführt wird, bis das gesamte "Hello World!" -Anweisung wurde der UART ausgedruckt. "Hallo Welt!" enthält zwölf Byte, 96 Bit, aber die Zeitdauer, die die Anweisung blockiert, hängt von der UART-Baudrate ab. Für einen mit 1 Mbit/s konfigurierten UART würden Sie etwa 96 Mikrosekunden erwarten. Für einen mit 9600 bps konfigurierten UART würden Sie etwa 10.000 Mikrosekunden erwarten! Das ist ein großer Unterschied, je nachdem, wie die Hardware konfiguriert ist, und kann die Programmausführung dramatisch beeinflussen, wenn der UART-Treiber als blockierender Treiber konfiguriert ist.

Ein nicht blockierender Treiber ist einer, der die Programmausführung nicht anhält, während der Treiber seine Aufgabe erledigt. Beispielsweise könnten printf und der UART-Treiber aus dem vorherigen Beispiel so konfiguriert werden, dass er nicht blockiert und stattdessen der Anwendung ermöglicht, die Ausführung fortzusetzen, während jedes Byte aus dem UART übertragen wird. Dies kann unter den richtigen Umständen für eine effizientere Anwendung sorgen, erfordert jedoch zusätzliche Einstellungen wie die Verwendung von Interrupts, DMA oder zumindest eines Sendepuffers.

Die Entscheidung, wie Sie Ihren Treiber entwerfen, hängt von Ihrer Anwendung und Hardware ab. Wenn der UART beispielsweise für 1 Mbit/s konfiguriert ist, bringt das Schreiben eines nicht blockierenden Treibers aus Effizienzgesichtspunkten wahrscheinlich nicht viel und könnte durch zusätzliche Programmkomplexität tatsächlich mehr Probleme verursachen als behebt. Wenn die Anwendung jedoch 9600 bps erfordert und der Anwendungscode für 10 Millisekunden blockiert wird, kann ein nicht blockierender Treiber die Programmeffizienz dramatisch verbessern und das Risiko für zusätzliche Probleme mit der Timing-Komplexität ist viel geringer und besser beherrschbar.

Überblick über einen eingebetteten ADC-Treiber

Es ist wichtig zu beachten, dass ich in einem einzigen Blog nicht alle Schritte ausführen kann, die zum Schreiben eines vollständigen ADC-Treibers erforderlich sind. Ich könnte leicht ein zwanzigseitiges Papier darüber schreiben oder ein ganzes Webinar geben, und es würde wahrscheinlich nicht alle Details abdecken, aber wir können uns zumindest einige der Kernstücke ansehen.

Es gibt mehrere Möglichkeiten, einen ADC-Treiber zu organisieren, aber die Art und Weise, wie ich sie organisieren möchte, erfordert drei Komponenten:

Der Low-Level-Treiber übernimmt das Konfigurationsmodul während der Initialisierung und richtet die Hardware basierend auf der Konfiguration ein. Der Low-Level-Treiber stellt eine gemeinsame Hardwareabstraktionsschicht (HAL) bereit, die der Anwendungscode dann verwenden kann. Die ADC-HAL-Aufrufe sollten generisch sein, damit die High-Level-Anwendung die Hardware auf jede erforderliche Weise konfigurieren kann und damit sie wiederverwendbar und skalierbar ist. Einige ADC HAL-Aufrufe, die ich in der Vergangenheit verwendet habe, sind beispielsweise:

Die ersten drei APIs bieten die Möglichkeit, die ADC-Hardware zu initialisieren, eine Konvertierung zu starten und dann den Konvertierungsstatus zu überprüfen. Die letzten drei Funktionen wurden entwickelt, um eine Skalierbarkeit auf die Low-Level-Hardware zu ermöglichen. Wenn die HAL beispielsweise keine von der Anwendung benötigte Option wie das Konvertieren eines einzelnen ADC-Kanals bereitstellt, kann die HAL mit den Funktionen Adc_RegisterRead und Adc_RegisterWrite erweitert werden. Dies bietet Flexibilität basierend auf den Anwendungsanforderungen, ohne eine überwältigende API zu erstellen.

Einen einfachen blockierenden ADC-Treiber schreiben

Wir können einen wirklich einfachen ADC-Treiber schreiben, der sich über der Hardwareschicht befindet. Beispielsweise können wir eine einfache Funktion namens Adc_Sample erstellen, die die ADC-Hardware startet und dann alle Ergebnisse in einem Puffer speichert, auf den dann die Anwendung zugreifen kann. Der Puffer, der die Zählwerte der Analogwerte speichert, muss nicht unbedingt nur einen einzelnen Wert speichern, sondern kann mehrere Werte speichern, die später je nach Anwendungsbedarf gemittelt oder gefiltert werden können. Die Blockierungsversion für die Sampling-Funktion könnte etwa so aussehen:

Wie Sie in diesem Code sehen können, blockiert die while-Schleife die Ausführung, bis die ADC-Hardware ihre Konvertierung abgeschlossen hat, und speichert dann die Werte im Anwendungspuffer.

Einen einfachen nicht blockierenden ADC-Treiber schreiben

Die Konvertierung des blockierenden Treibers in nicht blockierenden Code ist recht einfach, erfordert jedoch Änderungen am Anwendungscode der höheren Ebene. Wenn die Anwendung beispielsweise gerade die Sensoren abtasten möchte, ruft ein Entwickler an:

Adc_Sample();

In der nicht blockierenden Version muss ein Entwickler den Rückgabewert von Adc_Sample überprüfen, um zu sehen, ob die Beispiele abgeschlossen und einsatzbereit sind. Dadurch können die Beispiele im Hintergrund ausgeführt werden, der Anwendungscode kann mit den folgenden Aktualisierungen unseres Treibercodes weiter ausgeführt werden:

Schlussfolgerungen

Wie wir in diesem Beitrag gesehen haben, gibt es mehrere Möglichkeiten, einen ADC zu schreiben, und die Implementierung kann je nach Bedarf blockierend oder nicht blockierend sein. Blockierende Treiber sind in der Regel einfacher und weniger vollständig als nicht blockierende Treiber, können jedoch ineffizient sein. Nicht blockierende Treiber ermöglichen die Ausführung von anderem Code, während der Treiber funktioniert, aber der Anwendungscode muss trotzdem den Status überprüfen, was an sich in einer abgefragten Implementierung ineffizient ist.

Im nächsten Artikel dieser Serie werden wir untersuchen, wie wir eine Anwendung schreiben können, die einen Sensor über ein ADC-Peripheriegerät abtastet, das Interrupts verwendet.


Eingebettet

  1. Sensortypen mit ihren Schaltplänen
  2. Bulgin:kostengünstige IIoT-Lösungen mit neuen schlanken optoelektronischen Sensoren
  3. ams beleuchtet die Sensors Expo 2019 mit innovativen Demonstrationen
  4. DATA MODUL erweitert das Touchsensor-Portfolio um noch größere Größen
  5. Contrinex:Cloud-fähige intelligente Sensoren und Sicherheits-Lichtvorhänge mit Bluetooth-Schnittstelle
  6. Integrierte Treiber erleichtern das Design von Schrittmotoren
  7. Kontrollieren eines Effekts mit echten Sensoren
  8. Lesen analoger Sensoren mit einem GPIO-Pin
  9. Anbindung des PIR-Bewegungssensors HC-SR501 an Raspberry Pi
  10. Verbesserte Überwachung der Luftverschmutzung mit IoT-Sensoren