Dieser Thread stammt ursprünglich HIERHER, hat aber mit dem Ausgangsproblem nicht mehr viel zu tun, der Ordnung halber nun ein neuer.
Zwei Dinge, die man mir beigebracht hat sind sehr prägend hängen geblieben:
Gelber Schnee ist baba!
Finger weg von Delay
Und tatsächlich habe ich ein Problem mit einem Code, der mit Delay nicht funktionert, den ich aber einfach nicht in millis() umgeschreiben bekomme.
Könnt ihr mir da helfen?
DIESER Code funktioniert:
int R1 = 29;
int DimmPin1 = 4;
int DimmWert1 = 90; //einfach ein Wert zum ausprobieren.
int EinschaltZeit1 = 0;
void setup()
{
pinMode(R1, OUTPUT); //Hier ist ein Relais für die Leuchte angesteuert
digitalWrite(R1, HIGH); //Relais für Leuchte ein
pinMode(DimmPin1, OUTPUT);
attachInterrupt(0, zero_crosss_int, RISING); // PIN 2 am Mega- Clone
}
void zero_crosss_int()
{
EinschaltZeit1 = (75*DimmWert1); // For 60Hz =>65
delayMicroseconds(EinschaltZeit1); // Wait till firing the TRIAC
digitalWrite(DimmPin1, HIGH); // Fire the TRIAC
delayMicroseconds(10); // triac On propogation delay
// (for 60Hz use 8.33) Some Triacs need a longer period
digitalWrite(DimmPin1, LOW); // No longer trigger the TRIAC (the next zero crossing will swith it off) TRIAC
}
void loop()
{
/*
Das rauf- und runter Dimmen wird erst später benötigt
for (int i=50; i <= 95; i++){
DimmWert1=i;
delay(100); */
}
Mein Versuch das in millis() (micros) umzuschreiben sieht so aus und funtioniert NICHT:
Das stimmt nicht so ganz. Man kann die Zeiten in einer ISR schon abfragen. Aber sie werden nicht inkrementiert. Und auch das muss man eingrenzen:
unsigned long micros() {
unsigned long m;
cli();
m = timer0_overflow_count;
t = TCNT0;
return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}
Das ist gekürzt auf das relevante. Wie man sieht fließt der aktuelle Zählerstand immer ein. Aber der Überlauf (der ca. alle 1ms kommt) wird bei abgeschalteten Interrupts nicht höher
Außerdem solltest du micros() nicht immer wieder neu auslesen. Funktionsaufrufe kosten viel Zeit. Wobei das hier nicht so schlimm ist, da du dich beim Dimmen im Millisekunden Bereich bewegst
Und schon die nächste Frage:
Wenn ich einen Arduino Mega (Clon) und einen Nano (Clon) miteinander kommunizieren lassen will, und nur EINEN Wert übertregen möchte, was wäre da die einfachste Vorgehensweise für jemanden, der davon (noch) keine Ahnung hat?
Ein Signal über PWM ausgeben und analog einlesen?
Mehr über die serielle (oder was auch immer) Kommunikation zwischen zwei Arduinos lernen?
I2C oder Seriell
Bei der seriellen Schnittstelle hat der Mega mehrere. Auf dem Nano sollte man Software Serial verwenden und nicht die Hardware-Schnittstelle.
Mal darüber nachgedacht. Das geht sowieso in der ISR so nicht.
Ja, man kann micros() abfragen. Aber du bist nur einmal beim Nulldurchgang in der ISR. Du kannst also nicht rechzeitig abfragen ob die Zeit abgelaufen ist.
Du musst in der ISR ein Flag setzen und darauf in loop() abfragen. Und dann ständig abfragen ob die Zeit vorbei ist. Außerhalb könnte man dann auch delay() verwenden. Oder es nicht-blockierend machen was natürlich besser ist, wenn du noch andere Dinge wie Kommunikation erledigen willst.
Auch mit delay() muss der Rest des Codes nicht-blockierend sein, damit man das Flag in der Zeit zuverlässig abfrägt
Tiff48317:
Das heißt, das Problem ist für mich unlösbar.
Oder...ich nehme einen zweiten Arduino, der nur für das Dimmproblem zuständig ist.
Und der kann dann so viel Delay benutzen wie er lustig ist... :o
Och...
Das könnte auch für dich lösbar sein....
Wenn du dich in die ISR Thematik einliest.
Oder auch das Datenblatt des ATMega2560 auswendig lernst.
Denn da steht viel über die eingebauten Timer und ihre Möglichkeiten.
Serenifly:
Mal darüber nachgedacht. Das geht sowieso in der ISR so nicht.
Ja, man kann micros() abfragen. Aber du bist nur einmal beim Nulldurchgang in der ISR. Du kannst also nicht rechzeitig abfragen ob die Zeit abgelaufen ist.
Du musst in der ISR ein Flag setzen und darauf in loop() abfragen. Und dann ständig abfragen ob die Zeit vorbei ist. Außerhalb könnte man dann auch delay() verwenden. Oder es nicht-blockierend machen was natürlich besser ist, wenn du noch andere Dinge wie Kommunikation erledigen willst.
Auch mit delay() muss der Rest des Codes nicht-blockierend sein, damit man das Flag in der Zeit zuverlässig abfrägt
Nicht blockierend sollte es sein.
Es ist noch einges anderes dabei (z.B. IR Fernbedienung und später Blauzahn), was auch dann funktionieren soll.
Wenn Du das mit einem Prozessor sauber machen willst, wirst Du nicht umhin kommen, dich mit den Timern zu beschäftigen. Man muss das Datenblatt ja nicht gleich auswendig lernen. Aber man sollte wissen, was die Timer können, und wo steht, wie man das nutzt.
Du brauchst dann 2 Interrupts:
im zero_crosss_int erkennst Du den Nulldurchgang, berechnest, wann Du den Triac zünden willst, und ziehst den Timer mit dieser Zeit auf. Wenn dann der Timer seine ISR feuert, wird da nur noch der Triac gezündet - fertig.
Der loop ist dann völlig frei für andere Aufgaben und gibt letztendlich nur die Zeit zwischen Nulldurchgang und Zünden vor.
Dann werde ich mich mal mit timern beschäftigen. Uff...
Bis dahin (auch auf die Gefahr, völlig falsch zu liegen) ginge es vielleicht so?
int R1 = 29;
int DimmPin1 = 4;
int DimmWert1 = 50; //einfach ein Wert zum ausprobieren.
int EinschaltZeit1 = 0;
volatile bool trigger = false;
void setup()
{
pinMode(R1, OUTPUT); //Hier ist ein Relais für die Leuchte angesteuert
digitalWrite(R1, HIGH); //Relais für Leuchte ein
pinMode(DimmPin1, OUTPUT);
attachInterrupt(0, zero_crosss_int, RISING); // PIN 2 am Mega- Clone
}
void zero_crosss_int() { IAC }
void isr(){ trigger = true;}
void loop()
{
if(trigger)
{
trigger = false;
EinschaltZeit1 = (75*DimmWert1); // For 60Hz =>65
delayMicroseconds(EinschaltZeit1); // Wait till firing the TRIAC
digitalWrite(DimmPin1, HIGH); // Fire the TRIAC
delayMicroseconds(10); // triac On propogation delay
digitalWrite(DimmPin1, LOW); // No longer trigger the TRIAC (the next zero crossing will swith it off) TR
}
}
Es gibt Denke ich auch fertigen Code dazu. Wobei man das schon verstehen muss, da man es eventuell anpassen muss wenn vielleicht andere Bibliotheken noch einen Timer verwenden wollen
wenn vielleicht andere Bibliotheken noch einen Timer verwenden wollen
Timer0 ist belegt, für den ganzen Arduino Zeitkram.
Allerdings sind dessen Compare Interrupts eher nie in Benutzung. Also frei.
Und wenn man die PWM Funktionen des Timer0 auch nicht nutzt, dann kann man sich da schon was draus basteln.
Nachteil beim Timer 0 ist die Durchlaufzeit von ca. 1ms, an der man nichts ändern darf, da sonst die millis nicht mehr stimmen. Da muss man dann die Zünd-ISR mehrfach auslösen und mitzählen bis es 'feuert', denn Zeiten über 1ms wird man wohl brauchen.
Da muss man dann die Zünd-ISR mehrfach auslösen und mitzählen bis es 'feuert', denn Zeiten über 1ms wird man wohl brauchen.
Wohl wahr!
Aber da eine Halbwelle nur 10ms hat, muss man auch nur maximal bis 9 zählen.
8) Das soll doch ein AVR wohl hin bekommen. 8)
Immerhin wirds damit recht exakt...
256 Zählerstände pro ms
Macht dann ca. 2560 mögliche Zündzeitpunkte pro Halbwelle.
OK, die Enden, da fehlen ein paar Prozent, wegen den ISR Laufzeiten.
Ich hab es nun doch mit der Bibliothek versucht.
Wenn "nur" das Testprogramm auf dem Mega (Clon) ist, funktioniert es auch.
Es flackert zwar (zum Probieren ist eine gute alte 40W Glühlampe angeschlossen), aber es funktioniert.
Die Bibliothek frisst eine Menge Speicher, aber es reicht (hoffentlich), um meine Gäste morgen im Garten nicht im Dunkeln sitzen zu lassen.
Jetzt mal sehen, ob sich das in meinen Sketch einbauen läßt....