Hallo Zusammen,
ich habe den nachfolgenden Sketch für den Arduino Nano V3 programmiert.
Dabei dient das brücken gleichgerichtete und rechteckgewandelte 50Hz
Netzspgssignal als Taktsignal.
Während eines Zykluses (der im Beispiel unten aus 10 Rechteckperioden
besteht) bleibt das Ausgangssignal auf High bis die voreingestellte
Anzahl von Halbwellen gezählt wurde, dann schaltet der µC den GPO auf
Low.
Also quasi nichts anderes als eine PWM, die halt synchron zur
Netzfrequenz läuft.
Grundsätzlich funktioniert das auch. Das einzige Problem besteht darin,
daß der GPO frühestens nach zwei Taktzyklen auf Low geht, obwohl die
Vergleichszahl in OCR1B nur um 1 größer ist als die über TCNT1
definierte Startzahl des Zählers.
Ich hätte erwartet dass unter diesen Bedingungen der OCR1B Interrupt
nach einem Taktzyklus kommt, sprich der GPO nach einem Takt auf Low
wechselt.
Hat jemand eine Idee wieso das so ist und wie ich das korrigieren kann?
Vielen Dank und viele Grüße
Werner
1
#define osziPin 4 // Pin zum prüfen ob Wellenpaketsteuerung funzt
2
#define taktPin 5 // 100Hz Rechtecksignal Eingang
3
4
void setup()
5
{
6
pinMode(osziPin, OUTPUT); // Pin an dem das Signal für die Wellenpaketsteuerung (WPS) ansteht
7
pinMode(taktPin, INPUT); // 100Hz Rechtecksignal aus Netzspg. erzeugt liegt hier an
8
9
// Timer1:
10
noInterrupts(); // Alle Interrupts temporär abschalten
11
// Es folgen Einstellungen der Timer/Counter Control Register
12
TCCR1A = 0; // Keine weitere Programmierung von TCCR1A -> Alle bits =0, kein PWM, keine IR Ausgabe über IO Pins
13
TCCR1B = 0; // TCCR1B bestimmt die Taktquelle (int/ext.: Pin D5) und die Prescaler Einstellung
14
// Konfiguration über die drei Bits CS10..CS12=1. Bedeutet: 1. Kein prescaling, 2. ext. Taktquelle auf 3. steigende Flanke
15
TCCR1B |= (1 << CS10);
16
TCCR1B |= (1 << CS11);
17
TCCR1B |= (1 << CS12);
18
19
TIMSK1 |= (1 << OCIE1B); // Timer compare IR aktivieren
20
TIMSK1 |= (1 << TOIE1); // Overflow IR aktivieren
21
22
TCNT1 = 65526; // Register mit 65526 initialisieren, so dass 10 Zyklen bis Überlauf (65.536) verbleiben
23
OCR1B = 65527; // Output Compare Register B vorbelegen, so dass für Test 6 Zyklen bis Überlauf. Wert wird später dynamisch eingestellt.
24
digitalWrite(osziPin, HIGH); // Zu Beginn wird WPS Steuerungssignal high gesetzt.
25
interrupts(); // Alle Interrupts einschalten
26
}
27
// Interrupt Behandlungsroutine für den Timer Overflow
28
ISR(TIMER1_OVF_vect)
29
{
30
TCNT1 = 65526; // Register wieder auf Startwert setzen (10 unter overflow)
31
digitalWrite(osziPin, HIGH);
32
}
33
34
// Interrupt Behandlungsroutine für den OCR1B compare match Fall
> Hat jemand eine Idee wieso das so ist ...
"If TCNT equals OCR1x the comparator signals a match. A match will set
the Output Compare Flag (OCF1x) at the next timer clock cycle."
> ... und wie ich das korrigieren kann?
Indem Timer1 auf einen PWM-Modus gesetzt wird?
Hallo S. Landolt,
vielen Dank für den Hinweis, den habe ich offensichtlich überlesen.
Dann werde ich mir den PWM Mode mal näher anschauen. Ich bin bisher
davon ausgegangen dass eine PWM Zyklusdauer von 1s zu niedrig sein wird.
1s wäre nötig, um Sinuswellen im Nulldurchgang schalten und dabei eine
Auflösung von 2% realisieren zu können (Wellenpaket Steuerung).
Allerdings habe ich das noch nicht konkret im Datenblatt nachgelesen,
womöglich ist das kein Problem.
Grüße
Werner
> Zyklusdauer von 1s
Bei diesen langen Zeiten könnte man es auch komplett 'von Hand' machen,
also sogar ohne Timer (das war es vielleicht, was Dieter F. meinte),
einfach eine Variable im Interrupt hochzählen und entsprechend schalten.
Trotzdem würde ich einen PWM-Modus vorziehen (d.h. ganz ohne
Interrupt), z.B. 14 mit Top=ICR1; allerdings erreicht man dabei nicht so
ohne weiteres einen der Randwerte, es fehlt 0 % oder 100 % - kommt jetzt
auf die genauen Anforderungen an.
Danke S. Landolt.
Ich habe das Kapitel External Interrupts überflogen aber erst Dank
Deines Hinweises verstehe ich was Dieter F. gemeint haben könnte.
Manuell programmieren hatte ich zuallererst vor, als ich noch keinen
Arduino besaß und noch nicht ins Datenblatt geschaut habe. Jetzt ist mir
der ATmega mit seinen Countern dafür eigentlich zu schade.
Eben ist mir zudem klar geworden dass die kleine Unschönheit von zwei
Taktzyklen minimaler Einschaltdauer oberhalb vom Auszustand kein Problem
ist.
Wegen des brücken gleichgerichteten Sinussignals mit anschließender
Rechteckwandlung wird eine 50Hz Sinusschwingung ja von zwei 100Hz
Rechteckperioden repräsentiert. Somit kann ich trotzdem minimal eine
50Hz Periode schalten.
Ich möchte ein elektrisches Heizkabel steuern und dazu nur volle
Sinuswellen nutzen (Phasenan-/-abschnitt finde ich old School:-),
außerdem habe ich gelesen dass viele EVUn keine leistungsstarken
Phasenanschniitssteuerungen mehr erlauben).
Eine Änderung in 1% Schritten ist dafür vermutlich eh over the Top.
Vielen Dank für Eure hilfreichen Hinweise!
Viele Grüße
Werner
S. Landolt schrieb:> das war es vielleicht, was Dieter F. meinte
Nach dem externen Interrupt x (interne 16 oder so MHz Takte / Prescaler
z ) warten, bis y passiert.
Werner M. schrieb:> Eben ist mir zudem klar geworden dass die kleine Unschönheit von zwei> Taktzyklen minimaler Einschaltdauer oberhalb vom Auszustand kein Problem> ist.
Dein Fehler ist, das Du Dich auf den externen Takt (50 Hz ?) stützt um
damit/danach (als Counter) zu schalten - ergo bist Du viel zu langsam.
Du meinst, ich erwische den Nulldurchgang der Sinuswelle nicht mehr?
Das ist egal, dann erwische ich eben die nächste. Denselben Verzug gibt
es ja auch beim nächsten schalten, so dass die Schaltvorgänge konstant
versetzt sind.
Ich verwende ein Solid-State Relais mit Nullspannungsdetektor, das
schaltet ohnehin nur im Nulldurchgang.
> Solid-State Relais mit Nullspannungsdetektor
Also dann löst sich ja ohnehin alles in Wohlgefallen auf, dieser externe
Netztakt wird überflüssig, einfach den Timer1 mit einer PWM laufen
lassen.
Der Arduino Nano läuft mit 16 MHz, oder? Also Vorschlag: Timer1 im Modus
14, um auf die gewünschte Zeit von 1.0 s zu kommen, den Vorteiler auf
1024 und ICR1 auf 15625-1 setzen (ich selbst würde 4.0 s vorziehen,
folglich ICR1=62500-1). Den Tastgrad, wie gehabt, mit OCR1A oder B
einstellen, Ausgang ist dann OC1A oder B.