Forum: Mikrocontroller und Digitale Elektronik Dimmer flackert trotz Timer Interrupt


von Markus P. (sebastianwurst)


Lesenswert?

Hallo,
ich habe einen Dimmer/Phasenanschnitt mit Hilfe der bekannten 
Triacansteuerung realisiert. Jetzt merke ich das ich trotz 
Timerintterrupt, in der ich den Triac/Ausgang lösche, undefeniert, immer 
wenn der yC gerade etwas arbeiten muss, (UART, Schleifenaufruf...) ein 
Flackern der Lampe wahrnehme. Laut Oszi löscht er im Nulldurchgang den 
Ausgang nicht und hat somit nach dem Nulldurchang die komplette 
Halbwelle.
Ich benutze diese Interrupt/Timer Initialisierungen:
1
/////////////////////////////////////////////////
2
//Interrupt steigende Flanke Nulldurchgang konfigurieren
3
///////////////////////////////////////////////// 
4
 
5
  EIMSK  |= (1<<INT0);                 // External Interrupt 0 Enable PIN PD2  
6
  EICRA  |= (1<<ISC00) | (1<<ISC01);   // Int auslösen bei steigender Flanke
7
 
8
   
9
/////////////////////////////////////////////////
10
// Timer 0 Dimmwert für Triac Ansteuerung erhöhen (8-bit) konfigurieren
11
/////////////////////////////////////////////////
12
13
14
    TCCR0A  = (1<<WGM01);                 // CTC Modus
15
    TCCR0B |= (1<<CS00) | (1<<CS02);      // Prescaler 1024
16
  TCNT0   = 0;
17
18
  
19
 ////////////////////////////////////////////////////
20
 // Timer 1 Timer für den Dimmwertvergleich (16-bit)
21
 ////////////////////////////////////////////////////
22
 
23
    TCCR1B |= (1<<CS10) | (1<<WGM12);     // CTC uns Prescaler 1 (16.000.000/256)= 0,016ms TimerInterrupt auslösen) 
24
  TCNT1   = 0;                          // Timer Startwert
25
    OCR1A   = 256;                        // Load register      
26
    TIMSK1 |= (1<<OCIE1A);                // Interrupt nach Overflow

und hier sind die Timer / Interrupts:
1
//==================================================================================
2
// Timer 1 Dimmwertvergleich
3
//==================================================================================
4
ISR (TIMER1_COMPA_vect)
5
{
6
      
7
TriacZuenden(50,16); // Das Bit 16 welches den Triac ansteuert wird nach erreichen von TCNT0 >= 50 gesetzt.
8
9
// Timer zurücksetzen  
10
if (TCNT0 >= 135) 
11
  {
12
13
  TCNT0   = 0;
14
  TCCR0B  = 0b00000000;   // Timer stoppen
15
  }    
16
}
17
//==================================================================================
18
//Interrupt 0 Nulldurchgangerkennung steigende Flanke
19
// Im Nulldurchang wird der "TriacAusgang" gelöscht und der Timer wieder gestartet
20
//==================================================================================
21
22
ISR(INT0_vect)
23
{    
24
//  TRIAC Zündung löschen
25
AusgangUnsetBit(16);
26
AusgangOut();  
27
  
28
  
29
30
  
31
    // gestoppten Timer mit  Prescaler 1024 wieder starten
32
    TCCR0B |= (1<<CS00) | (1<<CS02);   // Prescaler 1024
33
  TCNT0   = 0;  
34
35
  
36
}
Hat evtl. jemand ein Tip warum da was schief geht?
Danke.

von Marvin M. (Gast)


Lesenswert?

Hallo,

nutzen die Routinen, die die Störungen verursachen, ebenfalls einen 
Interrupt oder sperren ihn?

von Markus P. (sebastianwurst)


Lesenswert?

Marvin M. schrieb:
> Hallo,
>
> nutzen die Routinen, die die Störungen verursachen, ebenfalls einen
> Interrupt oder sperren ihn?

Hi, dieses "oder sperren ihn?" verstehe ich vom Sinn nicht...
Die Routinen die die Störungen verursachen haben keine Interrupts mehr,
diese Routine z.B hat "nur" Schleifen und Stört:
1
void Eingaenge_abfragen (void)
2
{
3
    PORTC |= (1<<PC4);
4
5
    // Mit PL alle Eingänge in das Register schieben.
6
7
    // PL auf High
8
    PORTC |= (1<<PC5);
9
    // PL auf Low
10
    PORTC &= ~(1<<PC5);
11
    // PL auf High
12
    PORTC |= (1<<PC5);
13
14
      
15
      //Abfragen welches Registerbit gesetzt -> mit clock weiter schieben
16
    for(m=(Eingangskarten * 16)-1;m>=0;m--)
17
    {
18
          
19
      if (PINA & (1<<PINA0)) 
20
      { // Logisch 1 wenn Schalter nicht gedrückt da Pullup an
21
      Eingang[m] = false;     
22
      
23
            if      (m<= 8) StatusEingangByte1 &= ~(1 << m);
24
      else if (m<=16) StatusEingangByte2 &= ~(1 << m);
25
      else if (m<=24) StatusEingangByte3 &= ~(1 << m);
26
      else if (m<=32) StatusEingangByte4 &= ~(1 << m);
27
28
      } 
29
      else 
30
      {
31
      Eingang[m] = true;  
32
      
33
      if      (m<= 8)  StatusEingangByte1 |= ( 1 << m );
34
      else if (m<= 16) StatusEingangByte2 |= ( 1 << m );
35
      else if (m<= 24) StatusEingangByte3 |= ( 1 << m );
36
      else if (m<= 32) StatusEingangByte4 |= ( 1 << m );      
37
      }        
38
          
39
      // Mit Clock weiterschieben
40
41
      // Clock auf High
42
      PORTC |= (1<<PC4);
43
      // Clock auf Low
44
      PORTC &= ~(1<<PC4);
45
      // Clock auf High
46
      PORTC |= (1<<PC4);    
47
    }      
48
}

von Karl H. (kbuchegg)


Lesenswert?

Markus P. schrieb:

> Hi, dieses "oder sperren ihn?" verstehe ich vom Sinn nicht...

Gibt es in deinem Programm irgendwo sei()/cli() Aufrufe?

von Markus P. (sebastianwurst)


Lesenswert?

Wenn ich in der Timer Interrupt einen Ausgang toggle passt das auch, 
also er wird alle 0,016ms aufgerufen

Der Ausgang togglet im Sekundentakt:
1
ISR (TIMER1_COMPA_vect)
2
{
3
longCount++;
4
5
if (longCount>=62500 && !memm)        
6
{
7
     PORTC |= (1<<PC6);  
8
         longCount= 0;
9
         memm = true;
10
}
11
else if (longCount>=62500 && memm)      
12
{        
13
         PORTC &= ~(1<<PC6);
14
         longCount= 0;
15
         memm = false;
16
}
17
  
18
}

von Knut (Gast)


Lesenswert?

Ich hab mir deinen Code jetzt nicht genau angeguckt, aber du musst den 
Triac doch nur einmal "zünden", dann bleibt er doch "an". Also kurzen 
Puls aufs Gate und dann is gut. Damit ist sichergestellt dass er im 
Nulldurchgang definitiv aus ist.


Knut

von Markus P. (sebastianwurst)


Lesenswert?

Einmal sei() direkt hinter der Timer/Interruptinitialisierung:
1
....
2
3
 ////////////////////////////////////////////////////
4
 // Timer 1 Timer für den Dimmwertvergleich (16-bit)
5
 ////////////////////////////////////////////////////
6
 
7
    TCCR1B |= (1<<CS10) | (1<<WGM12);     // CTC uns Prescaler 1 (16.000.000/256)= 0,016ms Interrupt auslösen) 
8
  TCNT1   = 0;                          // Timer Startwert
9
    OCR1A   = 256;                        // Load register      
10
    TIMSK1 |= (1<<OCIE1A);                // Interrupt nach Overflow  
11
  
12
  //Globale Interrupts einschalten
13
  sei();

von Markus P. (sebastianwurst)


Lesenswert?

Knut schrieb:
> Ich hab mir deinen Code jetzt nicht genau angeguckt, aber du musst den
> Triac doch nur einmal "zünden", dann bleibt er doch "an". Also kurzen
> Puls aufs Gate und dann is gut. Damit ist sichergestellt dass er im
> Nulldurchgang definitiv aus ist.
>
>
> Knut

Ja das ist Richtig, ich lösche den Triac erst wieder mit steigender 
Flanke des Nulldurchgangs:
1
ISR(INT0_vect)
2
{    
3
//  TRIAC Zündung löschen
4
AusgangUnsetBit(16);
5
AusgangOut();  
6
  
7
  
8
9
  
10
    // gestoppten Timer mit  Prescaler 1024 wieder starten
11
    TCCR0B |= (1<<CS00) | (1<<CS02);   // Prescaler 1024
12
  TCNT0   = 0;  
13
 
14
}
Wenn ich jetzt Softwaremäßig den Nulldurchgang nicht mitbekomme (warum 
auch immer, ist wie im Anhang verdrahtet) dann würde er das Bit nicht 
löschen und wäre wieder/immer noch an. Das gehe ich mal noch genauer auf 
den Grund....

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

Gibts ausser der main() noch weitere Codefragmente, die du uns 
vorenthältst?

von Knut (Gast)


Lesenswert?

Markus P. schrieb:
>//===================================================================== 
=============
> //Interrupt 0 Nulldurchgangerkennung steigende Flanke
> // Im Nulldurchang wird der "TriacAusgang" gelöscht und der Timer wieder 
>gestartet
>//===================================================================== 
=============

Das ist zwar theoretisch möglich, würde ich aber schon früher machen, 
da:

Knut schrieb:
> Triac doch nur einmal "zünden", dann bleibt er doch "an"



Knut

von Markus P. (sebastianwurst)


Angehängte Dateien:

Lesenswert?

Anhang vergessen...

von Knut (Gast)


Lesenswert?

Interessant wäre auch mal deine Nulldurchgangserkennung-Hardware. Nicht 
das die einfach zu spät den Nulldurchgang meldet und da dein Triac schon 
gezündet hat. Wenn du das dann mit der Netzspannung vergleichst:

Markus P. schrieb:
> Laut Oszi löscht er im Nulldurchgang den
> Ausgang nicht


Knut

von Markus P. (sebastianwurst)


Lesenswert?

Magnus Müller schrieb:
> Gibts ausser der main() noch weitere Codefragmente, die du uns
> vorenthältst?

Ja, ich habe diesen Code angepasst:
http://son.ffdf-clan.de/?path=forumsthread&threadid=790

Da habe ich die Timer.c komplett rausgeworfen da ich die Timer.c halt 
für den Dimmer brauch.

von Magnus M. (magnetus) Benutzerseite


Lesenswert?

Markus P. schrieb:
> Magnus Müller schrieb:
>> Gibts ausser der main() noch weitere Codefragmente, die du uns
>> vorenthältst?
>
> Ja, ich habe diesen Code angepasst:
> http://son.ffdf-clan.de/?path=forumsthread&threadid=790

Und wo ist jetzt dein Code?

von Markus P. (sebastianwurst)


Lesenswert?

Knut schrieb:
> Interessant wäre auch mal deine Nulldurchgangserkennung-Hardware. Nicht
> das die einfach zu spät den Nulldurchgang meldet und da dein Triac schon
> gezündet hat. Wenn du das dann mit der Netzspannung vergleichst:
>
> Markus P. schrieb:
>> Laut Oszi löscht er im Nulldurchgang den
>> Ausgang nicht
>
>
> Knut

Optokoppler 4N25
Optokoppler MOC3020
Brückengleichrichter B250C1500
Schmitttriger  74HC14

TIC 246M  16 A /600V als Triac

von Knut (Gast)


Lesenswert?

Ok, nein, dass sieht ok aus. Versuch einfach mal den Ausgang vorm 
Nulldurchgang auszuschalten.



Knut

von Sascha W. (sascha-w)


Lesenswert?

Knut schrieb:
> Ok, nein, dass sieht ok aus. Versuch einfach mal den Ausgang vorm
> Nulldurchgang auszuschalten.

oder bei fallender Flanke an INT0 auslösen, dann wird der Nulldurchgang 
noch kurz vor dem eigentlichen Zeitpunkt erkannt.

Oder für die Triacansteuerung gleich eine Fast-PWM Betriebsart des 
Timers verwenden, und mit INT0 nur den Timer auf die Netzspannung 
syncronisieren.


Sascha

von Markus P. (sebastianwurst)


Lesenswert?

Ja, das ist besser. Bis jetzt ist das Flackern noch nicht wieder 
gekommen.

von Thomas (kosmos)


Angehängte Dateien:

Lesenswert?

@Markus P.: Noch ein kleiner Tip, ich verwende AC Optokoppler, damit 
kann man sich den Gleichrichter sparen.

Wenn wir hier schon beim Thema Flackern sind, habe gerade auch meine 
Software fertig, im Moment zum testen noch per Poti, aber ich habe ein 
leichtes hin und hergehen der Zündimpulse, sieht man am Ende des Videos 
einigermaßen. Findet ihr das ist das schon zu unruhig, um Flackerfrei 
eine Helligkeitsstufe zu halten.

http://kosmos.bplaced.net/24032012005.mp4

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.