in der ISR delayMicroseconds() ersetzen

Hallo,

gut, dann sind wir ein Stück weiter.
Ja, mit Flag oder Merker meint man in der Regel eine boolsche Variable, die nur ein Ereignis dokumentieren soll, worauf man dann reagiert. Neuerdings heißt auch dieser Datentyp in der IDE richtigerweise bool und nicht mehr boolean, wird jedoch noch beides aktzeptiert. Hat mal Serenifly erklärt vor längere Zeit. :wink:

Du brauchst also ein Flag damit dieses hier außerhalb der ISR starten kann. Soweit ist dir das ja bewusst.
Da du hier aber gleich mit einer Verzögerung beginnst, brauchst noch den Zeitpunkt der Flag Setzung.

/*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;      
*/

Im Grunde könnte deine ISR nur aus 3 Zeilen bestehen. Alle volatile. Den Rest machste in der loop inkl. zurücksetzen vom Flag. Falls die ISR eher wieder drankommt wie du außerhalb fertig bist, kannste den ISR Code noch so umschreiben das die neue Zeit nur neu gemerkt wird und das flag nur neu gesetzt wird wenn es "false". Das sollte jedoch nie der Fall sein, sonst hättest Zündausetzer.
Das wäre jetzt meine Vorschlag ohne bis ins letzte Detail zu gehen.

void zeroCrossDetected() { 
  ++counterZeroCrosses;                                   //Zähler für die Nulldurchgänge;

  flag_TriacStartRoutine = true;                  // bool

  time_TriacStartRoutine = micros();              // unsigned long
}

mit sinnvollen Variablennamen habe ich es nicht so ... benenne es wie du magst.

Die Funktion außerhalb könnte so aussehen, ob das funktioniert kann ich nicht testen.

  if (flag_TriacStartRoutine == true) {       // Startbedinung aus ISR
    if (micros() - time_TriacStartRoutine >= triacONdelay) {
      digitalWrite(Zuendung, HIGH);           // Phase anschneiden  
      flag_TriacStartRoutine = false;         // Flag zurücksetzen
      zuendung_ein = true;                    // zusätzliche bool
    }
  }

  if (zuendung_ein == true) {  
    if (micros() - time_TriacStartRoutine >= (triacONdelay + 25 )) {
      digitalWrite(Zuendung, LOW);            // abschalten der Zündfreigabe
      zuendung_ein = false;                   // Flag zurücksetzen
    }
  }

Da es bei dir um µs geht, wird mit der zusätzliche bool ein ständig neues Zündung HIGH setzen vermieden innerhalb der nächsten 25µs. Der zusätzliche Code sollte schneller sein als mehrfach digitalWrite.
Viel Spass beim grübeln oder machst das ganz anders ...
atomic Zugriff nicht vergessen!

Doc_Arduino:
Da es bei dir um µs geht, ...

Ist in so einem Fall nicht die Zünd-Triggerung per HW-Timer wesentlich exakter? Im Null-Durchgangs-ISR wird der Timer gestartet und in der Timer ISR dann der Triac gezündet. Das Timing im loop() ist dann wesentlich unkritischer und der loop kann sich ungestört den Bedienelementen und dem LCD widmen.
Oder man geht eben doch gleich auf Vollwellensteuerung - da passiert eh alles im Nulldurchgang.

Hallo,

klar wäre das genauer, :slight_smile: weil die loop Durchlaufzeiten nicht konstant sind. Dadurch werden auch Zeitvergleiche in der loop mal "eher" und mal "später" abgearbeitet im Vergleich zum vorherigen Durchlauf. Vollenwellensteuerung wurde schon mehrfach als die bessere Lösung angepriesen. Jetzt muss er wissen wie genau er seine Lötstation haben möchte.
Das ist keine böse Kritik - eine Empfehlung von allen.
Vom Verständnis her ist das jetzige erstmal die einfachere Variante, rein vom Aufbau und Code her - denke ich zumindestens.
Wenn er das drauf hat und alles funktioniert und mit Timer usw. besser umgehen kann, wird er bestimmt eine neue Herausforderung suchen und alles genauer machen wollen. :slight_smile:

Ich denke auch, man sollte jeden Zeit geben sich einzuarbeiten in neue Themen und Hinweise.
Die Selbsterkenntnis ist manchmal wichtiger wie tausend Hinweise, auch wenn sie noch so richtig sind. :slight_smile:
Habe ich selbst schon oft bei mir erlebt.

Doc_Arduino:
Ich denke auch, man sollte jeden Zeit geben sich einzuarbeiten in neue Themen und Hinweise.
Die Selbsterkenntnis ist manchmal wichtiger wie tausend Hinweise, auch wenn sie noch so richtig sind. :slight_smile:

Das ist zweifellos richtig. Bekanntermaßen ist ja noch kein Meister vom Himmel gefallen. Und auch das Hinfallen gehört zwingend zum Laufenlernen dazu :wink:

Also an alle zunächst einmal Danke für eure Geduld.
Ich hatte es wie Doc_Arduino schrieb versucht zum laufen zu bekommen. Das Ergebniss war unschön.... eine Menge an "geflattere" des Ausgangs und mehr aber auch nicht. Scheinbar war die Schleife selbst einfach zu langsam und vorallem SEHR UNTERSCHIEDLICH lange in den Ausführungszeiten, und das wurde ja auch schon prophezeit. Also machte ich mich an die Umgekehrte Lernstrategie, erstmal Code-Raubbau zu betreiben, den Code zu implentieren und mich dann ans "eigentliche" Verstehen zu machen......
.......und wie es google immer schafft bei korrekter Bedienung, hatte ich nach einige dutzend Seiten ein für mich ansatzweise verständliches HARDWARE gestützes Codesnippet gefunden. Und wenn wunderts eine Arduino-Homebase. ACPhaseControl.....

Das Einbinden des Code lief eigentlich ganz gut, musste nur den D4 Pin meines LCD-shiften da da drauf der Timer0-Clock Pin vom AtMega drauf war und das LCD zu spinnen anfing. Aber das war kein Problem.

Und TADA, nachdem der Code problemlos eingebetet war und mein PID-Regelausgang/bzw. in meinem momentanen Breadboard Fall, noch das Poti der Solltemperatur als Stellwertgeber (0-255 um den PID-Output zu simulieren) fungierte, klappte alles wie gewollt.
Mithilfe des Oszilloscopes noch die Zündzeitpunkte für frühestes und spätestes Triac zünden Optimiert und es lief alles wie gewünscht.
Und Timingtechnisch ist die Hardwareseitige Lösung wirklich genau, danke das Ihr mir da Zeit gegeben habt das selbst zu erkennen :confused:

Das was mir jetzt halt noch als Wermutstropfen übrig bleibt sind leider einige Fragen und noch einige Fragen mehr. Die sehr im Mindfuck endeten nachdem ich versucht hatte die Timer Funktionen zu verstehen im Datenblatt.....sind ja nur ein paar Dutzend Seiten :smiley: Naja in dem Punkt, kommt Zeit kommt Verständnis :smiley: hoffentlich

für alle die sich für meinen aktuellen Code im Moment den interessieren würde, siehe Anhang.

Primär hätte ich nur ein paar kleine Fragen, welche ich im Bezug auf den Code noch direkt habe, alles andere wird sich mir schon erschließen.

1.Warum ist die HIGH-Zeit, also der Triac Zündimpuls immer 64µs lang respektive 4counts bzw. 400Taktschritte des Controllers lang?
2.Warum brauch der Timer1 den PinD4 also T0 extern?

sketch_aug26i.ino (9.57 KB)

arduino-wasser:
1.Warum ist die HIGH-Zeit, also der Triac Zündimpuls immer 64µs lang respektive 4counts bzw. 400Taktschritte des Controllers lang?

Weil Du im Compareinterrupt ( wo der Triac gezündet wird ) den Zähler auf 65536-zeroTrigger stellst. Da zeroTrigger 4 ist, braucht es dann noch genau 4 Counts bis zum Überlauf des Zählers, und im Overflow IRQ schaltest Du den Zündimpuls wieder ab.

arduino-wasser:
2.Warum brauch der Timer1 den PinD4 also T0 extern?

Wie kommst Du da drauf? Timer1 hat mit dem PinD4 nichts am Hut. Den kann man als externen Takt für USART oder Timer 0 verwenden, was hier aber nirgends gemacht wird.
Diese Definition:

#define zeroTrigger 4               //T0 XCK-Counter;

hat überhaupt nichts mit T0/XCK oder PinD4 zu tun. Das ist einfach die Anzahl Ticks, die dein Zündimpuls lang ist.

Hallo,

ich freue mich ebenfalls das es funktioniert. Fragen wurden schon beantwortet. Das mit den Timer lernst du sicherlich auch noch. Damit kann man eine ganze Menge machen.