Hallo zusammen, das Thema Phasenanschnitt (50Hz Netzspannung) wurde schon etliche male behandelt. Eine passende Software dafür konnte ich jedoch leider nicht finden. Mein Problem: Ich habe einen Phasenanschnittsdimmer mit ATMega8 gebaut. An den OC1A-Pin ist ein TRIAC angeschlossen, über einen Jumper kann ich entweder am ICP-Pin oder am INT0-Pin ein Rechtecksignal einlesen, welches bei jedem Nulldurchgang seinen Zustand umkehrt. Nun meine Frage: Wie kann einen möglichst effizienten Code generieren, der mir den TRIAC nach einer eingestellten "Dimm-Verzögerung" (z.B. 8ms) einschaltet und kurze Zeit später, jedoch auf jeden Fall bei t < 10ms, wieder ausschaltet? Das Ganze eben möglichst ohne 3 Interrupts dafür zu benutzen o.ä.. Leider blicke ich bei den ganzen "Phase Corrected Frequency Corrected PWM Modes" etc. im Datenblatt nicht ganz durch bzw. sehe noch nicht, wie ich diese Funktionen geschickt einsetzen kann... Wäre für Tipps sehr dankbar! Schöne Grüße, Alex
Als Trigger muss man erst mal ein gefiltertes Netz verwenden. Ohne rabiaten Filter, der die Harmonischen rigoros wegmacht ist nichts. Dann einen Timer laufenlassen. Immer jeweils vom Trigger her. Und gleichzeitig die Periode pruefen, ist sie nicht relativ genau 20ms, dann macht man zur Sicherheit nichts. Einen durchgehenden Timer wuerd ich nicht verwenden, der laeuft dem Netz ueber eine gewisse Zeit davon und es knallt. Das Problem mit der Filterung ist, dass man das Netz selbst veraendert.
A...aha Soooo. schrieb: > Dann > einen Timer laufenlassen. Immer jeweils vom Trigger her. Genau, ich wollte auch bei jedem Wechsel des Trigger-Signals (es wechselt, wie gesagt, bei jedem Nulldurchgang) den Timer "resetten". >Und gleichzeitig die Periode pruefen, ist sie nicht relativ genau 20ms, dann >macht man zur Sicherheit nichts. Richtig, das hatte ich mir auch überlegt. Nun dennoch die Frage, wie man dazu geschickt die Timer-Funktionen des AVRs nutzen kann ohne alles in Software und mit Interrupts zu erledigen. Kann man nicht vieles davon in Hardware realisieren (mit den ganzen Timer-Spezialmodi)? Gruß, Alex P.S.: >und es knallt. Was denn und warum? Stimmt im schlimmsten Fall nicht einfach der "Dimm-Wert" nicht?
PWM ist hier nicht ganz angebracht. Es ist ja dein AC-Netz, das die Zeitvorgaben liefert, und nicht du, der du z.B. eine Grundfrequenz für PWM festlegst. Eine Überlegung: Was macht dein Prozessor denn noch? Nur Phasenanschnitt? Rechne dann doch einmal aus, wie sehr der sich langweilen wird zwischen den Nulldurchgängen. Ansonsten kann man sowas für zwei Kanäle prima mit den beiden Auffangregistern (Compare) eines Timers machen. ist zwar immer noch mit Spatzen auf Kanonen geschossen, macht aber nichts :-)
Was soll den geschnitten werden? Ohmsche oder Induktive Last?
Markus Müller schrieb: > Was soll den geschnitten werden? > Ohmsche oder Induktive Last? In erster Linie Ohm'sche Last. Ich glaubte jedoch (bis zu deiner Frage), dass induktives Dimmen genauso funktioniert... :-) >Was macht dein Prozessor denn noch? Es ist noch ein lokales User-Interface (1 LED, ein Drehencoder, ein Button) dran und eine ZigBee Schnittstelle (per UART) für "ein Bisschen" Kommunikation mit anderen Geräten. Ist aber nicht so "zeitkritisch". >Ansonsten kann man sowas für zwei Kanäle prima mit den beiden >Auffangregistern (Compare) Es ist nur 1 Kanal. Aber erläutere mir bitte mal genauer, wie du das meinst...
Nun, parametrier einen Timer in der Art, sodass er innerhalb einer Halbwelle gerade nicht überläuft. Er soll am Ende der Halbwelle den Wert X erreichen. Mit einem Auffangregister setzt du diesen Wert X TOP ein, das wäre dann einer von den CTC-Modi. Dadurch wird der Timer am Ende der Halbwelle wieder zurückgesetzt. Dann leg eine Tabelle mit Vergleichswerten an. '0' wäre volle Leistung, X wäre gar keine Leistung, dazwischen dann z.B. noch linearisieren. Legst du nun einen dieser Vergleichswerte in ein zweites Auffangregister (das erste sorgt ja bereits fürs Rücksetzen des Timers), so hast du deinen Zündzeitpunkt.
Hallo, Ich weiß ja nicht, was Du damit willst. Dein Timer wird doch eine Rahmenzeit von 10 ms == 180° haben, um jede Halbwelle anzuschneiden.Damit schaltet der Timer immer bei 10 ms ab. Der Trigger ist der Nulldurchgang der Netzspannung. Alex Bürgel schrieb: > "Phase Corrected Frequency Corrected PWM Modes" Phase corrected PWM würde bei einem Phasenwinkel von 0,2° bei 89,9° eine Signal auf High setzen und bei 90,1° wieder zurück auf Low. Also hättest Du als kleinsten Zündwinkel 90° == 50%. Ergo könntest Du auch nur von 50..100% dimmen. Das ist sicher nicht das gewünschte Verhalten.
Bei Induktiver Dimmung braucht man zwei Messungen: - Spannung / Nulldurchgang - Stromfluss durch den Verbraucher Beides über Optokoppler mit dem Oszi betrachtet gibt eine interessante Erkenntniss.
Alex Bürgel schrieb: > Nun meine Frage: Wie kann einen möglichst effizienten Code generieren, Ich habe für eine Thyristorgleichrichtung von meinem Labornetzteil das ganze in einen Timer-Interrupt gelegt, der alle 51us aufgerufen wird. (Ich hatte keine anderen Ressourcen im PIC16F876 mehr frei). Dort wird dann die Entprellung des Eingangssignals, messen der Periodendauer-Hälften und die Ausgabe an die Thyristoren durchgeführt. Die Berechnung der Anschnittwerte erfolgt separat im Hauptprogramm. Das ganze braucht etwa 13% der Rechenzeit, 46 Assembler-Befehle und erlaubt einen Phasenanschnitt mit knapp 0,5% Auflösung und Jitter. Gruß Anja
>Ich weiß ja nicht, was Du damit willst.
Es soll ein Dimmer für Glühlampen und 230V-Halogenlampen bis 500W sein
(wobei mir zunächst 60W reichen). Ferner dachte ich eigentlich auch
Niedervolthalogenlampen mit Ringkerntrafo damit dimmen zu können.
Bevor mir hier irgendetwas explodiert: Was sollte ich denn beim Dimmen
eines Ringkerntrafos erwarten? Meiner Erwartung nach steigt der Strom
beim Einschalten irgendwann innerhalb einer Halbwelle halt "langsam" an,
die Spannung ist natürlich sofort die aktuelle Sinusspannung.
Ausschalten tut sich der TRIAC doch von alleine wenn U ~ 0V und I ~ 0A
ist. Es gibt im übrigen auch einen Snubber mit 100nF/33Ohm über dem
TRIAC.
Das mit dem CTC kann ich mir noch nicht so recht vorstellen, muss mir
das nochmal anhand des Datenblatts durch den Kopf gehen lassen...
Gruß,
Alex
>das ganze in einen Timer-Interrupt gelegt, der alle 51us aufgerufen wird.
Ja klar, so kann man es machen... ich hatte nur gehofft anstatt alle
xxµs einen Interrupt zu generieren einfach diverse Hardware-Funktionen
nutzen zu können. So verfügt der "Input-Capture" ja z.B. über einen
"Noise Canceller" und der Output Compare hat 12 Betriebsmodi (oder so).
Da sollte es doch eine Kombination geben, mit der man so was
alltägliches mit nur 1 Interrupt lösen kann und dennoch
Störungsresistent etc. ist...
Hallo Alex, ich hatte im Sommer mal angefangen, einen Dimmer in Bascom zu schreiben, der etwa so läuft, wie Du es Dir vorstellst. Gedacht ist das Ding für Glühlampenlast bis 3 kW und Einknopfbedienung (Taster). Ist alles noch ziemlich provisorisch, geht aber im wesentlichen schon. Es läuft alles automatisch im Timer1 eines Attiny:
1 | '******************************************************************************* |
2 | ' Dimmer for ohmic loads with Attiny24 for one button operation |
3 | '******************************************************************************* |
4 | ' |
5 | ' Ralph Fischer 2010 |
6 | |
7 | |
8 | $regfile = "ATtiny24.dat" |
9 | $crystal = 1000000 '8 MHz with divider enabled |
10 | '$baud = 38400 |
11 | |
12 | $hwstack = 32 |
13 | $swstack = 32 |
14 | $framesize = 24 |
15 | |
16 | |
17 | Config Porta.0 = Output |
18 | Triac Alias Porta.0 |
19 | |
20 | Config Pina.1 = Input |
21 | Porta.1 = 1 |
22 | Key Alias Pina.1 |
23 | |
24 | Config Porta.2 = Output 'just for debugging |
25 | Led Alias Porta.2 |
26 | |
27 | |
28 | Config Int0 = Falling |
29 | On Int0 Int0_isr |
30 | Enable Int0 |
31 | |
32 | Dim Key As Bit |
33 | Dim Onoff_flag As Bit |
34 | Dim Dim_flag As Bit |
35 | Dim Dim_direction As Bit '1 = incr. brightness, 0 = decr. brightness |
36 | Dim Key_count_flag As Bit |
37 | Dim Count_0 As Byte 'for timing of the key |
38 | Dim Bright_min As Word |
39 | Dim Bright_max As Word |
40 | |
41 | |
42 | Declare Sub Key_count |
43 | Declare Sub Dimm |
44 | Declare Sub On_off |
45 | |
46 | |
47 | |
48 | Ocr1b = 7000 'start triac at x [µs] after zero cross; 0 = full power, 10,000 = off |
49 | Ocr1a = Ocr1b + 50 'end of triac start pulse |
50 | Config Timer1 = Timer , Prescale = 1 , Compare A = Disconnect , Compare B = Disconnect , Clear Timer = 1 |
51 | |
52 | On Oc1b Set_triac |
53 | On Oc1a Reset_triac |
54 | Enable Oc1b |
55 | Enable Oc1a |
56 | |
57 | Enable Pcint0 |
58 | On Pcint0 Isr_pcint0 |
59 | Pcmsk0 = &B00000010 'PA.0 is key interrupt |
60 | |
61 | Config Timer0 = Timer , Prescale = 1024 |
62 | On Timer0 Timer0_isr |
63 | Enable Timer0 |
64 | |
65 | |
66 | Enable Interrupts |
67 | |
68 | Bright_min = 7000 'note: this is the value for _minimum_ brighness |
69 | Bright_max = 2000 'note: this is the value for _maximum_ brighness |
70 | ' (values are the time gap between zero crossing and triac ignition) |
71 | |
72 | |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | '****Main**** |
79 | Do |
80 | |
81 | Led = onoff_flag |
82 | If Dim_flag = 1 Then |
83 | Gosub Dimm |
84 | End If |
85 | |
86 | If Key_count_flag = 1 Then |
87 | Gosub Key_count |
88 | End If |
89 | |
90 | Loop |
91 | '****/Main**** |
92 | |
93 | End |
94 | |
95 | Isr_pcint0: |
96 | Waitms 20 |
97 | If Key = 0 Then Set Key_count_flag |
98 | Return |
99 | |
100 | Int0_isr: |
101 | Timer1 = 0 |
102 | Start Timer1 |
103 | Return |
104 | |
105 | Timer0_isr: |
106 | 'Toggle Led |
107 | Incr Count_0 |
108 | Return |
109 | |
110 | Set_triac: |
111 | Set Triac |
112 | Return |
113 | |
114 | Reset_triac: |
115 | Reset Triac |
116 | Stop Timer1 |
117 | Return |
118 | |
119 | Sub On_off: |
120 | 'Reset Triac |
121 | Toggle onoff_flag |
122 | If onoff_flag = 1 Then |
123 | Enable Int0 |
124 | Else |
125 | Disable Int0 |
126 | Gosub Reset_triac |
127 | End If |
128 | End Sub |
129 | |
130 | Sub Key_count: |
131 | Reset Key_count_flag |
132 | Count_0 = 0 |
133 | While Key = 0 |
134 | 'Incr Count_0 |
135 | If Count_0 > 8 Then |
136 | Set Dim_flag |
137 | Count_0 = 0 |
138 | Exit Sub |
139 | End If |
140 | Wend |
141 | If Count_0 < 5 Then Gosub On_off |
142 | End Sub |
143 | |
144 | Sub Dimm: |
145 | Reset Dim_flag |
146 | Count_0 = 0 |
147 | Toggle Dim_direction |
148 | While Key = 0 |
149 | If Dim_direction = 0 Then |
150 | Incr Ocr1b |
151 | If Ocr1b > Bright_min Then |
152 | Ocr1b = Bright_min |
153 | End If |
154 | Elseif Dim_direction = 1 Then |
155 | Decr Ocr1b |
156 | If Ocr1b < Bright_max Then |
157 | Ocr1b = Bright_max |
158 | End If |
159 | End If |
160 | Ocr1a = Ocr1b + 50 |
161 | Waitms 1 |
162 | Wend |
163 | End Sub |
Vielleicht nutzt es. Ralph
A...aha Soooo. schrieb: > Als Trigger muss man erst mal ein gefiltertes Netz verwenden. Ohne > rabiaten Filter, der die Harmonischen rigoros wegmacht ist nichts. Hmm, komisch, mein 12-Kanal Dimmer funktioniert seit Jahren ausgezeichnet, auch ohne rabiaten Netzfilter. Die Kunst ist die Erkennung aller Nulldurchgänge, und zwar möglichst nahe an der Nullinie. Das habe ich mit einem Optokoppler mit Wechselspannungseingang gelöst. Dann gibt man dem Timer noch ein bisserl Reserve, so dass maximal 95% Leistung eingestellt werden können und dann ist alles super. Der Controller muss die Nulldurchgänge natürlich sauber erkennen, weshalb man hinter dem Optokoppler am besten einen Analog-Komparator-Eingang anstelle eines normalen Portpins nimmt. Diesen stellt man dann so ein, dass die Nullinie im Sinus einen schmalen Puls im Controller auslöst. Da der Analog-Komparator einen Interrupt auslösen kann, kann man die CPU zusätzlich entlasten. Als Leistungsstufe habe ich SSRs mit Snubbern hergenommen. Es hat sich herausgestellt, dass es sinnvoll ist, die SSRs den gesamten Leuchtzyklus nach dem Zünden eingeschaltet zu lassen, da es bei langen Lampenleitungen und zu kurzen Zündpulsen zu Flackern in kleinen Dimmstufen gekommen ist.
Hey Knut ! Vielen Dank für Deinen hilfreichen Tipp mit dem Analog-Comparator ! ( Ich quäle mich schon lange und das Gute lag so nah ;-)) Kannst Du mir bitte verraten, welches SSR Du benutzt ? Danke + Gruß Olaf
Ach so, vergessen zu schreiben, wie ich es mache: Ich nehme den Timer0 und teile ihn durch 1024. Bei 16 MHz habe ich dann nach 10 ms einen Zählerstand von 157. Das Capture Register muss dann also auf 157 minus irgendetwas gesetzt werden. In der Capture-Interrupt-Funktion dann EINSCHALTEN und in der AnalogCompare/INTx Interrupt-Funktion dann AUSSCHALTEN (benutze MOSFET´s) Just my 2 cents Olaf
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.