Oha, wenn ich mich täusche, liegt da ja noch einiges im Argen ... 
Mal losgelöst von der Interrupt-Frage, hier das, was mir so aufgefallen ist:
#include <Wire.h>
#include <MCP4726.h>
MCP4726 dac;
// name pins
const byte ADMUX0 = A0;
const byte ADMUX1 = A1;
const byte ADMUX2 = A2;
/************************************************************
Die folgende Deklarationen werden während des Programmlaufs
nicht verändert. Sie könnten wie die Pins oben als
const byte bzw. constexpr byte festgelegt werden.
Die Pins SW, LED und MUXMain werden als OUTPUT genutzt,
jedoch im setup() nicht per pinMode() als OUTPUT
konfiguriert.
************************************************************/
int SW = 9; // Switch for VDD
int LED = 10; // LED
int MUXmain = 12; // Multiplexer on mainboard
int vdd_pin = A7;
/************************************************************
volatile erzwingt das regelmässige komplette Einlesen eines Wertes
aus der zugeordneten Adresse und ist z.B. sinnvoll für Portzugriffe,
deren Wert sich "von außen" ändern kann. Es verhindert aber nicht(!),
dass ein Interrupt dazwischenfunkt. Dafür braucht es das ATOMIC_BLOCK Macro
siehe z.B. hier https://www.mikrocontroller.net/topic/170451
************************************************************/
volatile int index; // variable for binary
float vref;
const byte NUM_CHANNELS = 8; //Number of Channels
/************************************************************
Zu volatile siehe oben
************************************************************/
volatile float voltages[NUM_CHANNELS]; //array for set voltages
byte calculateIndex(byte pin0, byte pin1, byte pin2) {
return (digitalRead(pin0) ? 1 : 0) * 1 + (digitalRead(pin1) ? 1 : 0) * 2 + (digitalRead(pin2) ? 1 : 0) * 4;
}
void printncompare() {
/************************************************************
Die channelNames[] werden weiter unten erneut verwendet. Wäre es
ggf. sinnvoll, dieses Array global zu definieren,
damit man z.B. Änderungen nur einer Stelle vornehmen muss?
************************************************************/
const char* channelNames[] = {"TC", "O2", "CO", "PRESS", "COLD", "TEMP_O2", "TEMP_CO", "TEMP_PRESS"};
Serial.println("Current set voltages of all channels:");
for (int i = 0; i < NUM_CHANNELS; i++) {
Serial.print(channelNames[i]);
Serial.print(": ");
Serial.print(voltages[i], 4);
Serial.println(" V");
}
Serial.println();
}
/************************************************************
current_channel oder current_chnnel
************************************************************/
int current_chnnel;
void chng_mux() {
index = calculateIndex(ADMUX0, ADMUX1, ADMUX2);
dac.setVoltage(voltages[index]);
/************************************************************
current_channel oder current_chnnel? So compiliert es nicht ...
************************************************************/
current_channel = index;
}
/************************************************************
volatile float voltages[NUM_CHANNELS] = {1270, 2274, 1225, 1225, 987.7, 1225, 1225, 1225};
a) Erzeugt ein temporäres Array, das nach dem Aufruf von set_val_zero() wieder
in Vergessenheit gerät
b) Die Werte scheinen direkte Analogwerte zu sein und keine Spannungen in Volt,
obwohl ein gleichnamiges Array an anderer Stelle offensichtlich für das Speichern
von z.B. 3.3 oder 5.0 dienen soll
c) Alles nicht so schlimm, da die Funktion eh nirgends aufgerufen wird.
Es lässt aber Zweifel aufkommen, was denn nun tatsächlich in einem
voltages[] verwendet werden soll.
************************************************************/
void set_val_zero() {
volatile float voltages[NUM_CHANNELS] = {1270, 2274, 1225, 1225, 987.7, 1225, 1225, 1225};
}
void prepareSim() {
Serial.println("Device connected");
digitalWrite(LED, HIGH);
digitalWrite(MUXmain, HIGH);
}
void setup() {
pinMode(ADMUX0, INPUT);
pinMode(ADMUX1, INPUT);
pinMode(ADMUX2, INPUT);
pinMode(vdd_pin, INPUT);
Serial.begin(9600);
attachInterrupt(ADMUX0, chng_mux, CHANGE);
attachInterrupt(ADMUX1, chng_mux, CHANGE);
attachInterrupt(ADMUX2, chng_mux, CHANGE);
dac.begin(MCP4726_DEFAULT_ADDR);
}
void loop() {
float vdd_value = analogRead(vdd_pin);
/************************************************************
vdd_value ist offensichtlich ein Wert zwischen 0 und 1023
wie auch die Ableitung von vref verdeutlicht.
************************************************************/
vref = vdd_value * (5.0 / 1024.0); //Caution: The value '5.0' must be adjusted if the operating voltage is not equal to 5.0 V
/************************************************************
Hier wird vdd_value nun jedoch gegen 3.0 verglichen?
Sollte das hier möglicherweise vref heißen???
************************************************************/
if (vdd_value > 3.0) {
prepareSim();
Serial.println("Which signal should be changed?");
while (Serial.available() == 0); // Überprüfung, ob Daten über die serielle Schnittstelle verfügbar sind
char input[20]; // Array zur Speicherung der Eingabe
Serial.readStringUntil('\n').toCharArray(input, sizeof(input)); // Lesen der seriellen Daten in den char-Array
while (Serial.available() > 0) Serial.read(); // das leert den Buffer
/************************************************************
Zu channelNames[] siehe oben
************************************************************/
const char* channelNames[] = {"TC", "O2", "CO", "PRESS", "COLD", "TEMP_O2", "TEMP_CO", "TEMP_PRESS"};
int channelIndex = -1;
for (int i = 0; i < sizeof(channelNames) / sizeof(channelNames[0]); i++) {
if (strcmp(input, channelNames[i]) == 0) {
channelIndex = i;
break;
}
}
if (channelIndex != -1) {
/************************************************************
Hier wäre noch eine Zeile wie
Serial.print(channelNames[channelIndex]);Serial.print("\t");
hilfreich, um zu sehen, welcher Kanal akzeptiert wurde
************************************************************/
Serial.println("Which voltage value should be set?"); // Prompt User for input
/*********************************************************
Das folgende Konstrukt geht jedenfalls in der Wokwi-Simulation
regelmäßig schief.
So funktioniert es dort
float voltage = 0;
while (voltage == 0){
voltage = Serial.parseFloat();
}
Allerdings sollte/muss man auf blockierende Funktionen
verzichten, da sich die Interuptroutine nicht dazu eignet,
serielle oder I2C-Schnittstellen zu verwenden, wie es
hier benötigt wird.
************************************************************/
while (Serial.available() == 0);
float voltage = Serial.parseFloat();
while (Serial.available() > 0) Serial.read(); // das leert den Buffer
if (voltage <= vref) {
voltages[channelIndex] = voltage;
} else {
Serial.println("Error. Voltage value exceeds Vref.");
}
} else {
Serial.println("Error. Unknown signal");
}
printncompare();
}
else {
digitalWrite(LED, LOW);
digitalWrite(SW, LOW);
Serial.println("Measuring device is not connected!");
/************************************************************
Hier wird vdd_value ausgegeben.
Sollte das hier möglicherweise auch vref heißen???
************************************************************/
Serial.println(vdd_value);
delay(1500);
}
}
Kann mich natürlich an der einen oder anderen Stelle täuschen, aber vielleicht hilft's ja weiter.
Da sehr viele blockierende Funktionen (delay(1500), while (Serial.available() == 0); usw.) im Einsatz sind, muss das ganze Konzept noch mal überdacht werden. Man kann seriellen Input auch nicht-blockierend programmieren. Das ist auf jeden Fall zu empfehlen!
Funktionen wie Serial.parseFloat(); sind dabei hinderlich. Besser in der loop alle Zeichen sammeln, bis ein Abschluss erkannt wird und dann den so erhaltenen String auswerten.
Da steckt jedenfalls noch Arbeit drin 