Forum: Mikrocontroller und Digitale Elektronik Verzögerung Zündung TRIAC für Phasenanschnitt


von Markus P. (sebastianwurst)


Angehängte Dateien:

Lesenswert?

Hallo liebe Gemeinde.
Bei meinen Phasenanschnitt habe ich das Problem das wie im Bild 1. zu 
sehen, der angeschnittene Bereich schwankt und dadurch auch ein 
optisches Flackern der Lampe verursacht wird.
(PS.: Der Bereich ist kleiner als der Markierte, genau kann ich das 
nicht sagen, Oszi zu alt...)
Den Anschnitt mache ich über die Platine in Bild 2. Also kurz gesagt 
über Schieberegister (74HC595)und Triacs etc.
Der Nulldurchgang, der auch im Bild 1 zu sehen ist, steht wie eine Eins.
Ich "Nulle" den Timer (s.main.c) immer beim Nulldurchgang und starte 
dann den Timer neu, zünde den Triac wenn ein gwünschter Wert erreicht 
ist.
Diese Wertabfrage mache ich im Interrupt alle 0,016ms.
Nach meiner Auffassung kann im schlechtesten Fall nur eine Verzögerung 
von 0,016ms entstehen, das würde man aber mit Sicherheit nicht als 
flackern wahrnemen, denke ich.
Hat vielleicht noch einer ein Tip für mich was ich mal ausprobieren kann 
um der Sache auf die Spur zu kommen?

(Ich habe hier Beitrag "Dimmer flackert trotz Timer Interrupt" auch 
schon mal was geschrieben,da war aber das Problem das komplette Wellen 
nicht geschaltet wurden, das konnte ich bisher beheben. Jetzt geht es 
wirklich nur um den "kleinen" Versatz beim Starten der Zündung/Triacs)

von Falk B. (falk)


Lesenswert?

@  Markus P. (sebastianwurst)

>      1.JPG
>      1,6 MB, 6 Downloads

Bitte mal über Bildformate informieren.

>Diese Wertabfrage mache ich im Interrupt alle 0,016ms.

Wo?
Ich sehe nur einen INT0-Interrupt für den Nulldurchgang, einen 
TIMER0_COMPA für das verzögerte zünden und einen USART_RX für den 
Datenempfang per UART. Dort wird auch dein Jitter herkommen, denn 
während der USART_RX abgearbeitet wird, muss der TIMER0_COMPA warten. 
Schalt mal den UART testweise aus.

Ausserdem ist deine main Hauptschleife RIESIG, da sieht keine Sau durch. 
Pack das in Funktionen, damit man maximal 1-2 Bildschirmseiten für die 
Hauptscheife braucht. Ausserdem habe ich das unbestimmte Gefühl, dass da 
noch nicht alles rund läuft mit den Dutzenden Aufgaben.

MFG
Falk

von Markus P. (sebastianwurst)


Lesenswert?

Du hast Recht, ich muss mal aufräumen da ich 80% auch garnicht mehr 
gebrauche, ich weiss nur noch nicht ob es für ewig so bleiben wird 
deswegen hab ich die noch drin gelassen....

Durch diese Initialisierung des Timers 0:
1
TCCR0B |= (1<<CS00) | (1<<WGM02);     // CTC uns Prescaler 1 (16.000.000/256)= 0,016ms Interrupt auslösen) 
2
    
3
TCNT0   = 0;                          // Timer Startwert
4
OCR0A   = 255;                        // Load register   
5
TIMSK0 |= (1<<OCIE0A);                // Interrupt nach Overflow
Das sind dann 0,016ms

und hier wird die Aufgerufen:
Dort wird dann alle 0,16ms der TriacZuenden()aufgerufen und wenn der 
TCNT1 die Vorgaben überschritten hat der Triac gezuendet...
1
//==================================================================
2
// Timer 0 Dimmwertvergleich
3
//==================================================================
4
ISR (TIMER0_COMPA_vect)
5
{
6
7
  TriacZuenden(15000,16);
8
  TriacZuenden(15000,18);
9
10
11
// Timer zurücksetzen  
12
if (TCNT1 >= 19000 )
13
  {  
14
  
15
16
  
17
  AusgangUnsetBit(16);
18
  AusgangOut();
19
  
20
  AusgangUnsetBit(17);
21
  AusgangOut();
22
  
23
  AusgangUnsetBit(18);
24
  AusgangOut();
25
  
26
  
27
  
28
  TCNT1   = 0;
29
  TCCR1B  = 0b00000000;   // Timer stoppen
30
  }  
31
}


Wenn ich aber nichts über USART sende/empfange dann brauch die USART_RX 
auch nichts machen oder?

von MaWin (Gast)


Lesenswert?

Deine ISR (TIMER0_COMPA_vect) braucht wegen dem 
AusgangSetBit/UnsetBit/AusgangOut Verhau immer länger als 16us.


Das braucht sie so zwar immer noch, aber nur gelegentlich:

volatile int tick,dimm17=15000,dimm18=10000,dimm19=15000;

ISR(TIMER0_COMPA_vect)
{
   unsigned char changed=0;

   tick++;
   if(tick==dimm17) { AusgangSetPit(17); changed=1; }
   if(tick==dimm18) { AusgangSetPit(18); changed=1; }
   if(tick==dimm19) { AusgangSetPit(19); changed=1; }
   if(changed) AusgangOut();
}

ISR(INT0_vect)
{
   tick=0;
   AusgangUnsetBit(17);
   AusgangUnsetBit(18);
   AusgangUnsetBit(19);
   AusgangOut();
}

Man muß übrigens sicher stellen, daß nur die eine oder andere 
Interrupt-Funktion ausgeführt werden kann, keine geschachtelten 
Interrupts sonst wird eventuell mitten im rücksetzen noch gesetzt oder 
umgekehrt. Glücklicherweise ist das default-mässig der Fall.

von Falk B. (falk)


Lesenswert?

@  Markus P. (sebastianwurst)

>Durch diese Initialisierung des Timers 0:

>TCCR0B |= (1<<CS00) | (1<<WGM02);     // CTC uns Prescaler 1 >(16.000.000/256)= 
0,016ms Interrupt auslösen)

>TCNT0   = 0;                          // Timer Startwert
>OCR0A   = 255;                        // Load register
>TIMSK0 |= (1<<OCIE0A);                // Interrupt nach Overflow

Der Kommentar ist irreführend, weil falsch. Es ist der CTC Modus, da 
gibt es keinen Überlauf, sondern einen Compare Match. So heißt auch die 
ISR.

>Das sind dann 0,016ms

Oder wie der Fachmann sagt, 16us. Nicht viel, mach gerade mal 256 Takt 
bei 16MHz. Mit wieviel läift dein AVR?

>Dort wird dann alle 0,16ms der TriacZuenden()aufgerufen und wenn der
>TCNT1 die Vorgaben überschritten hat der Triac gezuendet...

Sportlich, in einem 16us Interrupt noch Funktionen aufrufen, die sind 
bekanntermassen beim AVR nicht so schnell an der Stelle (Stichwort 
Register sichern etc.). WENN, dann macht man das direkt in der ISR, ohne 
Funktionsaufruf. Aber wozu braucht man für eine Phasenanschnittsteuerung 
einen 16us Timer? Es reicht doch, per Output Compare nach dem 
Nulldurchgang ein IO-Pin zu setzen. Das macht der Timer allein ohne 
jegliche CPU-Last. Und jitterfrei ;-)
Wenn man nun noch so clever ist, und statt INT0 die Input Capture 
Funktion nutzt, clever combimiert mit der Output Compare Funktion, kann 
man nahezu beliebige Interrupts parallel nutzen, ohne den geringsten 
Jitter.

>Wenn ich aber nichts über USART sende/empfange dann brauch die USART_RX
>auch nichts machen oder?

Ja.

MFG
Falk

von Markus P. (sebastianwurst)


Lesenswert?

> Oder wie der Fachmann sagt, 16us. Nicht viel, mach gerade mal 256 Takt
> bei 16MHz. Mit wieviel läift dein AVR?

16Mhz


>Es reicht doch, per Output Compare nach dem
> Nulldurchgang ein IO-Pin zu setzen.

Aber ich habe ja mehrere Phasenanschnitt, daher das Schieberegister.

> Sportlich, in einem 16us Interrupt noch Funktionen aufrufen, die sind
> bekanntermassen beim AVR nicht so schnell an der Stelle (Stichwort
> Register sichern etc.).
Ich wollte das auch erst nicht mit Funktionsaufrufe in der ISR machen, 
wollte eigentlich nur ein Flag setzen und diesen dan in der main 
abfragen, aber das klappt auch nicht besonders gut (Flackern).

> Wenn man nun noch so clever ist, und statt INT0 die Input Capture
> Funktion nutzt, clever combimiert mit der Output Compare Funktion, kann
> man nahezu beliebige Interrupts parallel nutzen, ohne den geringsten
> Jitter.

Da bin ich zu doof für, glaub ich ;-( Aber ich versuche mein Bestes. 
Werde durch Eure Tips nochmal einbissel ausprobieren. Danke schonmaml. 
Bitte schaut nochmal rein....

von Falk B. (falk)


Lesenswert?

@  Markus P. (sebastianwurst)

>Aber ich habe ja mehrere Phasenanschnitt, daher das Schieberegister.

Wieviele? Timer 1 hat zwei Output COmpares Register, kann man schon mal 
zwei erledigen. Es gibt AVRs mit vier und mehr Output Compares, kann man 
nutzen. Reicht das nicht, muss man es so wie du in Software machen, ist 
dann eine Art synchroner Soft-PWM.

>Ich wollte das auch erst nicht mit Funktionsaufrufe in der ISR machen,
>wollte eigentlich nur ein Flag setzen und diesen dan in der main
>abfragen,

Keine gute Idee, da ist das Timing noch mieser.

> aber das klappt auch nicht besonders gut (Flackern).

Logisch.

MFg
Falk

von Markus P. (sebastianwurst)


Lesenswert?

Falk Brunner schrieb:
> Wieviele? Timer 1 hat zwei Output COmpares Register, kann man schon mal
> zwei erledigen. Es gibt AVRs mit vier und mehr Output Compares, kann man
> nutzen. Reicht das nicht, muss man es so wie du in Software machen, ist
> dann eine Art synchroner Soft-PWM.

Bis zu zehn sind das Ziel...

>Keine gute Idee, da ist das Timing noch mieser.

Das dachte ich mir dann auch...

von oszi40 (Gast)


Lesenswert?

Evtl. mal eine Gegenprobe mit Rechteckimpulsgenerator machen ob die 
gelieferten Impulse überhaupt AUSREICHEN um den Triac anzusteuern?

von Markus P. (sebastianwurst)


Lesenswert?

oszi40 schrieb:
> Evtl. mal eine Gegenprobe mit Rechteckimpulsgenerator machen ob die
> gelieferten Impulse überhaupt AUSREICHEN um den Triac anzusteuern?

Ich habe auch direkt am Ausgang vom Schieberegister gemessen (74HC595) 
das spiegelt den sinusverlauf der angeschnittenen Wechselspannung 
komplett wieder.

von Markus P. (sebastianwurst)


Lesenswert?

Vielleicht stelle ich mich auch viel zu sehr an.
Ich habe keinen Vergleichsdimmer bei mir im Hause, nur einen Dimmer der 
über Kondensatoren/Schieberegler den Phasenanschnitt macht. Da gibts 
kein flackern.

Das flackern ist auch so klein, denke mir nur das eine so flackernde 
Leselampe zu Kopfschmerzen führen würde.

von Markus P. (sebastianwurst)


Angehängte Dateien:

Lesenswert?

Kann dieser INT2 auch was damit zu tun haben, ich benutz das AVR Net IO 
Board da ist die NEtzwerkkarte auch drauf. Die brauch den Interrupt.

Welcher Interrupt gewinnt?
1
#define enc_select()            ENC_PORT &= ~(1<<ENC_CS)
2
  #define enc_deselect()          ENC_PORT |= (1<<ENC_CS)
3
4
  #define ETH_INTERRUPT           INT2_vect
5
  #define ETH_INT_ACTIVE          (!(ENC_PIN & (1<<ENC_INT)))
6
7
  #define ETH_INT_ENABLE  EIMSK |= (1<<INT2)
8
  #define ETH_INT_DISABLE EIMSK &= ~(1<<INT2)

von Who knows (Gast)


Lesenswert?

Auf der Platine kann man TIC206M lesen, zwei Lötpunkte für diesen Triac. 
Was ist mit dem mittleren Pin des Triacs?

Das bitte mal erklären.

von MaWin (Gast)


Lesenswert?

Der ist etwas nach vorne (oben) rausgebogen, damit die Abstände der 
Lötpunkt grösser werden.

von Markus P. (sebastianwurst)


Lesenswert?

> Wieviele? Timer 1 hat zwei Output COmpares Register, kann man schon mal
> zwei erledigen. Es gibt AVRs mit vier und mehr Output Compares, kann man
> nutzen. Reicht das nicht, muss man es so wie du in Software machen, ist
> dann eine Art synchroner Soft-PWM.

ich habe jetzt mal nur einen Ausgang getogglet und der sieht komplett 
identisch zu den Ausgängen der Schieberegister aus. Ich habe fast jeden 
weitern Code in der Main auskommentiert und trozdem wackelt der Ausgang. 
So wie im Bild vom ersten Eintrag... Auch ohne Schieberegister wackelt 
der (PD3)

Der Nulldurchgang steht auf die 1000/Sekunde, laut Oszi.

Müsste der getogglet Ausgang auch so stehen? Was ist denn Normal für so 
einen Atmega 644p mit 16Mhz Taktung?

Hier ist nochmal der Code der Interrupts:
1
/////////////////////////////////////////////////
2
/////////////////////////////////////////////////
3
//Interrupt 0 steigende Flanke Nulldurchgang 
4
///////////////////////////////////////////////// 
5
 
6
  EIMSK  |= (1<<INT0);                 // External Interrupt 0 Enable PIN PD2  
7
  EICRA  |= (1<<ISC00) | (1<<ISC01);   // Int auslösen bei steigender Flanke
8
9
  
10
////////////////////////////////////////////////
11
// Timer 1 Dimmwert für Triac Ansteuerung erhöhen (16-bit) 
12
/////////////////////////////////////////////////
13
14
15
    TCCR1A  = (1<<WGM12);                   // CTC Modus
16
    TCCR1B |= (1<<CS11);             // Prescaler 8 = (16.000.000/20000/8)= 10,00ms würde Interrupt ausgelöst) 
17
  TCNT1   = 0;              //
18
    OCR1A   = 20000;                        // Load register                                    
19
//  TIMSK1 |= (1<<OCIE1A);                // Interrupt nach Overflow
20
    
21
 ////////////////////////////////////////////////////
22
 // Timer 0 Timer für den Dimmwertvergleich (8-bit)
23
 ////////////////////////////////////////////////////
24
 
25
    TCCR0B |= (1<<CS00) | (1<<WGM02);     // CTC uns Prescaler 1 (16.000.000/256)= 0,016ms Interrupt auslösen) 
26
   // TCCR0B |= (1<<CS00) | (1<<CS01) | (1<<WGM02);     // CTC uns Prescaler 64 (16.000.000/256/64)= 1,024ms Interrupt auslösen) 
27
   // TCCR0B |= (1<<CS01) | (1<<WGM02);     // CTC uns Prescaler 8 (16.000.000/256/8)= 0,128ms Interrupt auslösen) 
28
  
29
  TCNT0   = 0;                          // Timer Startwert
30
    OCR0A   = 255;                        // Load register   0,064   
31
    TIMSK0 |= (1<<OCIE0A);                // Interrupt nach Overflow  
32
33
  //Globale Interrupts einschalten
34
  sei(); 
35
  /*
1
//==================================================================================
2
// Timer 0 Dimmwertvergleich
3
//==================================================================================
4
ISR (TIMER0_COMPA_vect)
5
{
6
7
//Triac setzen
8
9
if (u16Dimmwert[0] < 16000)
10
  {
11
  if (TCNT1 >= u16Dimmwert[0])
12
  {
13
  PORTD |= (1<<PD3); 
14
   AusgangSetBit(0);
15
   AusgangOut();
16
   }
17
  }
18
19
/*
20
if (u16Dimmwert[1] < 16000)
21
  {if (TCNT1 >= u16Dimmwert[1]){AusgangSetBit(1);AusgangOut();}}
22
23
if (u16Dimmwert[2] < 16000)
24
  {if (TCNT1 >= u16Dimmwert[2]){AusgangSetBit(2);AusgangOut();}}
25
26
if (u16Dimmwert[3] < 16000)
27
  {if (TCNT1 >= u16Dimmwert[3]){AusgangSetBit(3);AusgangOut();}}
28
*/
29
/*
30
  if ((u16Dimmwert[0] < 16000) && ausgaenge_status[4])
31
  {if (TCNT1 >= u16Dimmwert[0]){AusgangSetBit(PosDerLetzenRAS*8);AusgangOut();}}
32
  
33
34
if (u16Dimmwert[1] < 16000)
35
  {if (TCNT1 >= u16Dimmwert[1]){AusgangSetBit(PosDerLetzenRAS*8+1);AusgangOut();}}
36
37
if (u16Dimmwert[2] < 16000)
38
  {if (TCNT1 >= u16Dimmwert[2]){AusgangSetBit(PosDerLetzenRAS*8+2);AusgangOut();}}
39
40
if (u16Dimmwert[3] < 16000)
41
  {if (TCNT1 >= u16Dimmwert[3]){AusgangSetBit(PosDerLetzenRAS*8+3);AusgangOut();}}
42
  */
43
  
44
  
45
46
// Timer / Triac zurücksetzen  
47
if (TCNT1 >= 17000 )
48
  {    
49
    volatile bool b_SetAusgangOut = false;
50
  
51
  if (u16Dimmwert[0] < 16000)
52
    {
53
    PORTD &= ~(1<<PD3);
54
    AusgangUnsetBit(0);
55
    b_SetAusgangOut = true;
56
    }  
57
58
  
59
  
60
  //if (u16Dimmwert[1] < 16000){AusgangUnsetBit(1);b_SetAusgangOut = true;}
61
  //if (u16Dimmwert[2] < 16000){AusgangUnsetBit(2);b_SetAusgangOut = true;}  
62
  //if (u16Dimmwert[3] < 16000){AusgangUnsetBit(3);b_SetAusgangOut = true;}
63
  //if (b_SetAusgangOut) {AusgangOut();b_SetAusgangOut=false;}
64
  
65
  /*if (u16Dimmwert[0] < 16000){ PORTD &= ~(1<<PD3);AusgangUnsetBit(PosDerLetzenRAS*8);b_SetAusgangOut = true;}  
66
  if (u16Dimmwert[1] < 16000){AusgangUnsetBit(PosDerLetzenRAS*8+1);b_SetAusgangOut = true;}
67
  if (u16Dimmwert[2] < 16000){AusgangUnsetBit(PosDerLetzenRAS*8+2);b_SetAusgangOut = true;}  
68
  if (u16Dimmwert[3] < 16000){AusgangUnsetBit(PosDerLetzenRAS*8+3);b_SetAusgangOut = true;}
69
  */
70
  
71
  if (b_SetAusgangOut) {AusgangOut();b_SetAusgangOut=false;}
72
  
73
  TCNT1   = 0;
74
  TCCR1B  = 0b00000000;   // Timer stoppen
75
  }  
76
77
}
78
//==================================================================================
79
//Interrupt 0 Nulldurchgangerkennung steigende Flanke
80
//==================================================================================
81
ISR(INT0_vect)
82
{    
83
    
84
    Nulldurchgang = true;
85
  
86
    // gestoppten Timer mit  Prescaler 8 wieder starten
87
    TCCR1B |= (1<<CS11);   // Prescaler 8
88
  TCNT1   = 0;  
89
}

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
Noch kein Account? Hier anmelden.