Dimmersteuerung mit AVR ATmega 2560

OP #6388676
Lesenswert?
• ▲
▼
Hallo zusammen,

ich möchte mit dem ATmega 2560 einen Triac-Dimmer ansteuern. Die 
Sinus-Welle, mit der man den 230V Wechselstrom (50Hz) darstellen kann, 
überquert alle 10ms (halbe Sinus-Welle) den Nullpunkt auf der X-Achse 
(Zero-crossing). Nun möchte ich per Knopfdruck auf einen angeschlossenen 
Schalter ein Dim-Level einstellen. Um das Problem zunächst zu 
vereinfachen lasse ich nur zwei Dim-Level zu, nämlich MIN für aus und 
MAX für an. Um das Dim-Level auf die zu einem bestimmten Zeitpunkt auf 
der Sinus-Kurve einzustellen, lasse ich einen Timer-Interrupt alle 75 
Mikrosekunden feuern und habe so 128 diskrete Schritte (clocktick), 
wobei 128 MIN (LED aus) und 0 MAX (Led an) darstellt. Den clocktick 
setze ich bei jede Zero-crossing auf 0 und jedes Mal wenn der clock-tick 
dem eingestellten Dim-Level entspricht, setze ich den Pin, an dem der 
Triac angeschlossen ist auf high, warte 10µs und setze ihn dann wieder 
auf low. Das ganze lässt sich durch folgenden Code darstellen:
1
#include <time.h>
2
#include <TimerOne.h>
3
#include <TimerThree.h>
4
#include <DS3232RTC.h>
5
#include <sunMoon.h>
6
#include <DigitalIO.h>
7

8
#define MIN 127  // LED full off value, not 128 to avoid flicker
9
#define MAX 1 // LED full on value, not 0 -"-
10

11
volatile byte  clock_tick;
12
volatile byte dim_level = MIN; // init DL (LEDs off)
13
volatile byte buttonState1 = LOW;
14

15

16
void setup() {
17
  DDRC |= 0b01000000; //init pin for Triac as Output
18
  pinMode(18, INPUT);                   // init switch active/passive
19
  attachInterrupt(0, zero_cross_int, RISING);     // fire interrupt when signal is rising
20
  Timer1.initialize(75);                          // every 75 us
21
  Timer1.attachInterrupt(timerIsr);             // attach Interrupt Service Routine to Timer Interrupt
22
}
23

24
void timerIsr() // checks every 10us if triac needs to fired at the expected dim level DL
25
{  
26
  clock_tick++;
27
  if (dim_level == clock_tick)
28
  {
29
     PORTC |= 0b01000000;  //Triac high-
30
     delayMicroseconds(10);
31
     PORTC &= ~0b01000000;  //Triac low
32
  }
33
}
34

35

36
void zero_cross_int() // reset if sinus wave travels through zero point
37
{
38
  clock_tick=0;        // every 10 
39
}
40

41
void loop(){
42
  if (buttonState1 = digitalRead(channel_1_sw) == HIGH) //Button press
43
  {    
44
       delay(150); // Prellzeit Schalter
45
       if (buttonState1 = digitalRead(channel_1_sw) == LOW) // If MAX then MIN, else MAX
46
       {
47
          if(dim_level == MAX){dim_level = MIN;} else {dim_level = MAX;}
48
       }
49
  }
50
}

Mein Problem ist hier nun, dass ich mit dem hochfrequenten Interrupt 
nicht richtig umgehen kann. Meistens passiert nämlich gar nichts, wenn 
ich den Schalter betätige. Ab und zu hat man Glück und es funktioniert. 
Benutze ich nun aber Serial.print um mir irgendwelchen Text ausgeben zu 
lassen, funktioniert das Programm um einiges stabiler. Hier passiert nur 
ab und zu nichts bei einem Knopfdruck. Dieses komische Verhalten kann 
ich mir nur dadurch erklären, dass die Serial Bibliothek ebenfalls 
Interrupts verwendet und dadurch irgendwie das Verhalten meines 
Programms beeinflusst wird. Allerdings ist das natürlich nicht 
wünschenswert. Ich gehe davon aus, dass ich irgendwie kritische 
Sektionen verwenden muss, wenn die Triacs gefeuert werden oder so 
ähnlich, komme aber irgendwie auf keinen grünen Zweig. Wo könnte mein 
Fehler liegen?

Hoffe ihr könnt mir helfen und sorry für den Roman.

Gruss mikroluk

PS: Die Art den Knopfdruck zu prüfen, habe ich nur deswegen so gewählt, 
um die Menge an Interrupts zu reduzieren. Hatte vorher einen 
Hardware-Interrupt für den Knopfdruck, das Problem war aber das gleiche.
Gast #6388699
Lesenswert?
• ▲
▼
Wenn das die komplette Source ist die du zu bieten hast dann
wird die Variable <clock_tick> niemals ungleich null werden.
Und damit ist die Bedingung
1
  if (dim_level == clock_tick)
niemals erfüllt.

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.