Forum: Mikrocontroller und Digitale Elektronik 3 Triacs gleichzeitig ansteuern mit dem Mega168


von Robert (Gast)


Lesenswert?

Hallo,

ich habe mir eine Schaltung aufgebaut, bei der ich 12V Wechselspannung 
mit Triacs anschneiden will.
Insgesamt habe ich 3 Ausgänge, welche über Ports vom Mega168 angesteuert 
werden.
Ich gehe hierbei folgendermaßen vor:

Der Nulldurchgang der Wechselspannung wird detektiert und je ein 
Interrupt ausgelöst. Ab diesem Zeitpunkt wir der Triac entweder sofort, 
oder verzögert gezündet. (0...10ms)
Das funktioniert auch wunderbar bei einem Triac. Wenn ich nun jedoch die 
3 Triacs zu verschiedenen Zeitpunkten zünden will, also z.B. den ersten 
bei t=0ms, den 2. bei t=2ms und den 3. bei t=7ms bekomme ich da wohl 
Probleme, da dieses ja nicht parallel abgearbeitet werden kann.

Wäre über Tipps sehr dankbar.

Code habe ich noch keine, aber die Schaltung stelle ich demnächst mal 
rein.

Grüße
Robert

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Es wird nur ein Interrupt beim Nulldurchgang ausgelöst, es sei denn, Du 
hast mehrere Phasen. In diesem Interrupt setzt Du Zählvariablen zurück. 
In einem Timerinterrupt zählst Du wiederum diese Variablen hoch und beim 
Erreichen der Sollwerte zündest Du den jeweiligen Triac. Kein Problem 
also.

von robert (Gast)


Lesenswert?

Das problem ist allerdings, wenn die Triacs fast zum gleichen Zeitpunkt 
zünden sollen, ist die Rechenleistung nicht hoch genug und es zündet nur 
der erste.

Ich takte den MC mit 8MHz. Eine Halbwelle der Netzphase ist 10ms lang. 
Wenn nun der erste Triac bei 2ms zünden soll und der zweite bei 2,1ms, 
dann wird dieser ausgelassen. Nachfolgend habe ich mal den Code nur für 
das Zünden der Triacs bei festen Werten aufgeführt. Das Resultat ist, 
dass die zuerst gezündete Lampe gedimmt leuchtet, die anderen aber wild 
blinken.
Es sollen später auch noch die ADCs ausgelesen, sowie ein LCD 
angesteuert werden. Das wünde dann noch mehr rechenleistung kosten.

Der INT0, bei welchem phase auf 1 gesetzt wird, wird immer beim 
Phasennullduchgang ausgelöst.

Der Schaltplan befindet sich im Anhang.

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <lcd.h>
#include <lcd.c>

volatile uint8_t phase;

ISR (INT0_vect)
{
  TCNT1=0;
  phase=1;
}


int main(void)
{

  DDRC=0xff;
  PORTC=0xff;
  DDRB=0xff;

  EICRA|=(1<<ISC00);
  EIMSK|=(1<<INT0);

    TCCR1B|=(1<<CS11)|(1<<CS10);TIMSK1|=(1<<TOIE1);  //Timer1

    sei();


    while(1)
  {

  while(phase==1)
  {

  if(TCNT1==900)  //TCNT1=1200 entspticht 10ms
  {
  PORTC &= ~(1<<PC3);
  _delay_us(100);
  PORTC |= (1<<PC3);

         if(a>b & a>c)
  phase=0;

  }

  if(TCNT1==910)
  {
  PORTC &= ~(1<<PC4);
  _delay_us(100);
  PORTC |= (1<<PC4);

  if(b>a & b>c)
  phase=0;
  }

  if(TCNT1==920)
  {

  PORTC &= ~(1<<PC5);
  _delay_us(100);
  PORTC |= (1<<PC5);

  if(c>a & c>b)
  phase=0;

  }
     }

  }
}


MFG

von robert (Gast)


Angehängte Dateien:

Lesenswert?

Das mit dem Hochladen des Schaltplans hat wohl nicht geklappt.

von holger (Gast)


Lesenswert?

>Das problem ist allerdings, wenn die Triacs fast zum gleichen Zeitpunkt
>zünden sollen, ist die Rechenleistung nicht hoch genug und es zündet nur
>der erste.

Quatsch. Du verwendest  _delay_us(100);
 _delay_us(); ist mit Vorsicht zu geniessen.


6.22.2.2 void _delay_us (double __us)
Perform a delay of __us microseconds, using _delay_loop_1().
The macro F_CPU is supposed to be defined to a constant defining the CPU 
clock
frequency (in Hertz).
The maximal possible delay is 768 us / F_CPU in MHz.

In deinem Fall 768 us / 8 = 96us. 100us ist zu viel !

Hast du auch Optimierung im makefile eingeschaltet ?

von robert (Gast)


Lesenswert?

Das ist auf jeden Fall mal ein guter Tipp.
Die Optimierung ist ausgeschalten.

von Fred S. (Gast)


Lesenswert?

Hallo Robert,

die Verzögerung ist auf jeden Fall die Quelle des Problems. Wenn Du den 
ersten Triac bei 2ms zündest und dann bei

 if(TCNT1==900)  //TCNT1=1200 entspticht 10ms
  {
  PORTC &= ~(1<<PC3);
  _delay_us(100);
  PORTC |= (1<<PC3);

         if(a>b & a>c)
  phase=0;
  }

eben 100us wartest, wird das Programm beim Zeitpunkt von 2ms+100us noch 
warten (= nicht wieder in der Hauptschleife sein!) und so den Zeitpunkt 
zum Zünden des 2. Triacs verpassen.

Gruß

Fred

von robert (Gast)


Lesenswert?

Ich habe einen Fehler im code gemacht:

den Timerwerten TCNT1 habe ich a,b und c zugeordnet. Mit den Abfragen

if(a>b & a>c)

findet man heraus, welcher Triac als letzter zündet. Und bei diesem wird 
phase auf 0 gesetzt und die whileschleife wird verlassen.

von robert (Gast)


Lesenswert?

Dieser Code macht dasselbe Problem:

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <lcd.h>
#include <lcd.c>


#define UART_BAUD_RATE      9600


volatile uint8_t phase;

volatile uint16_t a=200;
volatile uint16_t b=600;
volatile uint16_t c=900;

volatile char buffer[16];
volatile char s[16];

volatile uint8_t update=0;


ISR (INT0_vect)
{
  TCNT1=0;
  phase=1;
}


int main(void)
{


  DDRC=0xff;
  PORTC=0xff;
  DDRB=0xff;

  EICRA|=(1<<ISC00);
  EIMSK|=(1<<INT0);

    TCCR1B|=(1<<CS11)|(1<<CS10);TIMSK1|=(1<<TOIE1);        //Timer1

    TCCR0B|=(1<<CS02)|(1<<CS00);TIMSK0|=(1<<TOIE1);


  sei();


    while(1)
  {


         while(phase==1)
  {

  if(TCNT1==a)  //TCNT1=1200 entspticht 10ms
  {
  PORTC &= ~(1<<PC3);
  _delay_us(50);
  PORTC |= (1<<PC3);

  if(a>b & a>c)
  phase=0;
         }

         if(TCNT1==b)
  {

  PORTC &= ~(1<<PC4);
         _delay_us(50);
  PORTC |= (1<<PC4);

  if(b>a & b>c)
  phase=0;
  }

  if(TCNT1==c)
  {
         PORTC &= ~(1<<PC5);
  _delay_us(50);
  PORTC |= (1<<PC5);

  if(c>a & c>b)
  phase=0;

  }
      }

    }
}

von holger (Gast)


Lesenswert?

>  if(b>a & b>c)

  if(b>a && b>c)

von robert (Gast)


Lesenswert?

stimmt, aber ich habe diese Abfrage mal mit dem Debugger getestet und es 
funktioniert so.

von holger (Gast)


Lesenswert?

Vieleicht triffst du TCNT1 ja nicht immer GENAU auf den Punkt ;)

while(phase==1)
 {
  unsigned int tmrtmp;
  cli();
  tmrtmp = TCNT1;
  sei();

  if(tmrtmp>=a && tmrtmp<b)  //TCNT1=1200 entspticht 10ms
   {
    PORTC &= ~(1<<PC3);
    _delay_us(50);
    PORTC |= (1<<PC3);
    if(a>b && a>c)  phase=0;
   }

  if(tmrtmp>=b && tmrtmp<c)
  {
    PORTC &= ~(1<<PC4);
    _delay_us(50);
    PORTC |= (1<<PC4);
    if(b>a && b>c)  phase=0;
  }

  if(tmrtmp>=c)
  {
   PORTC &= ~(1<<PC5);
   _delay_us(50);
   PORTC |= (1<<PC5);
   if(c>a && c>b) phase=0;
  }

 }

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.