Forum: Mikrocontroller und Digitale Elektronik Dimmersteuerung mit AVR ATmega 2560


von Tim Z. (mikroluk)


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.

: Bearbeitet durch User
von jo mei (Gast)


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.

von Tim Z. (mikroluk)


Lesenswert?

Jo danke, da ist mir beim Kopieren des Codes ein Fehler unterlaufen. In 
der TimerISR muss noch ein
1
clock_tick++;
über die if-Bedingung. Habe oben editiert.

: Bearbeitet durch User
von jo mei (Gast)


Lesenswert?

Tim Z. schrieb:
> da ist mir beim Kopieren des Codes ein Fehler unterlaufen

Ja schon klar, einfach copy & paste gemacht, und schon ist
nur eine Zeile weg, gell?

Da hat man als potentieller Helfer gleich volles Vertrauen
was bei dir alles so abgeht ....

von Tim Z. (mikroluk)


Lesenswert?

Das kannst du glauben oder nicht, so ungefähr war das. Du musst ja nicht 
helfen, wenn du kein Vertrauen hast. Ich kann dir versichern, dass das 
Programm genau so schon gelaufen ist und das
1
clock_tick++
 immer schon drin war.

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.