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
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.
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
Das mit dem Hochladen des Schaltplans hat wohl nicht geklappt.
>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 ?
Das ist auf jeden Fall mal ein guter Tipp. Die Optimierung ist ausgeschalten.
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
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.
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; } } } }
stimmt, aber ich habe diese Abfrage mal mit dem Debugger getestet und es funktioniert so.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.