Momentary Switches + Expressionpedal

Hey,

ich bastel gerade ein midi Footswitch mit der Hiduino Firmware. Ich habe dort 6 Momentary Footswitches angeschlossen und möchte zudem über den analogen Eingang ein Expressionpedal mit einem standard Potentiometer anschließen.
Allerdings feuert der Arduino in Dauerschleife midi Befehle an meinen PC. Ich habe schon versucht, den Rest des Codes in eine Whileschleife zu schreiben und diese so lange ausführen zu lassen, bis sich der Wert des Potentiometers ändert.
Das funktioniert allerdings nicht ganz so zuverlässig, da das Poti sehr empfindlich ist und seine Werte auch ändert, wenn ich es gar nicht bediene und somit die Schalter in der Whileschleife nicht mehr ansprechbar sind.

Gibt es auch eine andere Lösung dafür? Im Anhang einmal der Code

#include <MIDI.h>

int t1=2;
int t2=3;
int t3=4;
int t4=5;
int t5=6;
int t6=7;
int ex=0;

void setup() {
  pinMode(t1,INPUT);
  pinMode(t2,INPUT);
  pinMode(t3,INPUT);
  pinMode(t4,INPUT);
  pinMode(t5,INPUT);
  pinMode(t6,INPUT);
  MIDI.begin(1);
}

void loop() {
  //expression pedal
    int valunmapped=analogRead(ex);
    int val=map(valunmapped,0,1023,0,127);
    int previousval=val;
    MIDI.sendNoteOn(39,val,1);
  
  while (val==previousval){
  //loop switches
    if (digitalRead(t1)==LOW){
      MIDI.sendNoteOn(40,127,1);
        while (digitalRead(t1)==LOW){
        delay(170);        
        }

      MIDI.sendNoteOn(40,127,1); //aftertouch
    }
    
    if (digitalRead(t2)==LOW){
      MIDI.sendNoteOn(41,127,1);
        while (digitalRead(t2)==LOW){
        delay(170);        
        }

      MIDI.sendNoteOn(41,127,1); //aftertouch
    }
    
    //standard switches
    if (digitalRead(t3)==LOW){
      MIDI.sendNoteOn(42,127,1);
        while (digitalRead(t3)==LOW){
        delay(170);        
        }

    }
    
    if (digitalRead(t4)==LOW){
      MIDI.sendNoteOn(43,127,1);
        while (digitalRead(t4)==LOW){
        delay(170);        
        }

    }
    
    if (digitalRead(t5)==LOW){
      MIDI.sendNoteOn(44,127,1);
        while (digitalRead(t5)==LOW){
        delay(170);        
        }

    }
    
    if (digitalRead(t6)==LOW){
      MIDI.sendNoteOn(45,127,1);
        while (digitalRead(t6)==LOW){
        delay(170);        
        }

    }
  
}

Potis sind vermutlich nicht zu empfindlich, es sei denn es sind die eher preiswerteren oder abgenudelten. Beides sollte man vermeiden ;) Ich schätze, es wird eher an Brumm und Schmutz auf den Analogleitungen liegen. Mach mal nen kleinen Tiefpass rein, testweise irgendwie was mit 100nF und 1 - 10 k. Saubere Betriebsspannung ist natürlich auch ein Muss.

Alternativ kannst Du natürlich auch per SW tiefpassfiltern oder einfacher vor der Ausgabe erst Mittelwerte bilden und die auf Abweichungen prüfen. So, das war die Ausführung für's Expression-Pedal.

Für die Switches hast Du hoffentlich Pullups verwendet?

doederino:
Allerdings feuert der Arduino in Dauerschleife midi Befehle an meinen PC.

Bist Du sicher, dass Du die Buttons korrekt mit den notwendigen PullUp- oder PullDown-Widerständen angeschlossen hast?

Weil Dein Programm nicht die internen PullUps aktiviert, können die Buttons nur mit Pull-Widerständen korrekt ausgewertet werden.

Außerdem ist die Programmlogik natürlich sehr verquer.

Das Poti kannst Du bei schwankenden Werten nicht auf Gleichheit testen, sondern Du müßtest testen, ob die Werte innerhalb eines Bereichs um den ursprünglichen Wert liegen. Mathematisch bedeutet das, Du bildest die Differenz vom aktuellen und einem vorherigen Messwert und betrachtest den absoluten Betrag (Vorzeichen entfernt) der Differenz, ob dieser kleiner oder größer als ein bestimmter Grenzwert ist.

Bei den Buttons wären nicht nur die ggf. notwendigen Pull-Widerständen in der Schaltung zu beachten, sondern auch das mechanische Prellen der Kontakte. Mein Vorschlag für die softwaretechnische Entprellung: Die Buttons nur alle x Millisekunden auswerten und dabei auch nur auf den Übergang von “nicht gedrückt” zu “gedrückt” achten.

Außerdem sind natürlich Aufrufe von “delay” in einem interaktiven Programm, das schnell auf irgendwas reagieren soll, völlig unangebracht und müssen vermieden werden.

Mal ein ungetesteter Codevorschlag von mir (vielleicht läuft’s mit kleinen Änderungen):

#include <MIDI.h>
#define PRELLZEIT 5 // in Millisekunden
#define PEDALPIN A0
#define NUMBUTTONS 6

struct button_t {int pin; boolean pressed; int note; int velocity; int channel;};
button_t buttons[]={
  {2, false, 39, 127, 1},
  {3, false, 40, 127, 1},
  {4, false, 41, 127, 1},
  {5, false, 42, 127, 1},
  {6, false, 43, 127, 1},
  {7, false, 44, 127, 1},
};

void setup() {
  Serial.begin(9600); // Für Serial-Debug Meldungen, falls benötigt
  for (int i=0;i<NUMBUTTONS;i++)
    pinMode(buttons[i].pin, INPUT);
  MIDI.begin(1);    
}

void loop() {
  //expression pedal
  static int lastPedalValue;
  int newPedalValue;
  newPedalValue=analogRead(PEDALPIN);
  if (abs(lastPedalValue-newPedalValue)>10)
  {
    lastPedalValue=newPedalValue;
    MIDI.sendNoteOn(39,map(newPedalValue,0,1023,0,127),1);    
  }
  //loop switches
  static unsigned long lastTime;
  if (millis()-lastTime>PRELLZEIT) // Buttons nur in Zeitabständen auswerten
  {
    lastTime=millis();
    for (int i=0;i<NUMBUTTONS;i++)
    {
      boolean nowPressed=(digitalRead(buttons[i].pin)==LOW);
      if (nowPressed==true && buttons[i].pressed==false)
      {
        buttons[i].pressed==true;
        MIDI.sendNoteOn(buttons[i].note,buttons[i].velocity,buttons[i].channel);
      }
      else if (nowPressed==false) buttons[i].pressed==false;
    }
  }
}

Die Daten der Buttons habe ich mal in eine saubere Datenstruktur gebracht, damit die Buttons alle in einer einzigen Schleife und mit derselben Logik abgearbeitet werden können, das ist wartungsfreundlicher bei Änderungen.

Mit der Potentiometerauswertung wirst Du vermutlich trotzdem nicht zufrieden sein: Die spielt so die Note bei jeder festgestellten Änderung. Drehst Du das Poti langsam, werden viele Noten gespielt, weil viele Änderungen erkannt werden. Drehst Du das Poti schnell von einer in die andere Position, werden wenige oder sogar nur eine Note gespielt.

Die Poti-Logik wirst Du vermutlich anders haben wollen. Z.B. dass während des Drehens überhaupt keine Noten gespielt werden, und erst wenn der Poti-Wert sich für 0,01 oder 0,1 Sekunden nicht mehr ändert und stabil ist, soll eine Note gespielt werden. Aber das müßtest Du wissen und dann genau festlegen, wie es laufen soll.

Das Poti liefert keine Noten, “Expression” ist ja ein Controlerwert. Spielt aber keine Rolle was die Ausgabe angeht. Meine Erfahrung mit dem Midi-Shield ist jedenfalls - besonders im Bereich der CCs: das klappt prima mit dem Vergleich alter Wert <> neuer Wert.
Evtl. noch ne Hysterese rein von 1 bis 2 und fein. Je nach Anwendung stört das überhaupt nicht.

Klaus_ww:
Das Poti liefert keine Noten, “Expression” ist ja ein Controlerwert.

Ahh, danke für die Klarstellung!

Da kann man mal sehen, dass ich von MIDI-Effektgeräten so viel Ahnung habe wie der Thread-Starter vom programmieren, denn ich war jetzt glatt davon ausgegangen, dass mit dem Poti tatsächlich Noten gespielt werden sollen, weil der vom Thread-Starter gepostete Code versuchte, Noten über das Poti abzuspielen.

Wenn das Poti tatsächlich nur einen bestimmten Parameter der gespielten Note verändert (Lautstärke? Anschlaggeschwindigkeit?), dann ist es ja noch viel einfacher: Dann wird zu Beginn der loop die Stärke des eingestellten Effekts gemessen und auf den gewünschten Zahlenbereich von 0 bis 127 gemappt. Und immer wenn eine Note gespielt werden soll, dann wird dieser Wert zum Abspielen der Note verwendet.

Mein oben geposteter Code vereinfacht sich damit auf (immer noch ungetestet):

#include <MIDI.h>
#define PRELLZEIT 5 // in Millisekunden
#define PEDALPIN A0
#define NUMBUTTONS 6

struct button_t {int pin; boolean pressed; int note; int velocity; int channel;};
button_t buttons[]={
  {2, false, 39, 127, 1},
  {3, false, 40, 127, 1},
  {4, false, 41, 127, 1},
  {5, false, 42, 127, 1},
  {6, false, 43, 127, 1},
  {7, false, 44, 127, 1},
};

void setup() {
  Serial.begin(9600); // Für Serial-Debug Meldungen, falls benötigt
  for (int i=0;i<NUMBUTTONS;i++)
    pinMode(buttons[i].pin, INPUT);
}

void loop() {
  //expression pedal
  int pedalValue=map(analogRead(PEDALPIN),0,1023,0,127);
  //loop switches
  static unsigned long lastTime;
  if (millis()-lastTime>PRELLZEIT) // Buttons nur in Zeitabständen auswerten
  {
    lastTime=millis();
    for (int i=0;i<NUMBUTTONS;i++)
    {
      boolean nowPressed=(digitalRead(buttons[i].pin)==LOW);
      if (nowPressed==true && buttons[i].pressed==false)
      {
        buttons[i].pressed==true;
        MIDI.sendNoteOn(buttons[i].note, pedalValue, buttons[i].channel);
      }
      else if (nowPressed==false) buttons[i].pressed==false;
    }
  }
}

So ungefähr, wenn der pedalValue tatsächlich nur einen Parameter der gespielten Note beeinflussen soll?