Anwendung in Javascript - Animierte Partitur
(EN google-translate)
(PL google-translate)
Grundidee: Drei Musiker sollen über drei LED-Anzeigen angezeigt bekommen, welche Zählzeit gerade ist und ob sie gerade im Moment einen Ton zu spielen haben.
Hintergrund: Sie haben Noten als Papierkopie vorliegen, die am Bildschirm in einer Webanwendung in Echtzeit generiert werden. Um nun synchron mit der in der Webanwendung animierten Partitur spielen zu können, bekommen die Musiker Lichtsignale.
Genau 8 LEDs werden verwendet:
|
Das Ganze wird mit drei angeschlossenen Arduino-Micro-Boards realisiert.
Der Gesamte Leuchtzustand der einzelnen Arduino-Anwendungen würd über ein einziges Zeichen gesteuert: Dieses hat 8 Bit. Jedes Bit steht dafür, ob die korresponiderende Bit-LED leuchten soll (1) oder nicht (0):
Die Arduino-Kommunikation ist also Byte-basiert und nicht ASCII-basiert.
Auslesen eines Tasterzustandes
Um einen Neustart der Partitur mit Vorzählen auszulösen, wird zusätzlich auf dem Arduino-Board eine Taste verbaut, die am digitalen Pin 0 und Masse angeschlossen ist.
Wird diese gedrückt, so zählt die "Ampel" in drei mal vier Zählzeiten herunter. Erst dann beginnt das Stück.
Bild 0-1: Aufbau der drei Steckplatinen.
Arduino-Programm
//Random Cloud Composition (c) Guido Kramann, Potsdam, Germany //TON BIT //D3-D4 7 //+ - //BIT: //6 5 4 3 //1 2 3 4 //D5-D6 D7-D8 D9-D10 D11-D12 //+ - + - + - + - //BIT: //2 1 0 //rot gelb grün //A5-A4 A3-A2 A1-A0 //+ - + - + - //D23-22 D21-20 D19-18 char c; //Wird bitweise interpretiert: Jedes Bit eine LED, Abfolge s.o. char taster; //Hilfsvariable zum Erfassen des Tasterzustandes unsigned char DURCHLAUF = 0; void verarbeiteC() { //Bit0 - grün digitalWrite(19,c%2); c=(c>>1); //Bit1 - gelb digitalWrite(21,c%2); c=(c>>1); //Bit2 - rot digitalWrite(23,c%2); c=(c>>1); //Bit3 - 4 digitalWrite(11,c%2); c=(c>>1); //Bit4 - 3 digitalWrite(9,c%2); c=(c>>1); //Bit5 - 2 digitalWrite(7,c%2); c=(c>>1); //Bit6 - 1 digitalWrite(5,c%2); c=(c>>1); //Bit7 - TON digitalWrite(3,c%2); } void allesAn() { digitalWrite(3,1); digitalWrite(4,0); digitalWrite(5,1); digitalWrite(6,0); digitalWrite(7,1); digitalWrite(8,0); digitalWrite(9,1); digitalWrite(10,0); digitalWrite(11,1); digitalWrite(12,0); digitalWrite(18,0); digitalWrite(19,1); digitalWrite(20,0); digitalWrite(21,1); digitalWrite(22,0); digitalWrite(23,1); } void allesAus() { digitalWrite(3,0); digitalWrite(4,0); digitalWrite(5,0); digitalWrite(6,0); digitalWrite(7,0); digitalWrite(8,0); digitalWrite(9,0); digitalWrite(10,0); digitalWrite(11,0); digitalWrite(12,0); digitalWrite(18,0); digitalWrite(19,0); digitalWrite(20,0); digitalWrite(21,0); digitalWrite(22,0); digitalWrite(23,0); } void setup() { Serial.begin(9600); //Taster: pinMode(0,INPUT); digitalWrite(0,1); //Pullup-Widerstand pinMode(18,OUTPUT); pinMode(19,OUTPUT); pinMode(20,OUTPUT); pinMode(21,OUTPUT); pinMode(22,OUTPUT); pinMode(23,OUTPUT); pinMode(3,OUTPUT); pinMode(4,OUTPUT); pinMode(5,OUTPUT); pinMode(6,OUTPUT); pinMode(7,OUTPUT); pinMode(8,OUTPUT); pinMode(9,OUTPUT); pinMode(10,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); } void loop() { if(DURCHLAUF<3) { allesAn(); delay(500); allesAus(); delay(500); DURCHLAUF++; } else if(Serial.available()) { c=Serial.read(); taster = digitalRead(0); //Tasterzustand einlesen if(taster>0) Serial.write('0'); else Serial.write('1'); verarbeiteC(); } }
Code 0-1: Das Arduino Programm "rcc009.pde"
PHP-Serverprogramm
Voraussetzung: Die Webdateien liegen im Ordner .../htdocs/rcc eines laufenden lokalen XAMPP-Servers.
rcc.zip
Sind einmal drei Arduino-Boards angeschlossen, so haben sie i.d.R. die seriellen Portbezeichnungen: /dev/ttyACM0, /dev/ttyACM1, /dev/ttyACM2.
Um unter diesen auswählen zu können, wird der Portname ebenfalls über POST gesendet. So kann post_lesen.php für alle drei Boards von der Anwendung her aufgerufen werden und muß nicht mehr angepaßt werden:
Bild 0-2: post_lesen.php - Verbindung zwischen Mikrocontroller und HTML5/Javascript-Anwendung
Testanwendung
Vor der eigentlichen Anwendung wird ein Testprogramm erstellt. Dieses ermöglicht schon das Ansteuern aller LEDs einzeln und das Empfangen des Tasterzustandes.
Bild 0-3: Formularoberfläche von request.html
<!DOCTYPE html> <html> <head lang="de"> <meta charset="iso-8859-1"> <script language:javascript> var http; function beiAntwort() { if(http.readyState == 4 && http.status == 200) { document.getElementById("tasterzustand").value = http.responseText; } } function abschicken(wohin,muster) { http = new XMLHttpRequest(); var url = "http://localhost/rcc/post_lesen.php"; var params = "wohin="+wohin+"&"+"muster="+muster; http.open("POST", url, true); //Send the proper header information along with the request http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //Testweise Antwort anzeigen: http.onreadystatechange = beiAntwort; http.send(params); } function testen() { var wohin = document.getElementById("wohin").value; var muster = document.getElementById("muster").value; abschicken(wohin,muster); } </script> </head> <input type="button" value="abschicken" onclick="javascript:testen()"/> <input id="wohin" style="width:200px;" type="text" value="/dev/ttyACM0"/> <input id="muster" style="width:200px;" type="text" value="11110000"/> <input id="tasterzustand" style="width:200px;" type="text" value="x"/> </body> </html>
Code 0-2: request.html
Saalübung
Oben stehendes Programm wird erläutert und als Grundlage für eine kleine im Unterricht erstellte Anwendung genommen.
Teillösung
Das folgende Programm schickt nach dem Start zyklisch vier Leuchtmuster an den Arduino, die die Taktzählzeit anzeigen.
Über die Buttons "starten", "stoppen" kann der Prozeß wiederholt begonnen und beendet werden.
<!DOCTYPE html> <html> <head lang="de"> <meta charset="iso-8859-1"> <script language:javascript> var ADRESSE = "/dev/ttyACM0"; var ZAEHLZEIT = 0; var threadhandler; function tick() { if(ZAEHLZEIT==0) { abschicken(ADRESSE,"01000000"); } else if(ZAEHLZEIT==1) { abschicken(ADRESSE,"00100000"); } else if(ZAEHLZEIT==2) { abschicken(ADRESSE,"00010000"); } if(ZAEHLZEIT==3) { abschicken(ADRESSE,"00001000"); } ZAEHLZEIT++; ZAEHLZEIT%=4; } var http; function beiAntwort() { if(http.readyState == 4 && http.status == 200) { document.getElementById("tasterzustand").value = http.responseText; } } function abschicken(wohin,muster) { http = new XMLHttpRequest(); var url = "http://localhost/rcc/post_lesen.php"; var params = "wohin="+wohin+"&"+"muster="+muster; http.open("POST", url, true); //Send the proper header information along with the request http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //Testweise Antwort anzeigen: http.onreadystatechange = beiAntwort; http.send(params); } function testen() { var wohin = document.getElementById("wohin").value; var muster = document.getElementById("muster").value; abschicken(wohin,muster); } function starten() { threadhandler = setInterval(tick,500); } function stoppen() { threadhandler = window.clearInterval(threadhandler); } </script> </head> <input type="button" value="starten" onclick="javascript:starten()"/> <input type="button" value="stoppen" onclick="javascript:stoppen()"/> <input type="button" value="abschicken" onclick="javascript:testen()"/> <input id="wohin" style="width:200px;" type="text" value="/dev/ttyACM0"/> <input id="muster" style="width:200px;" type="text" value="11110000"/> <input id="tasterzustand" style="width:200px;" type="text" value="x"/> </body> </html>
Code 0-3: Teillösung anwendung.html - muß auch in htdocs/rcc liegen.