Forum: Mikrocontroller und Digitale Elektronik Atmega 168PA-PU Programmierung mit Arduino für Aquariumbeleuchtung


von Sven M. (beavis2809)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich bastel gerade eine Aquariumbeleuchtung für meinen Schwager.
Netz- und Steuerplatine sind fertig und funktionieren auch einwandfrei.
mit dem Programm welches auf dem Atmega 168PA-PU von Atmel läuft habe 
ich aber noch ein wenig Probleme. Ich hoffe es kann mir jmd einen Tipp 
geben was ich ändern muss, damit die Beleuchtungsphasen mit der 
entsprechenden Helligkeit leuchten.

Wie ihr aus dem pdf file für die Beleuchtungsphase entnehmen könnt, gibt 
es eine Art "Sonnenaufgang" mit 12 roten LEDs die von 08:00 Uhr bis 
08:30 Uhr von 0% auf 50% Helligkeit gesteuert werden (von 0 auf 128 bit) 
mit entsprechenden delay funktionen zwischen den Erhöhungen.
Dies funktioniert auch Tadellos. Jedoch wenn die 50% Helligkeit der 12 
roten LEDs erreicht sind, schalten sich auch alle 12 blauen und 90 
weißen LEDs zeitgleich ein auf 50% oder 100%...
Jedoch sollte blau von 08:30 Uhr bis 09:00 Uhr auch wie rot innerhalt 
dieser halben Stunde von 0% auf 50% Helligkeit geregelt werden. Weiß in 
diesem Fall von 0% auf 12,5%.

Anbei findet ihr noch den Schaltplan Screenshot von Eagle, 2 Bilder des 
Profils worauf die LEDs befestigt sind, sowie Netz- und Steuerplatine. 
Das ganze bekommt natürlich noch ein Gehäuse ;)
Die Beleuchtungsphasen sind dem pdf zu entnehmen und die 2 Screenshots 
des Arduino Sketches natürlich nicht zu vergessen.

PS. "for" Schleifen habe ich auch schon ausprobiert, jedoch hat dies 
nicht funktioniert. Ich hoffe es kann mir jmd mit der Programmierung des 
uC helfen.

Grüße beavis2809

von Sven M. (beavis2809)


Angehängte Dateien:

Lesenswert?

Die Beleuchtungsphase vergessen zu uppen :)

von Markus M. (mark_m)


Lesenswert?

Die Lichtausbeute reicht aber nur für Plastikpflanzen.

Grüsse

von Karl H. (kbuchegg)


Lesenswert?

Der ganze Ansatz mit den delays taugt nix.

Beschäftige dich erst mal damit, wie du eine 24 Stunden Uhr hinkriegst.

Die zum jeweiligen Zeitpunkt gültige Helligkeit jeder LED_Gruppe wird 
dann aus der Zeitinformation errechnet, indem du dir Formeln überlegst, 
die genau das leisten.

Die skuzessive Dimmung ergibt sich dann ganz von alleine, weil ja die 
Uhrzeit sich ändert und deine Formeln dann eben für den nächsten 
Zeitpunkt andere Helligkeitswerte errechnen.

PS: die ganze Rechnerei vereinfacht sich, wenn du die Uhrzeiten erst mal 
in 'Sekunden ab Mitternacht' ausdrückst. Dann ist das ganze Problem im 
Grunde nicht mehr als ein Absuchen einer Tabelle, das feststellen der 
Parameter für einen Dreisatz aus dieser Tabell, Dreisatzrechnen und LED 
auf die errechnete Helligkeit stellen.

Aber alles beginnt mit einer Uhr

von Sven M. (beavis2809)


Angehängte Dateien:

Lesenswert?

Ah ok. Dann meinst du sowas wie diese RTC hier im Anhang oder?
Hmm dann schau ich mal was ich da für Formeln nutzen könnte, die dann 
zur entsprechenden Uhrzeit die Helligkeit der LEDs berechnen und 
ausgeben.

Danke dir kbuchegg

von Thomasderbastler (Gast)


Lesenswert?


von Sven M. (beavis2809)


Lesenswert?

Danke für die Hilfe Thomasderbastler, aber ich werde mich erstmal an dem 
Vorschlag von kbuchegg versuchen.

von Karl H. (kbuchegg)


Angehängte Dateien:

Lesenswert?

Sven M. schrieb:
> Ah ok. Dann meinst du sowas wie diese RTC hier im Anhang oder?
> Hmm dann schau ich mal was ich da für Formeln nutzen könnte, die dann
> zur entsprechenden Uhrzeit die Helligkeit der LEDs berechnen und
> ausgeben.

Die blaue Kurve gibt den zu realisierenden Dimmverlauf an.
H1 ist die Heligkeit, die die LED vor dem Zeitpunkt 'von' hat. H2 ist 
die Helligkeit, die die LED nach dem Zeitpunkt 'bis' haben soll.

Hast du jetzt einen Zeitpunkt, der zwischen 'von' und 'bis' liegt, dann 
kannst du die 'Hgesucht' ausrechnen.
Jeweils 2 grüne Linien (hell/dunkel) zusammen mit der blauen Schräge 
bilden ein Dreieck. Da die beiden Dreiecke gleiche Winkel haben, sind 
sie nicht einfach irgendwelche Dreiecke, sondern 'ähnliche Dreiecke' 
(Mathe-Ausdruck). D.h. es gilt der Strahlensatz

   bis - von           H2 - H1
  -----------    =  ----------------
   jetzt - von         Hgesucht - H1

(wenn du mit der Zeichnung vergleichst, sind die einzelnen Teilausdrücke 
einfach nur die grünen Linien)

nach Hgesucht auflösen, den jeweiligen Zeitpunkt und die restlichen 3 
bekannten Werte einsetzen, noch H1 addieren (weil du ja Hgesucht in 
Bezug auf H1 berechnet hast) und du hast die Helligkeit, die zum 
Zeitpunkt 'jetzt' einzustellen ist.

Alles was du brauchst ist eine Tabelle, die nach den Zeiten geordnet 
ist. In dieser Tabelle suchst du raus, welche Tabellenzeile zu der 
aktuellen Uhrzeit gültig ist, in den zugehörigen Spalten dieser Zeile 
findest du dann die restlichen Werte und hast damit alles um die zum 
Zeitpunkt 'jetzt' gültige Helligkeit zu berechnen.

von Karl H. (kbuchegg)


Lesenswert?

Übrigens: Spitzen Idee, Programmcode als Bild zu posten. Da kann man 
sich so wunderbar in einer Antwort darauf beziehen.

von Eumel (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Übrigens: Spitzen Idee, Programmcode als Bild zu posten. Da kann man
> sich so wunderbar in einer Antwort darauf beziehen.

Lieber das Bild in ein Word Dokument einfügen.

von Sven M. (beavis2809)


Lesenswert?

Problem gelöst.
Wollte nur schnell Bescheid sagen, dass ich meinen Fehler in der 
Programmierung gefunden habe.
Danke für die Vorschläge mit einer Uhr also RTC um die entsprechenden 
Werte zur bestimmten Uhrzeit zu berechnen mit Formeln etc.
Da ich nur eine Kleinigkeit an meinem Programm ändern musste und es nun 
so läuft wie ich es haben möchte (Sonnenaufgang, Sonnenuntergang, 
Mondaufgang, Monduntergang und natürlich das Tageslicht) werde ich das 
Projekt nicht jetzt noch auf eine Uhr umstellen sondern belass es bei 
meinen "delay-skills" welche mich Zeit und Nerven gekostet haben, sodass 
innerhalb einer halben Stunde eine bestimmte Farbe von 0% auf 50% 
gefadet wird etc.

Für alle die eventuell auch einen solchen Anfängerfehler haben, wie ich 
ihn nenne da ich mich erst seit ein paar Wochen mit der Arduino 
Programmierung beschäftige, werde ich hier nun kurz erläutern woran es 
lag.

Problem:
Nach 30min faden die roten LEDs von 0% auf 50% --> alles gut geklappt
Dann geht schlagartig blau und weiß auch auf 50% (sollte eigentlich 
faden um die Fische nicht zu schocken!)
Das Problem lag an der Deklarierung der Farben (Stufen von 0-255)

Nur 1x die value der LEDs deklariert mit

//int led_val = 0;

dann rot innerhalb von 30min gefadet

//while(led_val != 128)
  {
    analogWrite(rot,led_val);
    led_val++;
    delay(14060.93749992);

--> jetzt ist die LED value schon auf 128 also 50%

dann

//while(led_val != 128)
  {
    analogWrite(blau,led_val);

--> somit war blau, wie auch weiß (auch im Sketch vorhanden) sofort auf 
50%


Lösung:

Für jede LED Farbe eigene values deklarieren.

//int led_val_rot = 0;
  int led_val_blau = 0;
  int led_val_weiss = 0;

:)


PS: Für das nächste Projekt werde ich wohl auf eine RTC zurückgreifen um 
solche Fehler zu vermeiden.

Grüße beavis2809

von Sven M. (beavis2809)


Lesenswert?

Hallo,

da die Aquariumsteuerung zeitlich nicht exakt läuft, habe ich mir ein 
DS1307 Modul besorgt.
Programmcode und Funktion ist einwandfrei.

17:56:15  6/3/13  Day_of_week:1
17:56:16  6/3/13  Day_of_week:1

usw.

Jetzt bin ich dabei die Uhrzeit in Sekunden umzurechnen, da ich mit 
Hilfe von Arrays immer zu bestimmten Sekunden die Helligkeit 
verschiedenfarbener LEDs erhöhen oder senken möchte. Mit der Formel für 
die aktuelle Minute und Sekunde habe ich keine Probleme, jedoch macht 
mir das mit den Stunden einen Strich durch die Rechnung.
Hier der Programmcode:

void loop()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  unsigned long neuesecond, neueminute, neuehour;
  unsigned long neuesmh;

  getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, 
&month, &year);
  Serial.print(hour, DEC);
  Serial.print(":");
  Serial.print(minute, DEC);
  Serial.print(":");
  Serial.print(second, DEC);
  Serial.print("  ");
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(year, DEC);
  Serial.print("  Day_of_week:");
  Serial.println(dayOfWeek, DEC);


  neuesecond = second;
  neueminute = minute*60;
  neuehour = hour*3600;
  neuesmh = neuesecond+neueminute+neuehour;


  Serial.print(neuesecond, DEC);
  Serial.println(" ");
  Serial.print(neueminute, DEC);
  Serial.println(" ");
  Serial.print(neuehour, DEC);
  Serial.println(" ");
  Serial.print(neuesmh, DEC);
  Serial.println(" ");




  delay(1000);
}


und das hier zeigt mein serieller Monitor.

18:7:5  6/3/13  Day_of_week:1
5
420
4294966560
4294966985
18:7:6  6/3/13  Day_of_week:1
6
420
4294966560
4294966986

Gibt es einen Trick oder vllt einen anderen Datentyp? Wenn ich statt 
"unsigned long" nur "long" deklariere, erhalte ich folgendes.

18:8:42  6/3/13  Day_of_week:1
42
480
-736
-214
18:8:43  6/3/13  Day_of_week:1
43
480
-736
-213

Bitte um Hilfe.

von Karl H. (kbuchegg)


Lesenswert?

>   neuehour = hour*3600;

Am Beispiel 19 Uhr

19 * 3600 ergibt 68400

und das ist zu groß für einen unsigned int (oder auch einen int).

Die Tatsache, dass du das Ergebnis einem unsigned long zuweist, ist 
dabei völlig unerheblich. C++ (genau wie C) funktioniert nicht so!

Du hast eine arithmetische Operation

   a op b

Wenn es darum geht zu entscheiden, wie die Operation op zu realisieren 
ist, in welchem Wertebereich die Operation durchgeführt wird, dann sind 
ausschliesslich und nur die Datentypen von a und b relevant, nicht 
jedoch, was mit diesem Ergebnis weiter geschieht!

hour ist bei dir ein byte (also ein unsigned char)
3600 ist ein int.

Damit wird die Multiplikation im Zahlenbereich int durchgeführt. Und das 
läuft nun mal über!

FAQ: Datentypen in Operationen

von Sven M. (beavis2809)


Lesenswert?

Vielen Dank Karl Heinz Buchegger!

ich habe einfach alle bytes durch unsigned long ersetzt. Ob das jetzt 
Sinn macht oder ob das Programm jetzt größer geworden ist, spielt für 
mich keine Rolle. Aber ich danke dir, dass du mir den Fehler in meinem 
Code gezeigt hast.

Danke

von Karl H. (kbuchegg)


Lesenswert?

Sven M. schrieb:
> Vielen Dank Karl Heinz Buchegger!
>
> ich habe einfach alle bytes durch unsigned long ersetzt.

Das war doch schon wieder Quatsch.
Das macht ja doch auch keinen Sinn, wenn du da völlig sinnlos unsigned 
long durch die Gegend schleppst!

hast du denn den Link nicht gelesen.
Alles was du tun musst, ist einen der Operationsteilnehmer auf long 
hochzuhieven. Zum Beispiel die 3600.

  neuehour = hour * 3600UL;

und fertig.

Jaaaaaaa. Auch Konstante haben Datentypen!
3600   ist ein int
3600L  ist ein long
3600UL ist ein unsigned long

damit steht dann da

  unsigned_long  =  byte * unsigned_long

und damit bleibt dem Compiler dann nichts anderes mehr übrig, als die 
Multiplikation als unsigned long Multiplikation zu implementieren und 
alles ist in Butter.

von Sven M. (beavis2809)


Lesenswert?

Schon wieder ein Problem :D

zu ausgerechneter und richtig angezeigter Zeit im serial.print will mein 
Atmega 168PA-PU nicht die ihm erteilte Aktion ausführen (rote LED an PWM 
Pin 9 um 1bit erhöhen). Hier der Code.


void setup()
{
  unsigned long second, minute, hour, dayOfWeek, dayOfMonth, month, 
year;
  Wire.begin();
  Serial.begin(9600);
  byte led_rot = 9;
  byte rot_val = 0;
}

void loop()
{
  unsigned long second, minute, hour, dayOfWeek, dayOfMonth, month, 
year;
  unsigned long neuesecond, neueminute, neuehour;
  unsigned long neuesmh;

  getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, 
&month, &year);
  Serial.print(hour, DEC);
  Serial.print(":");
  Serial.print(minute, DEC);
  Serial.print(":");
  Serial.print(second, DEC);
  Serial.print("  ");
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(year, DEC);
  Serial.print("  Day_of_week:");
  Serial.println(dayOfWeek, DEC);


  neuesecond = second;
  neueminute = minute*60;
  neuehour = hour*3600;
  neuesmh = neuesecond+neueminute+neuehour;


  //Serial.print(neuesecond, DEC);
  //Serial.println(" ");
  //Serial.print(neueminute, DEC);
  //Serial.println(" ");
  //Serial.print(neuehour, DEC);
  //Serial.println(" ");
  Serial.print(neuesmh, DEC);
  Serial.println(" ");


  if(neuesmh==65650)rot_p();
  if(neuesmh==65655)rot_m();


  delay(1000);
}

void rot_p(void)
{
  unsigned long neuesmh;

  if(neuesmh==65650)
  {
    analogWrite(led_rot,rot_val);
    rot_val++;
  }

}

void rot_m(void)
{
  unsigned long neuesmh;

  if(neuesmh==65655)
  {
    analogWrite(led_rot,rot_val);
    rot_val--;
  }

}


kbuchegg ich benötige deine Hilfe :)

von Karl H. (kbuchegg)


Lesenswert?

Sven M. schrieb:

> void rot_p(void)
> {
>   unsigned long neuesmh;

diese Variable hier ist eine neue Variable!
Die hat nichts mit der gleichnamigen Variablen in loop zu tun.
Die beiden haben zufällig den gleichen Namen, das wars aber auch schon. 
Abgesehen davon sind die beiden komplett voneinander unabhängig.

>
>   if(neuesmh==65650)

und wie soll diese neue Variable zu einem Wert kommen?
du hast ihr keinen zugewiesen, also steht da irgendwas drinnen. Das 
müsste schon ein gewaltiger Zufall sein, wenn diese Variable zufällig 
den Wert 65650 hätte.

> kbuchegg ich benötige deine Hilfe :)

Schön langsam muss ich sagen:
Wenn du etwas programmieren willst, warum lernst du dann nicht erst mal 
programmieren?
So richtig, mit Buch und Übungen und so.

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.