millis()

Hallo,
ich habe eine Frage zu der millis() - Funktion. Damit erzeuge ich ein Metronom (musikalischer Taktzähler), der per Buzzer und Display ausgegeben wird. Mit Touch-Schaltern kann ich dann das Tempo, die Taktlänge (3/4 oder 4/4 usw.) und anderes ändern.

Soweit funktioniert alles aber, nun zur Frage:

Kann es sein, dass millis() in der Genauigkeit schwankt?

Das ist mir schwer vorstellbar. Ich rede vonSchwankungen von 5 - 20 Millisekunden (nicht Microsekunden).
Aber ich habe folgendes Problem: Das Tempo, was ich mit dem Nano erzeuge, ist im Vergleich mit einem Metronom auf dem Handy oder im PC immer etwas zu langsam. Der Nano läuft bei Tempo 60 BPM (beats per minute) ca. 91 ms hinterher, bei 120 BPM ca. 37 ms, bei 180 BPM ca. 24 ms, bei 240 BPM ca. 18 ms.

Die Tempi laufen dabei aber für menschliche Ohren absolut gleichmäßig nur eben etwas langsamer.

Der Code beinhaltet jede Menge If -Abfragen und 4 Touchtaster (digitalRead) werden in der Loop abgefragt. Bremst das den Timer aus?

Wenn der Fehler im Code vermutet wird, reiche ich den gern noch nach. Es sind aber keine delay(xx) _ Befehle drin.

Vielen Dank schon mal für eure Expertise und Anregungen,

Hallo,

wie machst Du das ? Erzeugst Du mit tone einen Ton und die pausen machst Du mit milliis(). ?

Heinz

Kann es sein, dass millis() in der Genauigkeit schwankt?
Ich rede von Schwankungen von 5 - 20 Millisekunden

Da ist was faul inn deinem Sketch.
Vereinfache ihn evtl. zum Test. Im einfachsten Test-Fall solltest du sehen, dass es nicht an millis() selbst liegt. Je einfacher das Beispiel ist, das die Schwankungen zeigt, umso leichter lässt sich dein Problem analysieren.

60 BPM ist ein Zyklus von 1000 ms. Da sollten selbst bei nur Resonator-genauen Arduinos max 1 ms Abweichung sein. Wie erkennst du die Schwankungen?

art_U_dino:
Kann es sein, dass millis() in der Genauigkeit schwankt?

Ja, denn ein Arduino ist kein Präzisionszeitmeßinstrument, aber nicht in den von Dir genannten Größenordnungen.

art_U_dino:
Wenn der Fehler im Code vermutet wird, reiche ich den gern noch nach.

Ja, bitte!

Neben delay() gibt es noch mehr Möglichkeiten der blockierenden Programmierung. Das wäre so meine Vermutung.

Hi

Ein Arduino ist KEINE Uhr - der Arduino hat keinerlei Anspruch, in irgend einer Art genau zu sein.
Die Geschwindigkeit des Arduino ist recht konstant (trotzdem zu ‘wackelig’ für eine vernünftige Uhr).

Wenn Dein Arduino, statt mit 16MHz nur mit 15MHz taktet, sind auch die millis() eben keine Millisekunden, sondern 15/16tel davon.
Ganz so krass weicht Der nicht ab - nur zum ‘Sehen’.

Wenn die Abweichung konstant ist (wovon ich ausgehe), kannst Du Deine Zeiten mit einem Faktor ‘gerade rücken’.

MfG

Ein Original arduino hat einen Resonator mit einer "Genauigkeit" von 1000 ppm. ( 0,1 % ) oder 1 / 1000.

Das reicht nicht für eine echte Uhr, denn da würde man am Tag über eine Minute Abweichung haben.
Für ein Metronom sollte es aber reichen. Ein 60 BPM Takt kann durchaus um ca 1 ms "falsch" gehen ohne dass das weh tut. Erst bei 16 ms Abweichung wären die 60 BPM in Wirklichkeit 59 BPM (oder umgekehrt)

Der Nano läuft bei Tempo 60 BPM (beats per minute) ca. 91 ms hinterher

Die erwähnten 91 ms wären ein auf jeden Fall ein Reklamationsgrund für den Arduino.
Oder ein Fall für eine genauere Messung.

Oder ein Fehler im Referenz-Metronom ? :slight_smile:

Hallo,

wenn ich die Frequenz anzweifeln würde , dann könnte man schnell mal eine Zeitfunktion bauen mit millis() was machen und das mit einer Stopuhr (Handy) vergleichen. Wenn das z.B 100s läuft 1/10s lässt sich mit der Hand stoppen.

z.B Blinkwithoutdelay mit 100s

Heinz

Hallo an alle,
erst einmal vielen Dank für die schnellen Antorten, die sher gute Anregungen enthalten. Im folgenden ein Stück des Codes, es ist erst mal nur ein Teil, weil der ganze Code recht lang und mir unübersichtlich scheint, mit einer menge Funktionen, die ja funktionieren, also nur vom Problem ablenken (vielleicht auch nicht).

unsigned long Zeit;   // f. NormalZeit
unsigned long altZeit = 0;     // f. NormalZeit

int BarLenght = 4;  // Taktlänge initialisiert
int LaengeBeat = 0;
//int TaktCountV = 0;
int TaktCountN = 0;
int BPM = 240;   // Tempo initialisiert

const int Buzz = 9;

void setup() {
  Serial.begin(9600);
}

void loop() {
Zeit = millis();
   
  LaengeBeat = 60000 /BPM /2;   //   /2 bei Microtiming 8tel (wenn Microtiming 16tel, dann /4 )

 if (Zeit - altZeit >= LaengeBeat) {  //  normal Time nur für VibMotor
    altZeit = Zeit;
    TaktCountN = TaktCountN + 1;
    if (TaktCountN > BarLenght * 2) {     // N = normalZeit
        TaktCountN = 1;
    }
    Serial.print("TaktCountN: ");  Serial.println(TaktCountN); 
 }
if (TaktCountN == 1) {
            tone(Buzz, 880);
}
    else 
        if (TaktCountN == (3)|| TaktCountN == (5)|| TaktCountN == (7) || 
            TaktCountN == (9)|| TaktCountN == (11)|| TaktCountN == (13)){
            tone(Buzz, 440);
    }
    if (TaktCountN == (2)|| TaktCountN == (4)||TaktCountN == (6)|| TaktCountN == (8) 
        || TaktCountN == (10)|| TaktCountN == (12)|| TaktCountN == (14)) {
            noTone(Buzz);    
    } 
}

Aufgrund des Hinweises von michael_x habe ich den simplen Teil, also die Erzeugung von Beats getestet. Und es zeigt vsich, dass es hier diese Verzögerungen nicht gibt. Nicht wahrnehmbare Schwankungen sind hier nicht relevant. Ich will keine Atomuhr bauen. :wink:
Der Codeschnipsel steht hier nur, weil danach gefragt wurde und um die grundsätzliche Erzeugung von BPM zu zeigen. Sobald ich den störenden Codeteil entdecke, poste ich diesen.

PS: Ja - und "gemessen" habe ich mit dem Gehör. Der Buzzer am Arduino piept mit der MetronomApp um die Wette (Tempo mit Tab-Funktion eingegen, dort kommt schon wesas ganz anderes raus) aber dann lüauf der Arduino eben imme rmehr hinterher bzw. die App holt den Arduno ein. Ich ändere das Tempo in der App, wenn das Tempo in etwa gleich ist ermittle ich per Rechner die zeitliche Differenz, der unterschiedlichen BPM's.

art_U_dino:
Kann es sein, dass millis() in der Genauigkeit schwankt?

Das Tempo, was ich mit dem Nano erzeuge, ist im Vergleich mit einem Metronom auf dem Handy oder im PC immer etwas zu langsam. Der Nano läuft bei Tempo 60 BPM (beats per minute) ca. 91 ms hinterher, bei 120 BPM ca. 37 ms, bei 180 BPM ca. 24 ms, bei 240 BPM ca. 18 ms.

Vielen Dank schon mal für eure Expertise und Anregungen,

Zur Genauigkeit wurde schon besprochen. Ja.

Wenn man sich das genauer ansieht, nimmt die Ungenauigkeit bei steigender Frequenz ab.

Keine Expertise, da dafür keine Grundlage;) ABER Wenn Du Deinen Sketch einstellst, wird sich der Fehler in der "PauseTime" finden lassen.
Du löst IMHO den Ton nicht mit den vergangenen millis() aus.

 if (Zeit - altZeit >= LaengeBeat) {  //  normal Time nur für VibMotor

altZeit = Zeit;

 if (Zeit - altZeit >= LaengeBeat) {  //  normal Time nur für VibMotor
    altZeit += LaengeBeat;

Dann holte es wieder auf, wenn es den exakten Punkt verpasst hat.
So summiert sich der Fehler nicht.

OK, nun muss ich leider doch mein Machwerk vorstellen, ich hoffe, es findet sich jemand darin zurecht. Es würde jetzt recht lang, wenn ich alles erklären würde. Das wichtigste vielleicht: ich habe einen Vibrationsmotor für das Handgelenk angesteuert. Weil dieser Motor aber eine Trägheit im Starten hat, habe ich ein "timeOffset" eingefügt, der Buzzer und das 4Digit SevSeg-Display laufen also die entsprechend initialisierten ms hinterher, um mit dem Motor synchron zu sein.
Diese 2 Zeitschienen sind aber offenbar nicht das Problem, wie ich gerade separat getestet habe. das wäre jetzt meine Vermutung gewesen
Was ist es also dann? Die Touch-Taster funktionieren eigentlich, sie stellen Taklänge, Tempo (incl. schnellIncrease/ schnellDecrease) usw. ein. ABLETON-Modus bedeutet, dass ein Metronomsignal vom PC mit AbletonLive kommt und den Vibmotor steuert, die Trägheit gleiche ich dort im Programm aus, indem die Metronomspur vorverlagert wird.

Code kommt im nächsten Teil (überschreitet offenbar 9000 Zeichen).

sorry, der Code hat über 9000 Zeichen, wie soll ich den hier einstellen. Ich hab jetzt meine 5 Minuten gewartet ... aber es geht nicht, weil zu lang, soll ich nur die Loop posten ?

void loop() {

 Zeit = millis();
  
 LaengeBeat = 60000 /BPM /2;   //   /2 bei Microtiming 8tel (wenn Microtiming 16tel, dann /4 )
 
 display.setBrightness(0x0f);

 touchTmpDecrStat = digitalRead(touchTempDecr);
 touchBarLenStat = digitalRead(touchBarLen);      // Taktlänge-Touchbutton
 touchTabModStat = digitalRead(touchTabMod);
 touchTmpIncrStat = digitalRead(touchTempIncr);

if (ModusABLETON == 0) {  //  METROnormalModus:

// Tab-Modus (shortPress)
 if (touchTabModStat == HIGH)  {    // Programmierung auf Loslassen
   TabModStat = 1;
 }
 if ((touchTabModStat == LOW) && (TabModStat == 1)) {
   TabTShift();
   TabModStat = 0;
 }

 // Doppelklick Toggle Buzzer On/Off
 if ((TabTDiff[0] < 200) && (TabTDiff[0] > 10) && (prevBuzzMode == 0)) {   // evntl kleinerer Wert für Doppelklick
   BuzzMode = 1;
   prevBuzzMode = 1;
   NullTabDiffs();
   //Serial.println("Doppelklick --> BuzzMode ON!");
 }
 if ((TabTDiff[0] < 200) && (TabTDiff[0] > 10) && (prevBuzzMode == 1)) {   // evntl kleinerer Wert für Doppelklick
   BuzzMode = 0;
   prevBuzzMode = 0;
   NullTabDiffs();
   //Serial.println("Doppelklick --> BuzzMode off!");
 }
 //Serial.print("BuzzMode: "); Serial.println(BuzzMode);
 
 if (TabTDiff[0] > 2500) {     //evntl kleinerer Wert? 
    NullTabDiffs();   
 }
 if (TabTDiff[2] > 200) {
     TDiffAverage = (TabTDiff[0] + TabTDiff[1] + TabTDiff[2]) / 3;
     if ( TDiffAverage > 0 ) {
         BPM = 60000 / TDiffAverage;
         NullTabDiffs();   // um Plus/Minus Tempo wieder zu ermöglichen
         //Serial.print("BPM: "); Serial.println(BPM);
     }
 }
       
      
//  to ABLETON-Modus (longPress)
 if (touchTabModStat == HIGH) {
   if (Zeit - longAbleMillis > 1000) {
     //Serial.println("Tab/Mod lang gedrückt");
       longAbleMillis = Zeit; ModusABLETON = 1;   //  löst im nächsten Loop-Durchgang ABLETON-Modus aus
      // Serial.println("ModusABLETON???");
   }
 }
 if (touchTabModStat == LOW) {
   longAbleMillis = Zeit; 
 }

// shortPress Behavoir PLUS
 if ((touchTmpIncrStat == HIGH) )  { // Programmierung auf Loslassen
     TmpIncrStat = 1;
   } 
  if ((touchTmpIncrStat == LOW) && (TmpIncrStat == 1)) {
    BPM = BPM + 1; TmpIncrStat = 0;
   }
// longPress-Behavoir PLUS
 if (touchTmpIncrStat == HIGH) {
   if (Zeit - longPlusMillis > 500) {
       longPlusMillis = Zeit; BPM = BPM + 10;
   }
 }
 if (touchTmpIncrStat == LOW) {
   longPlusMillis = Zeit; 

 }
// shortPress Behavoir MINUS    
 if ((touchTmpDecrStat == HIGH) )  {    // Programmierung auf Loslassen
    TmpDecrStat = 1;
   } 
  if ((touchTmpDecrStat == LOW) && (TmpDecrStat == 1)) {
   BPM = BPM - 1; TmpDecrStat = 0;
   }
// longPress-Behavoir MINUS
 if (touchTmpDecrStat == HIGH) {
   if (Zeit - longMinusMillis > 500) {
       longMinusMillis = Zeit; BPM = BPM - 10;
   }
 }
 if (touchTmpDecrStat == LOW) {
   longMinusMillis = Zeit;

 }
  // Serial.print("TmpIncrStat: "); Serial.println(TmpIncrStat);

 if (touchBarLenStat == HIGH){ 
   if (BLStatus == 0) { 
     BarLenght = BarLenght +1; 
     BLStatus = 1; 
     }
     if (BarLenght > 7) { BarLenght = 1; }
   }
 if (touchBarLenStat == LOW) {
     BLStatus = 0;
   } 
 
 // Vorausschau welcher BarLength eingestellt wurde (damit man nicht warten muss, bis "durchgezählt" ist)
 if ((BarLenght == 1) && (touchBarLenStat == HIGH))  {
   data[3] = ONE; display.setSegments(data);
 }
 if ((BarLenght == 2) && (touchBarLenStat == HIGH)) {
   data[3] = TWO; display.setSegments(data);
 }
 if ((BarLenght == 3) && (touchBarLenStat == HIGH))  {
   data[3] = THREE; display.setSegments(data);
 }
 if ((BarLenght == 4) && (touchBarLenStat == HIGH))  {
   data[3] = FOUR; display.setSegments(data);
 }
 if ((BarLenght == 5) && (touchBarLenStat == HIGH))  {
   data[3] = FIVE; display.setSegments(data);
 }
 if ((BarLenght == 6) && (touchBarLenStat == HIGH)) {
   data[3] = SIX; display.setSegments(data);
 }
 if ((BarLenght == 7) && (touchBarLenStat == HIGH))  {
   data[3] = SEV; display.setSegments(data);
 }

//Modulo für BPM-Anzeige 4x 7Seg => Tempodarstellung in BPM
 Hunderter = BPM / 100;    // = Digit 1
   if (Hunderter == 0) { data[0] = 0b00000000; }
   else data[0] = display.encodeDigit(Hunderter); 
 Zehner = BPM % 100 / 10;   // = Digit 2
   data[1] = display.encodeDigit(Zehner); 
 Einer = BPM % 10;     // = Digit 3
   data[2] = display.encodeDigit(Einer); 
 
 display.setBrightness(0x0f);
 display.setSegments(data);

// die "DOPPEL-UHR" (2 verschiedene Zeitpunkte)
// Erzeugung Zeitpunkt1 (NormalZeit)
if (Zeit - altZeit >= LaengeBeat) {  //  normal Time nur für VibMotor
   altZeit = Zeit;
   TaktCountN = TaktCountN + 1;
   if (TaktCountN > BarLenght * 2) {     // N = normalZeit
       TaktCountN = 1;
   }
   Serial.print("ZeitN: ");  Serial.print(Zeit);
   Serial.print(" :: TaktCountN: ");  Serial.println(TaktCountN); 
     
// MetronomVibration (NormalZeit, unversetzt)
  if (TaktCountN == 1) {
           analogWrite(Vib, VibStaerke + 255);
  }
  else 
       if (TaktCountN == (3)|| TaktCountN == (5)|| TaktCountN == (7) || 
           TaktCountN == (9)|| TaktCountN == (11)|| TaktCountN == (13)){
           analogWrite(Vib, VibStaerke + 190);
       } 
  if (TaktCountN == (2)|| TaktCountN == (4)||TaktCountN == (6)|| TaktCountN == (8) 
     || TaktCountN == (10)|| TaktCountN == (12)|| TaktCountN == (14)) {
         analogWrite(Vib, VibStaerke = 0);    
     }
}
   
// Erzeugung Zeitpunkt2 (OffsetTime)  
if (Zeit >= altZeit + timeOffset) {  //  offsetTime nur für Display & Buzzer
     TaktCountV = TaktCountN;
     Serial.print("ZeitV: ");  Serial.print(Zeit);
     Serial.print(" :: TaktCountV: ");  Serial.println(TaktCountV); 
    }

 if (TaktCountV == 1) { 
   data[3] = ONE; display.setSegments(data); }
 if (TaktCountV == 3) {
   data[3] = TWO; display.setSegments(data); }
 if (TaktCountV == 5) { 
   data[3] = THREE; display.setSegments(data); }
 if (TaktCountV == 7) {
   data[3] = FOUR; display.setSegments(data); }
 if (TaktCountV == 9) { 
   data[3] = FIVE; display.setSegments(data); }
 if (TaktCountV == 11) {
   data[3] = SIX; display.setSegments(data); }
 if (TaktCountV == 13) { 
   data[3] = SEV; display.setSegments(data); }
 else if 
   (TaktCountV == (2)|| TaktCountV == (4)|| TaktCountV == (6)|| TaktCountV == (8) 
   || TaktCountV == (10) || TaktCountV == (12)|| TaktCountV == (14) ) {
       if (BPM <= 100) { data[3] = UND; display.setSegments(data); }
       if ((BPM > 100) && (BPM < 160)) { data[3] = NIX; display.setSegments(data); }
       if (BPM >= 160) { data[3] = data[3]; display.setSegments(data); }
   }
 
// Metronomclick (Buzzer, OffsetTime, versetzt))
 if (BuzzMode == 1) {
   if (TaktCountV == 1) {
           tone(Buzz, 880);
           }
   else 
       if (TaktCountV == (3)|| TaktCountV == (5)||TaktCountV == (7) || 
           TaktCountV == (9)|| TaktCountV == (11)||TaktCountV == (13)){
           tone(Buzz, 440);
       }
   if (TaktCountV == (2)|| TaktCountV == (4)||TaktCountV == (6)|| TaktCountV == (8) 
       || TaktCountV == (10)|| TaktCountV == (12)|| TaktCountV == (14)) {
           noTone(Buzz);    
       } 
   }
}

// abletonmidi: 
if (ModusABLETON == 1) {
 Serial.println("ModusABLETON");
 //noTone(Buzz);  // war für Ton aus MetroBuzzer --> geht spätestens aus bei noTone Befehl von MidiIN
 data[0] = grA; data[1] = klB; data[2] = grL; data[3] = grE;
 display.setSegments(data);

 empfangeMidi();
 // delay(10);    // ist nur für Kontroll-LED (intern Output13)
 // digitalWrite(13, LOW);

 if (midiStatus == 144) {   // 144 = 1001 0000 = 1001 (= Statusbyte & NoteON); 0000 (= Channel 1)
   
    if (midiData1 == 0) {
     analogWrite(Vib, VibStaerke + 255);
    }
    if (midiData1 == 1) {
     analogWrite(Vib, VibStaerke + 205);
     //Serial.print("midiData1 = "); Serial.println(midiData1);
    }
    if (midiData1 == 2) {
     analogWrite(Vib, VibStaerke = 0);
     //Serial.print("midiData1 = "); Serial.println(midiData1);
    }
 }

//  Back to Normal-Modus (longPress)
 if (touchTabModStat == HIGH) {
   if (Zeit - longAbleMillis > 1000) {
     longAbleMillis = Zeit; ModusABLETON = 0;
   }
 }
 if (touchTabModStat == LOW) {
   longAbleMillis = Zeit; 
 }
}
}

… und das, was oben drüber steht:

#include <Arduino.h>
#include <TM1637Display.h>
#include <inttypes.h>

#define CLK 2     // Display Pin
#define DIO 3     // Display Pin

const int Buzz = 9;
const int Vib = 10;

int touchTempIncr = 5;    // Tempo + (mit Longpress = Schnell-Increase)
int touchBarLen = 6;          // Taktlängentaster
int touchTabMod = 7;           // Tabtaster & bei Lonpress ABLETON/Metronom - Toggle
int touchTempDecr = 8;   // Tempo - (mit Longpress = Schnell-Decrease)

int touchTmpIncrStat = 0;  
int touchBarLenStat = 0; 
int touchTabModStat = 0;
int touchTmpDecrStat = 0;

int TmpIncrStat = 0;
int TmpDecrStat = 0;
int TabModStat = 0;
int BuzzMode = 0;
int prevBuzzMode = 0;

int VibStaerke = 0;       // 255 max; kann man initialisieren oder direkt im Befehl aufaddieren

int BLStatus = 0;   // TaktLängen (BarLength) StatusTouch
int prevBLStatus = 0;

int ModusABLETON = 0;

int TabState = 0;   // das Gleiche wie TabModState???
int prevTabState = 0;

int TabTDiff[3]; // TabTimeDifferenz 
int TDiffAverage = 0;

int DecrState = 0;
int longPressDecr = 0;

int IncrState = 0;
int longPressIncr = 0;


// Zahlen:
int ZERO = 0b00111111; int ONE = 0b00000110; int TWO = 0b01011011; int THREE = 0b01001111; 
int FOUR = 0b01100110; int FIVE = 0b01101101; int SIX = 0b01111101;  int SEV = 0b00000111;  
int EIGHT = 0b01111111; int NINE = 0b01100111;  // EIGHT / NINE brauhht Metronom vorraussichtl. nicht
// keine Anzeige:
int NIX = 0b00000000;
// und (offBeat)
int UND = 0b00011100;
// "AbLE" => f. ABLETON-Modus
int grA = 0b01110111; int klB = 0b01111100; int grL = 0b00111000; int grE = 0b01111001; 

int Hunderter = 0;
int Zehner = 0;
int Einer = 0;

int BarLenght = 4;  // Taktlänge initialisiert

TM1637Display display(CLK, DIO);

unsigned long Zeit;   // f. NormalZeit
unsigned long altZeit = 0;     // f. NormalZeit
unsigned long StoreTime = 0;     // Beginn Tabmessung (press Tabtaster)
unsigned long longPlusMillis;
unsigned long longMinusMillis;
unsigned long longAbleMillis;
//unsigned long offsetTime;     // evntl. auch als "int" möglich???

byte midiStatus;
byte midiData1;
byte midiData2;

int LaengeBeat = 0;
int TaktCountV = 0;
int TaktCountN = 0;
int BPM = 80;   //initialisiert Starttempo
int timeOffset = 80;    // initialisiert Zeitverschiebung f. Digitsdisplay und Buzzer (VibMotor hat normalZeit)

uint8_t data[4];

void TabTShift() {      // (TabTimeShift) = Zeitnahme und weiterschieben der Zeitdifferenzen zur Tempo(er)mittlung
  TabTDiff[2] = TabTDiff[1]; TabTDiff[1] = TabTDiff[0]; 
  TabTDiff[0] = Zeit - StoreTime;
  StoreTime = Zeit;
  Serial.print("TDiff0: "); Serial.print(TabTDiff[0]);
  Serial.print(" --- TDiff1: "); Serial.print(TabTDiff[1]);
  Serial.print(" --- TDiff2: "); Serial.println(TabTDiff[2]);
}

void NullTabDiffs() {     // = Reset
  TabTDiff[2] = 0;
  TabTDiff[1] = 0;
  TabTDiff[0] = 0; 
  Serial.print("TDiff0: "); Serial.print(TabTDiff[0]);
  Serial.print(" --- TDiff1: "); Serial.print(TabTDiff[1]);
  Serial.print(" --- TDiff2: "); Serial.println(TabTDiff[2]);
}

void empfangeMidi() {
  do {
    if (Serial.available()) {
      midiStatus = Serial.read();
      midiData1 = Serial.read();
      midiData2 = Serial.read(); 
    }
  }
  while (Serial.available() > 2);   // sobald 3 Bytes eingetroffen sind
}

//ACHTUNG!!! Serial Baudrate wieder auf midi-Speed setzen
void setup() {
  Serial.begin(31250);    // midi-speed = 31250
  display.clear();
  pinMode(Buzz, OUTPUT); pinMode(Vib, OUTPUT);
  pinMode(touchTempDecr, INPUT); pinMode(touchBarLen, INPUT); 
  pinMode(touchTabMod, INPUT); pinMode(touchTempIncr, INPUT);
}

Ein Blick in Dein Loop lässt mich zur Aussage hinreissen:
Du musst versuchen das, was da drin ist dringend in Funktionen auszulagern.
Nachtwächter ist das Stichwort.

Und nochwas:

   if (touchTabModStat == HIGH)
      {
      if (Zeit - longAbleMillis > 1000)
        {
        //Serial.println("Tab/Mod lang gedrückt");
        longAbleMillis = Zeit; ModusABLETON = 1;   //  löst im nächsten Loop-Durchgang ABLETON-Modus aus
        // Serial.println("ModusABLETON???");
        }
      }
    if (touchTabModStat == LOW)
      {
      longAbleMillis = Zeit;
      }

Warum machst Du da kein If / else?
Das spart Rechenzeit, denn wenn "== HIGH" erfüllt ist, kann "==LOW" nicht mehr erfüllt sein.

Schau mal, das Du den Code effektiver machst.

Wegen dem Umfang schaff ich da jetzt nichts mehr. Mal sehen, ob sich da sonst noch wer findet. Ich schau später drauf

Vielen Dank für den if/else Tipp. Spart das demnach die Rechenzeit, weil eine Kommandozeile gespart wird oder weil eine Vergleichsabfrage gespart wird?

Mit den Funktionen meinst du "void's" ? Das werde ich probieren. Mindestens übersichtlicher sollte es dann werden.

Mir ist vollkommen klar, dass Leute mit Ahnung vom Programmieren, die Hände über dem Kopf zusammenschlagen, wenn sie diesen Code sehen. Ich weiß die Mühe zu schätzen sich dennoch mal darüber zu beugen und bin für die Tipps sehr dankbar.

Gute Nacht einstweilen.

Mit den Funktionen meinst du "void's" ?

Leider gibt es in C/C++ keine "voids"!
void heißt "nicht vorhanden" oder "unbestimmt"

Und damit ist hier wohl der Rückgabe Datentype der Funktion gemeint.

Da die in Sketchen immer vorhandenen Funktionen 'setup' und 'loop' keine Werte zurückgeben, und deshalb als 'void' deklariert sind, wird dieses 'void' fatalerweise von vielen Einsteigern als Synonym zu Funktionen gesehen.

Da dann in vielen Anfängersketchen und Beispielen bei eigenen Funktionen lieber globale Variable anstelle von Funktionswerten und Parametern verwendet werden, verfestigt sich dieser Irrglaube leider immer mehr.

Hier ist offensichtlich Aufklärungsarbeit notwendig :wink:

Ich stimme dir zu!

Da dann in vielen Anfängersketchen und Beispielen bei eigenen Funktionen lieber globale Variable anstelle von Funktionswerten und Parametern verwendet werden, verfestigt sich dieser Irrglaube leider immer mehr.

Hier habe ich leichte Einwände!

Viele, viele, welche in der Arduino Welt eintreffen, haben keine EDV lastige Vorausbildung.
Ihnen fehlt das Wissen um die korrekten Begrifflichkeiten.
Darum denken sie sich welche aus. (voids, if-schleifen, blockadefrei :o )
Wobei man sich aber um genaue und eindeutige Begrifflichkeiten ernstlich bemühen muss, um überhaupt eine Sinn behaftete Unterhaltung führen zu können.
Ohne Bedeutung, keinen Sinn.

In Sachen Arduino, ist da das Datenblatt des betreffenden µC und ein schönes dickes, modernes, C++ Buch, ungemein hilfreich.

Hallo, danke für die Richtigstellung.

Leider gibt es in C/C++ keine "voids"!
void heißt "nicht vorhanden" oder "unbestimmt"

nun habe ich in meinem Code ja folgende "Void" (was auch immer) eingefügt und es funktioniert ja auch:

void empfangeMidi() {
  do {
    if (Serial.available()) {
      midiStatus = Serial.read();
      midiData1 = Serial.read();
      midiData2 = Serial.read();
    }
  }
  while (Serial.available() > 2);   // sobald 3 Bytes eingetroffen sind
}

Kannst du bitte kurz erläutern (oder Erläuterungslink schicken) wann es sinnvoll ist diese "Void's" zu erstellen und wann die "Funktionen()"?
In der Arduino-Referenz sieht man ja was Funktionen sind, mir ist nur nicht klar wie und warum ich sie selbst kreieren kann/sollte. Daher dachte ich, "void name()" wäre ein gutes Mittel, um Code zu verbessern... :confused: