Komponenten Helligkeitssensor und Speaker

Der Helligkeitssensor ist vergleichsweise unkritisch. Dieser kann als einfacher Analogeingang wie gehabt realisiert werden. Die Helligkeitswerte müssen dann nur noch als String formatiert werden und dem Datensatz für unsere Log-Datei angefügt werden. Für den Speaker sieht die Sache schon schwieriger aus. Wir finden in den bisher verwendeten UML Paketen keine Lösung für einen Speaker. Zur Erinnerung das Blockbild der bis hier zu nutzenden Bausteine des Systems.

Komponenten entwerfen

Die eleganteste Variante eine Tonfrequenz für den Speaker zu erzeugen ist, einen Timer zu beauftragen dies zu tun. Dabei könnte man ein einfaches Toggeln des gewünschten Pins beauftragen oder Frequenz und Lautstärke der Ausgabe kontrollieren. Letzteres lässt sich durch die Erzeugung eines PWM-Signal realisieren. Da es sich um eine Alarmfunktion handelt klingt die Variante Frequenz und Lautstärke über PWM zu kontrollieren am zweckmäßigsten. Zunächst müssen wir ein geeigneten Pin finden. Dieser sollte in der Nähe des Speakers liegen und über eine Alternativfunktion für Ausgabe durch einen Timer besitzen. Ihnen stehen zur Auswahl geeigneter Anschlusskonfigurationen unterschiedliche Werkzeuge zur Verfügung. Natürlich zum einen das Datenblatt des Controllers, die mySTM32F4 Referenzkarte oder ST-MicroXplorer von ST. In der Vorbereitung des Projektes ist die Wahl auf Pin PE5 gefallen. Dieser liegt sehr nah beim Speaker, ist nicht durch eines der bereits verbundenen Geräte belegt und kann mit dem Kanal 4 des Timer 9 ein PWM-Signal ausgeben. Eine Speakerklasse sollte über folgende Funktionen verfügen:

  • starten mit Frequenz und Lautstärke
  • stoppen
  • Frequenz ändern
  • Lautstärke ändern

Daraus lässt sich folgender Klassenentwurf für den Speaker ableiten:

Da es sich hier nicht um eine allgemeine Klasse für einen Speaker handelt haben wir im Namen der Klasse notiert, dass diese sondern ein PWM mit dem Timer 9 an Pin E5 erzeugt. Die Operation Start überladen wir womit ein Start des Speakers mit Angabe von Frequenz und Lautstärke möglich ist aber auch ein Start ohne Parameter für die Initialisierung mit den Werten aus den Attributen frequenz und volume.

Der betreffende Ausschnitt unseres Klassendiagramms sieht bei bewährter Konstruktion des Lichtsensors und dem obigen Speakerkonzept wie folgt aus:

Ergänzen Sie das Klassendiagramm des Projektes um die gezeigten Elemente.

Komponenten realisieren

Für die Realisierung des Speakers wäre ein PWM-Beispiel hilfreich. Davon finden sich im Netz aber auch in den von ST mitgelieferten Paketen nachvollziehbare Beispiele. Vergleichen Sie dazu auch die Beispiele in diesem Projekt

Das Starten einer PWM-Ausgabe erfordert folgende Schritte:

  1. GPIOx initialisieren
    • GPIO-Takt einschalten
    • Pin im GPIO_Mode_AF konfigurieren
    • Pin Alternativfunktion für TimerX zuweisem
  2. TIMx initialisieren
    • Timer-Takt einschalten
    • Basisinitialisierung = Frequenz
    • PWM-Initialsierung (OutputCompare) = Volume
    • Timer starten
    • PWM-Ausgabe erlauben
start(ton,volume):
Rcc rcc;
 
// GPIOE Pin9 initialisieren
rcc.ahb1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
gpio.initStruct.GPIO_Pin = GPIO_Pin_5;
gpio.initStruct.GPIO_Mode = GPIO_Mode_AF;
gpio.initStruct.GPIO_OType = GPIO_OType_PP;
gpio.initStruct.GPIO_Speed = GPIO_Speed_50MHz;
gpio.initStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
gpio.init(GPIOE);	
gpio.pinAfConfig(GPIO_PinSource5, GPIO_AF_TIM9);
 
// Timer 9 initialisieren
rcc.apb2PeriphClockCmd(RCC_APB2Periph_TIM9 , ENABLE);
tim.timeBaseInitStruct.TIM_Prescaler = 4;
tim.timeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
tim.timeBaseInitStruct.TIM_ClockDivision = 0;
tim.timeBaseInitStruct.TIM_RepetitionCounter = 0;
tim.init(TIM9);
frequency=ton;
tim.timeBaseInitStruct.TIM_Period = ((SystemCoreClock/10) / frequency ) - 1;
tim.timeBaseInit();
tim.ocInitStruct.TIM_OCMode = TIM_OCMode_PWM2;
tim.ocInitStruct.TIM_OutputState = TIM_OutputState_Enable;
tim.ocInitStruct.TIM_OutputNState = TIM_OutputNState_Enable;
tim.ocInitStruct.TIM_OCPolarity = TIM_OCPolarity_Low;
tim.ocInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High;
tim.ocInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set;
tim.ocInitStruct.TIM_OCNIdleState = TIM_OCIdleState_Reset;
tim.ocInitStruct.TIM_Pulse = volume;
tim.ocxInit(1);
tim.cmd(ENABLE);
tim.ctrlPwmOutputs(ENABLE);

Und hier die Operation start ohne Parameter.

start():
this->start(frequency,volume);
stop():
tim.cmd(DISABLE);
tim.ctrlPwmOutputs(DISABLE);
setFrequency(ton):
frequency=ton;
tim.timeBaseInitStruct.TIM_Period = ((SystemCoreClock/10) / frequency ) - 1;
tim.timeBaseInit();
setVolume(level):
tim.ocInitStruct.TIM_Pulse = volume;
tim.ocxInit(1);

Das reicht für eine einfache PWM-Ausgabe. Jetzt können wir die Komponente Testen.

Komponenten einzeln testen

Zum Test schalten wir den Speaker in der Startsequenz einfach an. Diese und die folgenden Codezeile entfernen wir wieder nach dem Test.

onStart:
// nur zum kurzen Test 
speaker.start(400,200);

Wir können beide Komponenten wunderbar miteinander testen indem die Werte vom Lichtsensor an den Speaker gegeben werden. Dabei erreichen wir eine maximale Lautstärke wenn als Volumelevel die Hälfte der Tonfrequenz benutzt wird.

onTimer100ms:
// nur zum kurzen Test 
uint16_t helligkeit;
helligkeit=lichtsensor.getValue();
speaker.setFrequency(helligkeit);
speaker.setVolume(helligkeit/2);
waitMs(200);

Sie können jetzt mit dem Finger den Lichtsensor abdecken und sollten eine entsprechende Änderung der Tonfrequenz deutlich hören. Ich hoffe Sie haben genauso viel Spaß an diesem Test wie ich ;-)

<flashplayer width=„560“ height=„450“ position=„0“>file=http://youtu.be/H8NXbax50zs</flashplayer>

OK, jetzt nervt es :-/ Also weiter im Text :-|

Komponenten integrieren und testen

Entfernen Sie nach erfolgreichem test die Operation onTimer10ms aus der Applikation und die in der Operation onStart enthaltenen Test-Codezeilen. Ergänzen Sie die Operation onWork wie folgt:

onWork
String datensatz,lage="0",trennzeichen="; ",zeilenende="\n";
 
// Zeit und Temperatur ermitteln
zeit=echtzeituhr.getTime("%d.%M.%Y %h:%m:%s");
//temperatur=temperatursensor.getGrad("%G,%K");
int value = temperatursensor.getValue();
temperatur.format("%d,%d",value/10,value%10);
 
//Helligkeit als Text formatieren
value=lichtsensor.getValue();
helligkeit.format("%d,%d",value/100,value%100);
 
if (waechter.isAlarm())
	lage="1";
else
	lage="0";
 
waechter.alarmReset();
 
// Datensatz zusammenbauen
datensatz = zeit+trennzeichen
			+temperatur+trennzeichen
			+helligkeit+trennzeichen
			+lage+zeilenende;
 
terminal.sendString(datensatz);
 
// Datei öffnen
if (sd.logfile.open("/log.csv"))
{
	// Datensatz anhängen
	sd.logfile.append(datensatz);
	sd.logfile.close();
	terminal.sendString("Datensatz wurde geschrieben.\n");
}
else
{
	terminal.sendString("Datei konnte nicht geöffnet werden\n");
}
 
// Test Wartezeit 1 Sekunde bis zum nächsten Zyklus
waitMs(1000);

Erstellen, Übersetzen und Übertragen Sie das Programm. Korrigieren Sie ggf. Schreibfehler im Quelltext. Achten sie darauf, dass eine µSD-Karte mit maximal 1 GB Kapazität und FAT16-Formatierung ordnungsgemäß in den SD-Kartenhalter eingelegt ist bevor das Programm startet. Lassen Sie die Anwendung einige Minuten laufen. Beobachten Sie die Protokollausgaben im SiSy-Controlcenter. Entnehmen sie die SD-Karte und überprüfen Sie den Inhalt der Datei log.csv.

Nächster Schritt