Den Beschleunigungssensor nutzen

Den Bewegungssensor wollen wir genau für das nutzen wofür er entwickelt wurde, Bewegung feststzuellen. Der auf dem STM32F4-Discovery verbaute Bewegungssensor ist ein mikromechanischer (MEMS) Beschleunigungssensor (Accelerometer). Er ermittelt die Beschleunigung in 3 Achsen X,Y und Z. Die ermittelten Werte können per SPI oder I²C ausgelesen werden.

Auf dem STM32F4-Discovery,Version B ist der Bewegungssensor LIS302D verbaut; auf den Version C und D der LIS3DSH (Stand 2016).

Die Aufgabe soll darin bestehen, festzustellen, in welche Richtung das Board bewegt wurde und dies über die LEDs anzeigen. Eine Differenzierung der Bewegungsrichtung über die leuchtenden LEDs wird eher schwierig, weil der Sensor sehr empfindlich ist. Da bei der kleinsten Bewegung Beschleunigungen in alle Richtungen detektiert werden, soll die Lösung eher grobmotorischer Natur sein. Derartige Nutzerinteraktionen kennen wir von den derzeit sehr beliebten Smartphones. Wir streicheln nicht nur, sondern rütteln und schütteln unser Telefon auch ab und an.

Falls Sie jetzt noch das Klassendiagramm geöffnet haben, wählen Sie im Kontextmenü des Diagramms den Menüpunkt nach oben. Falls das Projekt nicht mehr geöffnet ist, öffnen Sie das SiSy UML-Projekt wieder. Legen Sie ein neues Klassendiagramm an, wählen Sie die Sprache ARM C++ und stellen Sie die Hardware (STM32F407) ein. Beim Öffnen des Diagramms laden Sie aus dem SiSy LibStore die Diagrammvorlage Application Grundgerüst für PEC Anwendungen (XMC, STM32, AVR). Weisen Sie das Treiberpaket für STM32F4 zu.

Natürlich schauen wir uns zuerst im Framework um, ob es eine Treiberklasse für den Bewegungssensor gibt. Die wollen wir uns als Erstes näher betrachten. Über den Explorer oder den Navigator/UML-Pakete lassen sich die einzelnen Bausteine erreichen. Es ergibt sich folgendes Gesamtbild zu der vorhandenen Lösung für den Bewegungssensor:

Aus dem Schaltplan für das STM32F4-Discovery ist zu entnehmen, dass der Bewegungssensor fest mit dem Baustein SPI1 des Controllers verbunden ist. Die Leitung CS (chip select) ist fest mit Pin PE3 verbunden. Das Protokoll zum Auslesen der Beschleunigungswerte ist in der Operation getAcc realisiert. Diese erwartet für X, Y und Z als Referenzparameter drei vorzeichenbehaftete 32-Bit Werte. Damit lässt sich die geforderte Lösung in folgendem Blockbild skizzieren:

Der Bewegungssensor ist an SPI1 angeschlossen, als Datenverbindung zum PC nutzen wir die bewährte USART3. Die optische Anzeige der Beschleunigung soll über die LEDs an PD12, PD13 und PD14 erfolgen. Das ist der Plan!

Der Bewegungssensor ist laut Datenblatt des STM32F4-Discovery an SPI1 angeschlossen. Das Framework bietet uns für diesen Sensor die oben vorgestellte Treiberklasse. Die Beschleunigungswerte sollen für die Achsen X, Y und Z über drei LEDs und via UART ausgegeben werden. Der Klassenentwurf für die angestrebte Lösung sieht wie folgt aus:

Hinweis: Versionsabhängig ist ein unterschiedlicher Bewegungssensor auf dem Board verbaut. Dementsprechend ist die verfügbare Klasse auszuwählen.

  • Version B: MotionSensorLis302dl
  • Versionen C und D: MotionSensorLis3dsh
Controller::onWork:
// aktuelle Sensorwerte holen
// WENN x>0 DANN LED1 an SONST aus
// WENN y>0 DANN LED2 an SONST aus
// WENN z>0 DANN LED3 an SONST aus
// Werte als Text formatieren
// Text per UART senden

Die Realisierung soll in zwei Schritten erfolgen. Zunächst wollen wir einfach nur die aktuellen Werte für die drei Achsen sehen. Diese schicken wir per UART an das SiSy-Controlcenter. Über die LEDs visualisieren wir, ob die Werte größer oder kleiner Null sind.

Controller::onstart
motion.connect(spiMaster);
motion.init();
Controller::onWork:
waitMs(200);
///////// Motion
int16_t x,y,z;
motion.getAcc(x,y,z);
if (x>0) led1.on(); else led1.off();
if (y>0) led2.on(); else led2.off();
if (z>0) led3.on(); else led3.off();
///////// per UART senden
String txt;
txt.format("Motion=%d,%d,%d\n",x,y,z);
com.writeString( txt );

Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers. Verbinden Sie RxD mit PD8, verwenden Sie Patchkabel.

  1. Erstellen (Kompilieren und Linken)
  2. Brennen
  3. Verbindung herstellen
  4. ControlCenter starten

Die im Controlcenter angezeigten Werte lassen darauf schließen, dass der Sensor neben Beschleunigungswerten auch Lagewerte liefert. Jede Lage des Boards zeigt reproduzierbare Werte. Technisch gesehen befinden sich in dem Sensor drei winzige federnd gelagerte seismische Massen (Feder-Masse-System) in X-, Y- und Z-Anordnung. Natürlich liefern diese Sensorelemente nicht nur Veränderungen der Lage (Beschleunigung), sondern auch in Ruheposition definierte Werte entsprechend der Erdanziehungskraft, die auf die seismische Masse der jeweiligen Achse wirkt (Erdbeschleunigung).

Im ersten Anlauf haben wir die absoluten Werte zyklisch erfasst und ausgewertet. Im zweiten Anlauf wollen wir die Änderung als die Differenz zwischen zwei Messungen auswerten. Der Einfachheit halber erst mal nur für die Y-Achse. Dabei sollen positive und negative Veränderungen in Y-Richtung unterschieden werden. Parallel zur Anzeige über die LEDs soll ein UART-Protokoll mitlaufen.

Controller::onWork:
// Delta festlegen
// Textbuffer leeren
// aktuelle Werte vom Sensor holen
// WENN  LED1 nicht an UND Y-Beschleunigung größer Delta DANN
//    LED1 an
//    LED2 aus
//    Text="+Y"
// WENN  LED2 nicht an UND Y-Beschleunigung kleine -Delta DANN
//    LED1 aus
//    LED2 an
//    Text="-Y"
 
// WENN  Text nicht leer ist DANN
//	sende den Text	
//      warte bis das Board ruhig liegt
//	motion.getAcc(x,y,z); 
//      aktuelle Werte vom Sensor holen
// alten Sensorwert speichern

Die erste Lösung war geeignet Werte zu ermitteln, die eine bestimmte Lage des Boards repräsentieren. Die folgende Erweiterung soll ermitteln, ob das Board in eine bestimmte Richtung bewegt wurde. Die Empfindlichkeit der Beschleunigungsmessung soll dabei einstellbar realisiert werden. So können unbeabsichtigte kleine und langsame Bewegungen von bewusst ausgeführten Bewegungen, zum Beispiel das Schütteln des Boards, unterschieden werden.

Controller::onWork:
static int16_t oldValueY=0;
int16_t x,y,z,delta;
delta=100;
 
motion.getAcc(x,y,z);
 
String txt;
txt.clear();
 
if ((led1.getState()==false)&&(oldValueY-y)>delta)
{
		led1.on();
		led2.off();
		txt.addContent("+Y");
}
if ((led2.getState()==false)&&(y-oldValueY)>delta)
{
		led1.off();
		led2.on();
		txt.addContent("-Y");
}
 
 
if (txt.getSize()>0)
{
	com.writeString( txt );		
	waitMs(500); // entprellen
	motion.getAcc(x,y,z); 
}
 
oldValueY=y;

Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers.

  1. Erstellen (Kompilieren und Linken)
  2. Brennen

Das Anstupsen des Boards wird jetzt über die LEDs signalisiert. Es ist leicht möglich die Bewegung explizit nur in einer Richtung zu ermitteln. Na wenn dass nicht der erste Ansatz für eine Spielsteuerung ist ;-)

Videozusammenfassung

Erlernte und gefestigte Arbeitsschritte:

  1. Klassendiagramm anlegen und öffnen
  2. Diagrammvorlage für PEC Applikation auswählen, laden und Treiberpaket für STM32F4 einfügen - Navigator auf UML Pakete umschalten
  3. gewünschte Klasse im Explorer suchen und ins Diagramm ziehen
  4. Klassen aggregieren
  5. Templates anlegen und Realisierungsparameter festlegen
  6. Operationen anlegen und in eine Klasse/Template einfügen
  7. Klassen und Templates zu Komponenten zusammenbauen
  8. den nötigen Quellcode in den Operationen erstellen
  9. Erstellen und Brennen einer ARM Applikation im Klassendiagramm

Und hier diesen Abschnitt wiederum als Videozusammenfassung:

Übung

Ändern Sie zur Übung die Anwendung so ab, dass die vier LEDs die Bewegungsrichtung des Boards in alle vier Richtungen in der Ebene anzeigen. Änderungen der Höhenlage des Boards können Sie vernachlässigen.

Nächstes Thema