in der ISR delayMicroseconds() ersetzen

Hallo zusammen,
habe nun wieder ein Problem, ich habe mir eine Lötstationsregelung zusammengecoded. Soweit funktioniert der Spaß wie gewünscht, nur ist durch die Verwendung von der delayMicroseconds() Funktion in der ISR Schleife (in nem Interrupt ausgelöst durch den Nulldurchgang einer 50Hz Spannung) der Controller praktisch im niedrigen Regelbereich nur am "pausieren" und das gefällt mir nicht, da dadurch auch die LCD anzeige freezed. (Das LCD läuft über die millis()-Funktion ala BlinkWithoutDelay).

    delayMicroseconds(triacONdelay);
    digitalWrite(Zuendung, HIGH);     //Phase anschneiden; 
    delayMicroseconds(25); 
    digitalWrite(Zuendung, LOW);      //abschalten der Zündfreigabe;

eben dieses habe ich versucht durch in die micros() Pendant umzuschustern. Nur leider funktioniert das ganze nicht wirklich.

GLOBALE VARIABLEN:
 volatile unsigned long triacONdelay;    //aka microsInterval1;
 unsigned long microsPrevious1 = 0;
 unsigned long microsPrevious2 = 0;
 unsigned long microsInterval2 = 250;  //25µs Zündimpuls;

ISR CODE:
unsigned int microsCurrentMoment1 = micros();
  if (microsCurrentMoment1 - microsPrevious1 >= triacONdelay) {
    microsPrevious1 = microsCurrentMoment1;
    digitalWrite(Zuendung, HIGH);     //Phase anschneiden;    
  }
  //Zeit für den Triac zum sicheren Zünden von 10µs ON-TIME garantiert danach;
  unsigned long microsCurrentMoment2 = micros();
  if (microsCurrentMoment2 - microsPrevious2 >= microsInterval2) {
    microsPrevious2 = microsCurrentMoment2;
    digitalWrite(Zuendung, LOW);      //abschalten der Zündfreigabe, sodass bei nächstem 0-Cross Triac auch sicher aus ist;      
  }

Auf dem Oszilloskop sieht man, in der Variante mit dem delayMicroseconds() den Impuls der Zündung an Ausgang schon sich in der Periode hin und her bewegen. Je nach Prozentualem Phasenanschnitt => also wie gewünscht.

Bei meinem kläglichen Versuch unten hängt der Zündimpuls einfach am Triggerpunkt fest, indem der Arduino den Nulldurchgang mit dem RISING Signal erkennt fest und bewegt sich nicht gemäßt der Regelstrecke.
ABER das Display freezed nicht mehr. Somit bin ich sicher, das zumindest die Ursache für freezen das delayMicroseconds() ist.

Funktioniert die BlinkWithoutDelay Adaption in ner ISR überhaupt? Oder sprengt mich da irgendwas raus?
Höffe ihr könnt mir da eventuell helfen und mich erleuchten
Dankeschonmal

Wieso Phasenanschnittsteuerung?

Vollwellensteuerung ist viel einfacher, effizienter, produziert weniger Störungen und funktioniert ohne Synchronisation.
Du brauchst nur ein SSR mit Nulldurchgangserkennung. Es genügt einen oder mehrere 20ms Ansteuerimpuls auf das SSR zu geben.

Grüße Uwe

Naja es gibt mehrere Gründe dafür.

  1. Der Lerneffekt wie man das ganze Funktionspaket aufbaut.
  2. Portierbarkeit der Phasenanschnittssteuerung auf andere Projekte
  3. und natürlich habe ich zur Zeit leider kein SSR vorrätig. Einen Triac habe ich und das SSR braucht auch relativ viel Platz.

ABER ich muss sagen das Vollwellensteuerung mit Triac noch auf dem Realisierungsplan liegt. (Bzw. Ich muss noch herausfinden wie ich das umsetze kann)

Hallo,

Blockierungen und serielle Ausgaben haben in einer ISR nichts zu suchen.
Man sollte dann nur Flags (volatile Variablen) setzen und diese im Hauptprogramm mit atomic auswerten.
Alle nicht lokalen Variablen der ISR müssen volatile sein. Das ist bei dir nicht der Fall wenn ich mich nicht irre.
Dann wird die Sache rund.
Wenn du deine millis Werte global nicht benötigst, dann mach sie lokal. Lokal macht weniger Probleme.

Warum überhaupt so schnell regeln? Für eine Lötstation genügt es doch, alle 5 bis 10 Sekunden die Heizung ein- oder auszuschalten, also einfach ein "blink" mit variablen An- und Aus-Zeiten

olf2012:
Warum überhaupt so schnell regeln? Für eine Lötstation genügt es doch, alle 5 bis 10 Sekunden die Heizung ein- oder auszuschalten, also einfach ein "blink" mit variablen An- und Aus-Zeiten

Hatte ich ja schon vorgeschlagen.
Er will Phasenanschnittsteuerung ausprobieren.

Grüße Uwe

olf2012:
Warum überhaupt so schnell regeln? Für eine Lötstation genügt es doch, alle 5 bis 10 Sekunden die Heizung ein- oder auszuschalten, also einfach ein "blink" mit variablen An- und Aus-Zeiten

Ich sage mal nein. Die muss sofort reagieren und heizen, wenn es der Lötspitze zu kalt wird. Dabei darf sie natürlich nicht zu stark überschwingen. Und wenn die Wärmeabnahme (Lötstelle) fehlt, dann muss sie wieder anders reagieren. Es bleibt eine Herausforderung. Die Idee mit der Vollwellensteuerung finde ich jedoch auch gut. Das eine hat jedoch mit dem anderen nichts zu tun.

Hallo also effektiv habe ich jetzt mal die restlichen globalen Variablen noch volatile gesetzt. Leider funktioniert es aber immer noch nicht....? Aber ich muss erlich sagen ich weiß nicht warum.

Die vier globalen Variablen, dabei einmal einen simplen Zähler der Nulldurchgänge welcher auch sinnvolle Werte über die loop-Schleife im SeriellenMonitor auswirft. Somit wird die ISR ja richtig aufgerufen und irgenwas stimmt nur mit der micros() Funktion die verwende nicht??? ODER...

"triacONdelay" beziehe ich aus der Regelstrecke im loop. Die Regelstrecke selbst und auch der Wert triacONdelay gibt auch sinnvolle Werte via loop-SeriellMonitor Ausgabe zurück.

Nur eben die Ansteuerung des "Zuendung" Pin hängt fest in dem Punkt wo das Interrupt ausgelöst wird und somit die RISING Flanke erkannt wird.
Und wie im Startpost möchte ich "eigentlich" nur die delayMicroseconds() durch eine if-Schleife mit der micros() Funktion ersetzen. Nur irgendwie happerts da eben, leider.

Und die anderen beiden Variablen für den micros() Zähler als Startwert.

volatile unsigned long counterZeroCrosses;
volatile unsigned long triacONdelay;         
volatile unsigned long microsPrevious1 = 0;
volatile unsigned long microsPrevious2 = 0;

Und hier die Interrupt-Routine:

void zeroCrossDetected() {  
  ++counterZeroCrosses;                                   //Zähler für die Nulldurchgänge;
  
  
  unsigned long microsCurrentMoment1 = micros();
  if (microsCurrentMoment1 - microsPrevious1 >= triacONdelay) {
    microsPrevious1 = microsCurrentMoment1;
    digitalWrite(Zuendung, HIGH);     //Phase anschneiden;    
  }
  //Zeit für den Triac zum sicheren Zünden von 25µs ON-TIME garantiert danach;
  unsigned long microsInterval2 = 25;  //25µs Zündimpuls;
  unsigned long microsCurrentMoment2 = micros();
  if (microsCurrentMoment2 - microsPrevious2 >= microsInterval2) {
    microsPrevious2 = microsCurrentMoment2;
    digitalWrite(Zuendung, LOW);      //abschalten der Zündfreigabe, sodass bei nächstem 0-Cross Triac auch sicher aus ist;      
  }

Ich weiß nicht so recht ob ich mein Problem richtig darstellen kann....respektive ob ichs verständlich mache korrekt......

Außerhalb der ISR musst du auf diese Variablen atomar zugreifen. Das heißt bei abgeschalteten Interrupts

@Serenifly:
auf welche Variablen beziehst du dich und wie meinst du das mir atomar genau? Bin mir nicht sicher ob ich das korrekt verstanden habe, sorry.

Wenn du meinst das ich in der Regelstrecke während ich "triacONdelay" verändere die Interrupts abschalten muss damit die ISR den Wert dann aufrufen kann?

Das habe ich schon mal Versucht ändert aber nichts am Problem. (die 9420 sind die µs die max. bis zur Triaczündung gewartet werden sollen)

noInterrupts();  
  //Regelstrecke;
  myPID.Compute();
  int PIDOutputINT = int(PIDOutput);
  int PIDOutputPercent = map(PIDOutputINT, 0, 255, 0, 100);
  triacONdelay = map(PIDOutput, 0, 255, 9420, 0); 
interrupts();

Hallo,

zeig doch mal den gesamten Sketch und nicht immer nur Bruchstücke.
Ein abstraktes Bsp. mit atomic sicheren Zugriff.

#include <util/atomic.h>    // für cli() und sei() mit SREG Sicherung

volatile int ISR_value;    // wird in der ISR verändert
int ISR_value_Sicherung;   // für Übernahme

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  ...
  
  ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {    // cli()+sei() mit SREG Sicherung
    ISR_value_Sicherung = ISR_value;  // Variable aus ISR wird sicher vor Zugriff und 
    ...                               // zwischenzeitlicher Veränderung übernommen bzw. ausgelesen
    ...
    ...
  }
    
}

Oh natürlich, Entschuldigung war keine Absicht oder so.

#include <LiquidCrystal.h>
#include <PID_v1.h>

#define IstwertThermoelement A0     //ADC0;
#define SollwertPoti A1             //ADC1:
#define zeroCross 2                 //INT0;
#define Zuendung 9                  //OC1A; ??? überhaupt benötigt PWM Pin ???

//globale Variablen für delayMicroseconds Ersatzfunktion;
volatile unsigned long counterZeroCrosses;
volatile unsigned long triacONdelay;          //aka microsInterval1;
volatile unsigned long microsPrevious1 = 0;
volatile unsigned long microsPrevious2 = 0;
    
//globale Übergabevariablen für PID Aufruf in der Interrrupt-Schleife;
double PIDthTempJformel = 0;        //Übergabe in loop-Schleife aus IST-Wert Thermoelement-Messung;
double PIDOutput = 0;
double PIDtemperaturSoll = 0;       //Übergabe in loop-Schleife aus SOLL-Wert Poti-Abfrage;
//Regelparameter PID;
double PIDKp = 1.0;
double PIDKi = 5.0;
double PIDKd = 0.05;

//PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, POn (P_ON_E (error) or P_ON_M(measurement)), Direction); 
//PID myPID(Lötkolben-IST-Temperatur, "PWM 0-255" PID-Regelgröße, Poti-Sollwert, Kp, Ki, Kd, POn (P_ON_E (error) or P_ON_M(measurement)), Direction);
PID myPID(&PIDthTempJformel, &PIDOutput, &PIDtemperaturSoll, PIDKp, PIDKi, PIDKd, P_ON_E, DIRECT); 



//LiquidCrystal(RS, ENABLE, D4, D5, D6, D7) --- R/W auf GND für write;
//LCD-Pinout (Pin3-6;11-14): V0 weiß; RS schwarz; R/W braun; ENABLE rot; D4 orange; D5 gelb; D6 grün; D7 blau;
LiquidCrystal lcd(11, 12, 4, 5, 8, 10);
uint8_t DegreeBitmap[]= { 0x6, 0x9, 0x9, 0x6, 0x0, 0, 0, 0 };      //erstellen von °-Zeichen
unsigned long millisPrevious = 0;  
const long millisInterval = 200; 

void setup() {
  Serial.begin(9600);
  lcd.createChar ( 1, DegreeBitmap );                             //einfügen von °-Zeichen in custom-Char '1';

  //PID-Regler initialisieren;
  myPID.SetMode(AUTOMATIC);                                       //Aktivierung PID-Regelung;
  
  //Eingänge konfigurieren;
  analogReference(DEFAULT);
  pinMode(IstwertThermoelement, INPUT);
  pinMode(SollwertPoti, INPUT);  

  //Interrupt für Nulldurchgangserkennen;
  pinMode(zeroCross, INPUT);
  counterZeroCrosses = 0;
  attachInterrupt(digitalPinToInterrupt(zeroCross), zeroCrossDetected, RISING);

  //Ausgabe konfigurieren;
  pinMode(Zuendung, OUTPUT);
  
  //LCD Init und check ob Lötkolben/Thermoelemt angeschlossen ist;
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("BOOTING -- Check");
  lcd.setCursor(0,1);

/////////////////////////////////////////TODO: Anschlusserkennung Lötkolben/Fehlerausgabe - notConnected;
   
  delay(2500);
  //Statische Werte im LCD;
  lcd.clear();
  //Zeile 1;            
  lcd.setCursor(0,0);
  lcd.print("Soll ");               //9digits 
  //Zeile 2;       
  lcd.setCursor(1,1);
  lcd.print("Ist ");                //8digits
}

arduino-wasser:
und wie meinst du das mir atomar genau?

Spielt auch im Multi-Threading Bereich eine sehr wichtige Rolle

Wenn du meinst das ich in der Regelstrecke während ich "triacONdelay" verändere die Interrupts abschalten muss damit die ISR den Wert dann aufrufen kann?

Ja. Das sind Multi-Byte Variablen. Und hast einen 8-Bit Prozessor. Wenn du also außerhalb der ISR auf solch eine Variable zugreifst kann zwischen zwei Bytes die ISR drann kommen

Wobei du die Interrupts auch nicht länger aus unbedingt nötig abschalten musst. Es reicht direkt vorher abschalten und gleich wieder aktivieren. Wenn man eine Variable an mehrere Stellen braucht macht man eine Kopie

void loop() {
//Erhöhen der ADC-Sammpling Rate???;
//Bitmath Register verändern???;
  
  //Sollwert Messung Potentiometer;
  long potiSollMW1000 = 0;
  long potiSolladd = 0;
    for (int count1 = 0; count1 < 1000; count1++){
      long potiSollMomentan = analogRead(SollwertPoti);
      potiSolladd = potiSolladd + potiSollMomentan; 
    }
    potiSollMW1000 = potiSolladd / 1000;
  
  int temperaturSoll = map(potiSollMW1000, 0, 1023, 0, 60);    
  //Staffelung des Potis in 5°C Schritte:
    temperaturSoll = (temperaturSoll * 5) + 150;
  //übertragen in PID-Regelparameter;
  PIDtemperaturSoll = double(temperaturSoll);

  //Konstanten zur Berechnung der Thermoelement Temperatur;
  const int thAmplification = 166;              //Verstärkung Thermoelement Messverstärker 6k/1M=166,667
  const float thmVperDigitTypeJ = 0.054423333;  //Temperaturkonstante - °C/mV
  const int thCalibration = 0;                  //0°C-100°C Kalibrierung/Abgleichsfaktor  
  // Erstellen des ADC-Mittelwerts zur Anzeige-Temperatur-Stabilisierung;
  long thAmpMW1000 = 0;
  long thAmpMWadd = 0;
      for (int count2 = 0; count2 < 1000; count2++){
        long thAmpMomentan = analogRead(IstwertThermoelement);
        thAmpMWadd = thAmpMWadd + thAmpMomentan;
      }    
      thAmpMW1000 = thAmpMWadd / 1000; 
             
  float thTempJformel = (((thAmpMW1000 * (5.0 / 1023.0)) / thAmplification) * 1000) / thmVperDigitTypeJ; 
  //übertragen in PID-Regelparameter;
  PIDthTempJformel = double(thTempJformel);
  int thTempJformelINT = int(thTempJformel);
  
  //Regelstrecke;
  myPID.Compute();
  int PIDOutputINT = int(PIDOutput);
  int PIDOutputPercent = map(PIDOutputINT, 0, 255, 0, 100);
  triacONdelay = map(PIDOutput, 0, 255, 9420, 0); 
      
  //LCD via millis()-Funktion alle Interval-ms ansteuern und Display refreshen;
  unsigned long millisCurrentMoment = millis();
    if (millisCurrentMoment - millisPrevious >= millisInterval) {
        millisPrevious = millisCurrentMoment;          
          //Ansteuerung LCD für Betrieb 16*2 ;
            //Zeile 1;
            lcd.setCursor(5,0);
            lcd.print(temperaturSoll);            //3digits;
            lcd.setCursor(8,0);
            lcd.print((char)001);                 //1digit;
            lcd.setCursor(9,0);
            lcd.print("C");                       //1digit;
            //Zeile 2;                                       
            if (thTempJformelINT >= 100) {
              lcd.setCursor(5,1);
              lcd.print(thTempJformelINT);        //3digits;
            }
            if ((thTempJformelINT < 100) && (thTempJformelINT >= 10)) {
              lcd.setCursor(5,1);
              lcd.print(" ");                     //1empty digits für <100°C;
              lcd.setCursor(6,1);
              lcd.print(thTempJformelINT);        //2digits;
            }
            if ((thTempJformelINT < 10) && (thTempJformelINT >= 0)) {
              lcd.setCursor(5,1);
              lcd.print("  ");                    //2empty digits für <10°C;
              lcd.setCursor(7,1);
              lcd.print(thTempJformelINT);        //1digit <10°C;
            }            
            lcd.setCursor(8,1);
            lcd.print((char)001);                 //1digit;
            lcd.setCursor(9,1);
            lcd.print("C");                       //1digit

            if (PIDOutputPercent >= 100) {
              lcd.setCursor(12,0);
              lcd.print(PIDOutputPercent);  
            }
            if ((PIDOutputPercent < 100) && (PIDOutputPercent >= 10)) {
              lcd.setCursor(12,0);
              lcd.print(" ");
              lcd.setCursor(13,0);
              lcd.print(PIDOutputPercent);
            }
            if ((PIDOutputPercent < 10) && (PIDOutputPercent >= 0)) {
              lcd.setCursor(12,0);
              lcd.print("  ");
              lcd.setCursor(14,0);
              lcd.print(PIDOutputPercent);  
            }
            lcd.setCursor(15,0);
            lcd.print("%");
    }
  //Ende LCD Ausgabe;

Serial.print("Nulldurchgänge: ");
Serial.println(counterZeroCrosses);
Serial.print("PID-Soll: ");
Serial.println(PIDOutput);
Serial.print("triacONdelay: ");
Serial.println(triacONdelay);

}

//Interrupt-Funktion an INT0 mit Optokoppler-Doppel-Nulldurchgangserkennung;
//Signal alle 50Hz => 10-ms peak-peak --- RISING Signal HIGH if 0-Cross;
void zeroCrossDetected() {  
  ++counterZeroCrosses;                                   //Zähler für die Nulldurchgänge;
  
  //Triac-Steuerstrecke via Phasenanschnitt für Ohmsche und Induktive Lasten;
  //Werte ermittelt mit Oszilloscop - aus 15VAC 0,8A Steckernetzteil;
  //Risetime 340µs,Falltime 340µs,pos-Width 940µs, neg-Width der OptokopplerSchaltung 9080µs => max. Peridode= 10,04ms;
  //somit max. 9420µs Zeit um den Triac anzuschalten damit er nicht im Fall-Signal erst gezündet würde; 
  //Zeit in µs abwarten bis der Phasenanschnitt beginnt und der Triac HIGH geschalten wird;
  
  
  unsigned long microsCurrentMoment1 = micros();
  if (microsCurrentMoment1 - microsPrevious1 >= triacONdelay) {
    microsPrevious1 = microsCurrentMoment1;
    digitalWrite(Zuendung, HIGH);     //Phase anschneiden;    
  }
  //Zeit für den Triac zum sicheren Zünden von 25µs ON-TIME garantiert danach;
  unsigned long microsInterval2 = 25;  //25µs Zündimpuls;
  unsigned long microsCurrentMoment2 = micros();
  if (microsCurrentMoment2 - microsPrevious2 >= microsInterval2) {
    microsPrevious2 = microsCurrentMoment2;
    digitalWrite(Zuendung, LOW);      //abschalten der Zündfreigabe, sodass bei nächstem 0-Cross Triac auch sicher aus ist;      
  }

/*Funktioniert aber blockiert; 
    delayMicroseconds(triacONdelay);
    digitalWrite(Zuendung, HIGH);     //Phase anschneiden; 
    delayMicroseconds(25); 
    digitalWrite(Zuendung, LOW);      //abschalten der Zündfreigabe, sodass bei nächstem 0-Cross Triac auch sicher aus ist;      
*/
}

Serenifly:
Ja. Das sind Multi-Byte Variablen. Und hast einen 8-Bit Prozessor. Wenn du also außerhalb der ISR auf solch eine Variable zugreifst kann zwischen zwei Bytes die ISR drann kommen

Wobei du die Interrupts auch nicht länger aus unbedingt nötig abschalten musst. Es reicht direkt vorher abschalten und gleich wieder aktivieren.

Im Grunde wie beim 4-Bit Modus eines "eigentlich" 8-Bit LCD wo mit LOW/High Byte gearbeitet wird. Nur können in meinem Fall noch mehr Häppchen sein. Richtig oder soweit?
Also reicht es effektiv wenn ich den Interrupt im Falle des loop-Zugriffes auf die Variable triacONdelay abstelle.

noInterrupts();
  triacONdelay = map(PIDOutput, 0, 255, 9420, 0); 
interrupts();

Ja, aber das gilt genauso für die anderen Variablen. Wenn du lesend darauf zugreifst passiert vielleicht nichts schlimmes wenn es nur um eine Ausgabe zur Kontrolle geht, aber du kannst trotzdem inkonsistente Daten haben

Variablen die nur in der ISR verwendet werden - wie der micros() Zählerstand - müssen übrigens nicht global sein. Sondern können in der ISR als static deklariert werden. Dann behalten sie ihren Wert bei. Wie bei normalen Funktionen auch

Hallo,

der counter in der ISR wäre nur ein Anzeigeproblem. Hat keine Wirkung auf den Code an sich.
Wenn das richtig laufen soll, dann so

ATOMIC_BLOCK (ATOMIC_RESTORESTATE) {    // cli()+sei() mit SREG Sicherung
    ISR_counterZeroCrosses = counterZeroCrosses;  // Variable aus ISR vor Zugriff/Änderung sicher auslesen
  }
  Serial.println(ISR_counterZeroCrosses);

ganz oben fügst du noch die Lib ein und brauchst natürlich noch die Initialiserung der zusätzlichen Sicherungsvariablen, kannst auch andere Namen verwenden.

#include <util/atomic.h>    // für cli() und sei() mit SREG Sicherung

unsigned long ISR_counterZeroCrosses;

@Doc_Arduino:
ok, aber das einzige was ja meiner Meinung nach richtig bereits funktioniert ist der Counter.

Jedoch eben nicht die Ansteuerung von meinem Ausgang Zuendung den ich mit der if-Schleife und den micros() Zähler versuche zu Schalten.
Hast du dazu auch eine Idee?

Hallo,

dann haben wir uns falsch verstanden, korrigiert dennoch einen Fehler.

Also das was in der ISR namens zeroCrossDetected am Ende auskommentiert ist möchtest du zum laufen bekommen?
Soll das nur behandelt werden wenn der ISR aktiv ist?

Dann setze ein Flag und merkst dir den Zeitpunkt dessen in der ISR welches du außerhalb der ISR behandelst und zurücksetzt wenn abgearbeitet. Den Rest machste wieder blockierfrei mit micros rechnen in der Funktion außerhalb der ISR.

Ich glaube jetzt sehe ich mehr. Der Code oberhalb der Auskommentierung soll das darstellen?
Naja, der kann an der Stelle nur rechnen und vergleichen wenn die ISR aufgerufen wird. Ansonsten tut sich dort nichts.
Deswegen wie gesagt Flag in der ISR setzen und Zeitpunkt merken, worauf man außerhalb der ISR jederzeit reagieren kann.
Die beiden µs delays wäre dann ein Art Schrittkette was noch eine Statusvariable verlangt. Laut meiner Auffassung.

Sowas ähnliches und etwas kürzer wirst du bestimmt dann programmieren müssen.
http://forum.arduino.cc/index.php?topic=465607.0

Umgang mit millis/micros ist klar?

Theseus erklärt millis()
http://forum.arduino.cc/index.php?topic=400102.msg2752141#msg2752141

GuntherB - BlinkwithoutDelay - Die Nachtwächtererklärung
http://forum.arduino.cc/index.php?topic=423688.0

Erstmal danke für die Info mit der ATOMIC Funktion, mir is nun klar das bei Zeitkritischen(oder überhaupt Interrupt beiflussten Variablen) das Lesen/Schreiben darauf Zeitlich einwirkt und somit den "korrekten" Wert verfälscht. :smiley:

Nun zum eigentlichen Salat:

Doc_Arduino:
Also das was in der ISR namens zeroCrossDetected am Ende auskommentiert ist möchtest du zum laufen bekommen?
Soll das nur behandelt werden wenn der ISR aktiv ist?

Ja, das ist mein größtes Problem gerade....bitte :smiley:

Doc_Arduino:
Ich glaube jetzt sehe ich mehr. Der Code oberhalb der Auskommentierung soll das darstellen?
Naja, der kann an der Stelle nur rechnen und vergleichen wenn die ISR aufgerufen wird. Ansonsten tut sich dort nichts.
Deswegen wie gesagt Flag in der ISR setzen und Zeitpunkt merken, worauf man außerhalb der ISR jederzeit reagieren kann.

Ich denke ich hab mich da mit der Zeitverzögerung mittels micros() in der ISR zeroCrossDetected wohl etwas verrannt.
micros(),millis() -Funktionsschleifen sind mir eigentlich soweit klar wie ich sie aufrufen muss.
Ok. Soweit schonmal alles in Ordnung.

Doc_Arduino:
Dann setze ein Flag und merkst dir den Zeitpunkt dessen in der ISR welches du außerhalb der ISR behandelst und zurücksetzt wenn abgearbeitet. Den Rest machste wieder blockierfrei mit micros rechnen in der Funktion außerhalb der ISR.

Und mit Flag aufrufen meinst du im Interrupt zeroCrossDetected nur ein boolean = true für eine BoolescheVariable setzen.
Welche dann in der loop-Schleife abgefragt wird und eine eigene Funktion für den Phasenschnitt an sich aufruft.
Die Phasenschnittfunktion lässt dann die Zeitverzögerung (meine Variable triacONdelay verstreichen. Und schaltet den Triac für ne bestimmte Zeit an und löscht die Freigabe wieder.

Aber wie meinst du das mit "Zeitpunkt merken", das wäre das einzige was ich soweit noch nicht verstanden haben.
Danke