kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




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:

  • TON - Gelbe LED - Bit7 - leuchtet, wenn gerade Ton zu spielen ist.
  • ZÄHLZEIT - grün rot rot rot - Bit6..3 - zeigen Zählzeit an.
  • AMPEL - rot gelb grün - Bit2..0 - Countdown vor dem Losspielen

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.

Aufbau der drei Steckplatinen.

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"

rcc009.zip

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:

post_lesen.php - Verbindung zwischen Mikrocontroller und HTML5/Javascript-Anwendung

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.

Formularoberfläche von request.html

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.