forked from bracci/Qlockthree
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Qlockthree.ino
2282 lines (2060 loc) · 72.2 KB
/
Qlockthree.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
Clockthree
Die Firmware der Selbstbau-QLOCKTWO.
@mc Arduino/RBBB (ATMEGA328)
@autor Christian Aschoff / caschoff _AT_ mac _DOT_ com
@version 3.4.8
@created 1.11.2011
@updated 15.3.2015
Versionshistorie:
V 1.1: - DCF77 auf reine Zeit ohne Strings umgestellt.
- Ganzes Datum wird in die DS1307 geschrieben (wieder verworfen).
V 1.2: - Schnelles Schreiben der Shift-Register eingefuehrt.
V 1.3: - Auf eigene DCF77-Bibliothek umgestellt (MyDCF77) und DCF77Helper verbessert.
V 1.4: - Glimmen/Nachleuchten dank Tipp von Volker beseitigt (http://www.mikrocontroller.net/topic/209988).
- Erneute Fehlerbereinigung in der DCF77-Bibliothek.
V 1.5: - Die Helligkeit laesst sich ueber die Variable 'brightness' einstellen (Bereich 1-9) bzw.
ueber den Compiler-Schalter 'ENABLE_LDR' die Regelung einschalten.
V 1.6: - Fehler in der DCF77Helper-Bibliothek behoben.
V 1.7: - SKIP_BLANK_LINES eingefuehrt, damit hellere LEDs (Danke an Johannes).
V 1.8: - UPSIDE_DOWN eingefuehrt, damit man die Kabel beim Anoden-Multiplexer nicht kreuzen muss.
V 1.9: - Diverse Verbesserungen und Fehlerbehebungen, die das Flackern drastisch reduzieren.
V 1.9.1: - Fehler behoben, der die Nutzung eines analogen Pins fuer den DCF77-Empfaenger verhindert hat.
V 1.9.2: - Timing-Parameter fuer die PWM ueber DEFINE anpassbar.
- LDR-Grenzwerte automatisch anpassbar.
- Schreibfehler in setHoures()->setHours() behoben.
- Kompatibilitaet zu Arduino-IDE 1.0 hergestellt.
V 1.9.3: - Glimmen wieder behoben.
V 1.9.4: - Modus zum Einstellen der Helligkeit eingefuehrt.
V 2.0: - Sprachrelevante Dinge ausgelagert, so kann man mehr Sprachen haben und einfach durch einkommentieren aktivieren.
- setWords in setMinutes und setMinutes in setCorners umbenannt, weil es mehr Sinn ergibt.
- setCorners in eigene Datei ausgelagert, weil viele Bastler sich vertun und in der Routine Aenderungen vornehmen muessen.
- LDR in eigene Klasse ausgelagert und Werte geglaettet. Am Anfang werden 1000 Werte gelesen, damit er sich einpegelt.
- Signal vom DCF77-Empfaenger geglaettet, damit nicht ein einzelner falscher Peak das Telegramm zerstoert.
- Status-LEDs koennen ueber DEFINEs ausgeschaltet werden.
- DCF77- und SQW-LED blinken am Anfang drei Mal als 'Hello', damit man ohne Serial-Monitor sehen kann, ob der ATMEGA anlaeuft.
- Serial-Output ist immer an, kleine Statusmeldung waehrend der Initialisierung, damit man beim Bespielen des ATMEGA ohne weitere
Elektronik sehen kann, ob das Programm drauf ist und laeuft.
- Aenderung, die ein Stellen der Zeit nach dem DCF77-Signal auch im Modus 'BLANK' ermoeglicht - in diesem Modus ist der Empfang
weniger gestoert, da die LED-Matrix abgeschaltet ist.
- Zeitgesteuertes Abschalten des Displays eingefuehrt (Stromsparen in der Nacht/Schlafzimmer/besserer Empfang des DCF77-Empfaengers).
- Speaker auf D13 eingefuehrt.
- Alarm-Mode eingefuehrt.
- Bayrische Sprachvariante (DE_BA): 'viertel nach Zehn', aber 'dreiviertel Elf'.
V 2.0.1: - DCF77-Tresholds angepasst.
V 2.0.2: - Strings in PROGMEM (flash) ausgelagert.
V 2.0.3: - SPEAKER_IS_BUZZER eingefuehrt, damit kann man sagen, ob man einen Lautsprecher oder Piezo-Buzzer als Alarm verwendet.
V 2.0.4: - falsches BREAK dank Lars behoben.
V 2.0.5: - Franzoesisch hinzugefuegt, Woerter_??.h's anschaulicher gemacht. Weitere Sprachen angelegt, aber noch nicht die Logik implementiert (Hilfe?!).
V 2.0.6: - cleanWordsForAlarmSettingMode() eingefuehrt, damit das Stellen des Alarms sprachenunabhaengig ist.
- Das DCF77-Signal kann per Compiler-Schalter invertiert werden.
V 2.0.7: - Neuer Modus: Umschaltung LDR auto/manuell dank Alexander.
V 2.0.8: - Genauigkeit verbessert, dank Peter (Interrupt auf FALLING). @Peter: Das Zurueckscheiben in die DS1307 passiert im Normalbetrieb ja
nur beim Update ueber den DCF77-Empfaenger, daher habe ich es weggelassen.
V 2.0.9: - SplitSideDown rausgenommen, diesen seltenen Fehler braucht kein Mensch.
V 2.1: - Neue Sprachen hinzugefuegt: Englisch und Italiensch. Spanisch ist angelegt, aber nicht implementiert, weil ich kein Wort Spanisch spreche.
- Man kann jetzt einfach relativ weit oben im Code ueber Compiler-Schalter festlegen, welche Sprache man haben moechte.
V 2.1.1: - Bitmaps in den PROGMEM ausgelagert. So kann man alle Buchstaben halten.
V 2.1.2: - Bug im Alaram-Modus behoben.
V 2.1.3: - Zusaetzlich zu den Ziffern auch Staben eingefuehrt, A/M-Modus darauf umgestellt (Vorbereitung auf Konfigurationsmoeglichkeit
fuer alle Sprachen in einer Firmware)
V 2.1.4: - Optimierung hinsichtlich Speicherbedarf.
V 3.0: - LedDriver-Klasse erstellt, welche die Shift-Register und UDN2981A als Led-Treiber kapseln. Dadurch kann man auch andere
LED-Treiber nehmen (MAX7219, AS1130 etc.) und einfach eine passende Klasse von der LedDriver-Klasse vererben und in den Code einklinken.
- Alle Sprachen im 'Renderer' zusammengefasst, so dass sie ohne die Firmware neu zu flashen umschaltbar werden.
- Niederlaendisch hinzugefuegt (Danke an Wekog24 und Rudolf K.).
- Eine kleine Debug-Klasse eingefuehrt, damit die #debug-Statements nicht so stark den Code zerhacken und er besser lesbar wird.
- Beim Starten wird der freie Speicher und die Version auf der Console ausgegeben.
- Eine Alarm-Klasse eingefuehrt, das macht den 'Hauptcode' nochmal besser lesbar.
- Configuration.h eingefueht, in der alle wichtigen Compiler-Schalter zusammengefuehrt sind, dadurch gibt es eine zentrale Stelle
fuer die Anpassungen (Danke fuer das Konzept an Markus K.).
- Settings.h eingefuehrt, in der die Spracheinstellung gehalten wird und im EEPROM gespeichert wird (Danke fuer das Konzept an Markus K.).
- Modes zum Einstellen der Sprache und des Eck-Modus eingefuehrt.
- Extended Modes eingefuehrt.
- Saechsisch als Sprache aufgenommen, danke an Sven.
- Bug im setzten der Eck-LEDs fuer den Ueberpixel behoben.
- Brightness ist normaler Mode, aber nur wenn ldr_auto == FALSE.
- Automatische Alarm-Abschaltung nach MAX_BUZZ_TIME_IN_MINUTES.
- Stellen der Uhr nur im erweiterten Modus moeglich (sonst verstellt man sie leicht bei der Verwendung als Wecker).
- LDR-Modus wird im EEPROM abgelegt.
- kleinere Korrekturen, die nur in erweiterten Compiler-Ausgaben zu Warnings gefuehrt haben.
- Kleinere Optimierungen, Danke an Michael K.
- Bug aufgrund eines moeglichen Ueberlaufs von millis() in Button.cpp behoben.
- Verbesserungen in der Helligkeitssteuerung.
- ENABLE_LDR aus Configuration.h entfernt, da sich der LDR ueber das erweiterte Setup ausschalten laesst.
V 3.0.1: - Schweizer Layout angepasst.
V 3.1: - Spanisch implementiert.
- Der LDR skaliert jetzt selbst, dann flackert es weniger bei unguenstigen Lichtverhaeltnissen.
V 3.1.1. - Die Displayhelligkeit wird beim starten gesetzt.
- Kleiner Fehler im Spanischen behoben.
- Die alte Shiftregistermethode ist wieder aktiv, die schnelle kann in Configuration.h gesetzt werden.
V 3.1.2. - Led-Driver-Klassen sagen, wer sie sind (fuer die Ausgabe der Konfiguration beim Start).
- Klassen-Namen verbessert.
V 3.2. - Led-Driver fuer das Licht-Monster implementiert.
- LDR-Klasse auf 0-100% umgebaut.
- Brightness wird im EEPROM gesichert.
- EnableAlarm und DCF77SignalIsInverted ins EEPROM ausgelagert und ueber das erweiterte Setup einstellbar.
- Die Modi SCRAMBLE und ALL entfernt, dafuer den Modus TEST eingefuehrt. ALL ist fuer manche DisplayDriver gefaehrlich wegen des Stromverbrauchs. TEST schalte nacheinander alle LEDs einmal durch.
- Moeglichkeit zur Zeitverschiebung eingefuehrt.
V 3.2.1. - Alle Deutsch-Varianten zusammengefasst, um Platz zu sparen.
- Fehler im Italienischen behoben.
- Fehler mit Doppelbelegung einer Variable im Qlockthree.ino behoben.
- Der LDR wird nur alle 250ms gelesen, dann flackert er weniger bei unguenstigen Verhaeltnissen.
V 3.2.2. - DS1307 Multi-MCU-Faehig gemacht.
- Initialisierung der DS1307 verbessert.
V 3.2.3. - A0-Hack: Verbindet man die freie A0-Leitung mit PON vom DCF77-Empfaenger, schaltet diese den Empfaenger korrekt
ein und aus, je nach Displayzustand. Ist PON fest mit GND verbunden, passiert nichts (schadet aber auch nicht).
V 3.2.4. - Der DCF-Empfaenger wird ueber A0 am Anfang eingeschaltet, dann nicht mehr ausgeschaltet.
- Wird in den Blank-Modus geschaltet (Display aus), schaltet sich nach dem erfolgreichen Empfang der Zeit ueber DCF77
das Display wieder ein (hilft beim Debuggen).
- Der Nachtabschaltmodus ist ein eigener, nicht manuell erreichbarer Modus.
V 3.3.0. - LedDriverNeoPixel fuer den Aufbau mit WS2812B-Streifen eingefuehrt (Verkabelungsschema ist beim LedDriverNeoPixel)...
- ...dazu die Klasse Button angepasst, so dass sie auch gegen GND schalten kann (damit Unterstuetzung fuer das BBRTCAD).
- Achtung! Wenn die NeoPixel-Library im Librarys-Ordner ist, kann ich keinen Pointer auf den Stripe (in LedDriverNeoPixel.h)
definieren (ich weiss leider nicht warum, es kommt eine seltsame Compiler-Meldung). Wenn sie im Qlockthree-Ordner ist, geht es.
- IR-Fernbedienungs-Unterstuetzung eingefuehrt. Achtung! Wegen Platzmangels alle IRs ausser der Sparkfun (NEC) auskommentiert. Siehe weitere
Infos weiter unten und bei der IR-Fernbedienung!
- Achtung! Weil ich die IR-Receiver-Library (https://github.com/shirriff/Arduino-IRremote/) entschlacken musste, ist sie hier
im Qlockthree-Ordner. Wenn sie auch im Librarys-Ordner ist, schlaegt die Compilierung fehl! Wer andere Codes als die von der
SparkFun-Fernbedienung (NEC) nehmen mechte, muss die entsprechenden Typen in der Datei IRremote.cpp so ab Zeile 427 wieder
einkommentieren. Die Implementierung hier ist beispielhaft zu sehen, um eigene Ideen verwirklichen zu koennen.
- Test-Modus geaendert, damit er mit der IR-Fernbedienung klappt. Die Eck-LEDs zaehlen im Sekunden-Takt hoch, die Spalten werden
im Sekunden-Takt nach rechts durchgeschaltet.
- DCF-Empfang verbessert, dank Tipp aus dem Forum (unguenstiger INTERNAL_PULLUP beim Signal-Pin; PULL-Widerstaende muessen in Hardware
je nach verwendetem Empfaenger realisiert werden).
- Flackern in Ext-Menues und Manual-Brightness behoben, falsch durchdachtes linesToWrite-Statement (interessiert nur DefaultLedDriver,
alle anderen ignorieren es eh).
- Fehler in der DS1307-Klasse behoben. Nicht immer kommen die angeforderten 7 Bytes, dann verwerfen und neu anfordern (und nach
8 Versuchen abbrechen). Der I2C-Bus ist wohl speziell bei LED-Stripes gerne mal gestoert, dann kommen die beruehmten '85' Sekunden.
- Mode fuer die Visualisierung des DCF77-Empfangs (im Ext-Menue nach dem LED-Test) eingefuehrt. Man kann damit abschaetzen, wie gut der
DCF77-Empfang ist. Mit der gelben LED muessen die Ecken durchschalten. Schalten sie wild durcheinander, gibt es Fehlsignale.
Das Problem ist, dass ja die LED-Matrix den Empfang stoert. So stoert natuerlich potentiell auch die Visualisierung den Empfang.
Mit einem WortWecker hat das dennoch ganz gut geklappt. Mit dem experimentellen LedDriverNeoPixel nicht.
- Kleinen Fehler im Italienischen behoben, danke an die diversen Hinweisgeber!
V 3.3.1. - Stundenbegrenzung im Renderer (die ja wegen der Zeitverschiebungsmoeglichkeit existiert) auf den Bereich 0 <= h <= 24 ausgeweitet,
dank Tipp aus dem Forum.
V 3.4.0. - Die DCF77-Decoding-Klasse vollstaendig umgestellt. Alle Beispiele im Internet gehen davon aus, dass man keine Vergleichszeit hat.
Da wir hier eine Echtzeituhr haben, kann man statistische Methoden zur Auswertung verwenden. Wenn das Signal optisch brauchbar aussieht (gelbe LED),
Synchronisiert die Zeit in weniger als 4 Minuten. Aber es muss eben brauchbar aussehen. Kurzes Aufblinken 1 Mal pro Sekunde, eine
Pause pro Minute.
V 3.4.1. - Die Adafruit- und IR-Library umbenannt ("My" vorangestellt), damit sie nicht mit den offiziellen Librarys kollidieren. Warum sie hier lokal liegen,
steht weiter oben.
V 3.4.2. - LDR-Bugs behoben und -Klasse optimiert. Dazu auch Getter fuer die Helligkeit in den Display-Drivern eingefuehrt.
V 3.4.3. - Vergessene DEBUGs auskommentiert, Check der DS1307 beim Start verbessert (Danke an Erich M.).
V 3.4.4. - Verbesserungen in der RTC (setzten der Zeit durch Compile-Zeit moeglich).
- Adafruits NeoPixel-Library muss jetzt im Librarys-Ordner liegen.
V 3.4.5. - DS1307 nach MyRTC umbenannt, weil es nicht mehr nur um die DS1307 geht.
- Einschalten des Rechtecksignals fuer DS1307 und DS3231 getrennt (Danke an Erich M.) - Konfiguration in der Configuration.h.
- Unterstuetzung verschiedener IR-Fernbedienungen vereinfacht. Codes von NEC-compatiblen Fernbedienungen werden angezeigt, wenn eine Fernbedienung in
der Configuration.h eingeschaltet ist (muss nicht die richtige sein) und #DEBUG an ist. Drei Beispiel-Remotes sind angelegt: Sparkfun,
Mooncandles, Lunartec. Bei der Verwendung von Nicht-NEC-Fernbedienungen muss der entsprechende Part in MyIRremote.cpp einkommentiert werden,
ein guter Start ist Zeile 428.
- Im Zusammenhang mit den Fernbedienungen setColor() fuer die LED-Driver eingefuehrt. Damit kann man die Farben von RGB-Stripes aendern. Bei
dem klassischen Aufbau mit einfarbeigen LEDs (75HC595; MAX7219 etc.) passiert natuerlich nichts.
- Unterstuetzung fuer APA102-Stripes (DotStars) eingefuehrt, die Adafruit APA102-Library muss dazu im librarys-Ordner liegen.
- FPS werden bei eingeschaltetem #DEBUG angezeigt.
- Die Helligkeitsregelung laeuft jetzt sanfter. Timing-Werte fuer die verschiedenen LedDriver in der Configuration.h hinterlegt.
V 3.4.6. - Unterstuetzung fuer LPD8806-Stripes eingefuehrt, die Adafruit LPD8806-Library muss dazu im librarys-Ordner liegen. Achtung! Zur Zeit hat die LPD8806-Library
von Adafruit einen Bug. Es fehlt das klassische #ifndef __CLASSNAME__ #define __CLASSNAME__ [Klasssendefinition] #endif um die Klasse im .h-File.
V 3.4.7. - Unterstuetzung fuer Buttons auf rein analoge Ports hinzugefuegt, wie sie der ATMEGA328 in SMD-Ausfuehrung hat.
- Unterstuetzung fuer die alte Arduino-IDE (bis 1.0.6) entfernt, da sich die Firmware damit eh nicht mehr kompilieren laesst.
- Library fuer MAX7219 (LedControl) ausgelagert, sie muss jetzt im Librarys-Ordner liegen.
V 3.4.8. - HelperSeconds-Behandlung in Interrupt-Funktion verschoben, damit die nicht aufgrund von Tastendruecken hochgezaehlt werden, danke an Meikel.
*/
#include <Wire.h> // Wire library fuer I2C
#include <avr/pgmspace.h>
#include <EEPROM.h>
#include <SPI.h>
#include "Configuration.h"
#include "LedDriver.h"
#include "LedDriverDefault.h"
#include "LedDriverUeberPixel.h"
#include "LedDriverPowerShiftRegister.h"
#include "LedDriverNeoPixel.h"
#include "LedDriverDotStar.h"
#include "LedDriverLPD8806.h"
#include "IRTranslator.h"
#include "IRTranslatorSparkfun.h"
#include "IRTranslatorMooncandles.h"
#include "IRTranslatorLunartec.h"
#include "IRTranslatorCLT.h"
#include "MyIRremote.h"
#include "MyRTC.h"
#include "MyDCF77.h"
#include "Button.h"
#include "AnalogButton.h"
#include "LDR.h"
#include "DCF77Helper.h"
#include "Renderer.h"
#include "Staben.h"
#include "Alarm.h"
#include "Settings.h"
#include "Zahlen.h"
#include "Modes.h"
#include "MyTempSens.h"
#ifdef EVENTS
#include "Events.h"
#endif
#define FIRMWARE_VERSION "CLT OS V2.0"
/*
Den DEBUG-Schalter gibt es in allen Bibiliotheken. Wird er eingeschaltet, werden ueber den
'Serial-Monitor' der Arduino-Umgebung Informationen ausgegeben. Die Geschwindigkeit im
Serial-Monitor muss mit der hier angegeben uebereinstimmen.
Default: ausgeschaltet
*/
//#define DEBUG
#include "Debug.h"
// Die Geschwindigkeit der seriellen Schnittstelle. Default: 57600. Die Geschwindigkeit brauchen wir immer,
// da auch ohne DEBUG Meldungen ausgegeben werden!
#define SERIAL_SPEED 57600
/*
Die persistenten (im EEPROM gespeicherten) Einstellungen.
*/
Settings settings;
/**
Der Renderer, der die Woerter auf die Matrix ausgibt.
*/
Renderer renderer;
/**
Der LED-Treiber fuer 74HC595-Shift-Register. Verwendet
von der Drei-Lochraster-Platinen-Version und dem
NachBau_V02-Board sowie dem WortWecker nach Christian.
Data: 10; Clock: 12; Latch: 11; OutputEnable: 3
LinesToWrite: 10
*/
#if defined (LED_DRIVER_DEFAULT)
LedDriverDefault ledDriver(10, 12, 11, 3, 10);
#define PIN_MODE 7
#define PIN_M_PLUS 5
#define PIN_H_PLUS 6
#define BUTTONS_PRESSING_AGAINST HIGH
#define PIN_IR_RECEIVER A1
#define PIN_LDR A3
#define IS_INVERTED true
#define PIN_SQW_SIGNAL 2
#define PIN_DCF77_SIGNAL 9
#define PIN_DCF77_PON A0
#define PIN_SQW_LED 4
#define PIN_DCF77_LED 8
#define PIN_SPEAKER 13
#define PIN_TEMP_SENS A2
/**
Der LED-Treiber fuer 4 MAX7219-Treiber wie im Ueberpixel.
Data: 10; Clock: 11; Load: 12
*/
#elif defined (LED_DRIVER_UEBERPIXEL)
LedDriverUeberPixel ledDriver(5, 6, 7);
#define PIN_MODE 8
#define PIN_M_PLUS 3
#define PIN_H_PLUS 4
#define BUTTONS_PRESSING_AGAINST HIGH
#define PIN_IR_RECEIVER A1
#define PIN_LDR A3
#define IS_INVERTED true
#define PIN_SQW_SIGNAL 2
#define PIN_DCF77_SIGNAL 9
#define PIN_DCF77_PON A0
#define PIN_SQW_LED 10
#define PIN_DCF77_LED 11
#define PIN_SPEAKER 13
#define PIN_TEMP_SENS A2
/**
Der LED-Treiber fuer Power-Shift-Register.
Data: 10; Clock: 11; Load: 12
*/
#elif defined (LED_DRIVER_POWER_SHIFT_REGISTER)
LedDriverPowerShiftRegister ledDriver(10, 12, 11, 3);
#define PIN_MODE 7
#define PIN_M_PLUS 5
#define PIN_H_PLUS 6
#define BUTTONS_PRESSING_AGAINST HIGH
#define PIN_IR_RECEIVER A1
#define PIN_LDR A3
#define IS_INVERTED true
#define PIN_SQW_SIGNAL 2
#define PIN_DCF77_SIGNAL 9
#define PIN_DCF77_PON A0
#define PIN_SQW_LED -1
#define PIN_DCF77_LED -1
#define PIN_SPEAKER -1
#define PIN_TEMP_SENS A2
/**
Der LED-Treiber fuer NeoPixel-Stripes...
*/
#elif defined (LED_DRIVER_NEOPIXEL)
/**
...an einem BBRTCAD.
Data: 6
*/
#ifdef BOARD_BBRTCAD
LedDriverNeoPixel ledDriver(6);
#define PIN_MODE 11
#define PIN_M_PLUS 13
#define PIN_H_PLUS 12
#define BUTTONS_PRESSING_AGAINST LOW
#define PIN_IR_RECEIVER A1
#define PIN_LDR A0
#define IS_INVERTED true
#define PIN_SQW_SIGNAL 2
#define PIN_DCF77_SIGNAL 3
#define PIN_DCF77_PON 4
#define PIN_SQW_LED 9
#define PIN_DCF77_LED 10
#define PIN_SPEAKER -1
#define PIN_TEMP_SENS A2
/**
* ...an einer CLT.
* Data: 13
*/
#elif defined(BOARD_CLT)
LedDriverNeoPixel ledDriver(13);
#define PIN_MODE 7
#define PIN_M_PLUS 5
#define PIN_H_PLUS 6
#define BUTTONS_PRESSING_AGAINST HIGH
#define PIN_IR_RECEIVER 10
#define PIN_LDR A3
#define IS_INVERTED true
#define PIN_SQW_SIGNAL 2
#define PIN_DCF77_SIGNAL 9
#define PIN_DCF77_PON -1
#define PIN_SQW_LED 4
#define PIN_DCF77_LED 8
#define PIN_SPEAKER -1
#define PIN_TEMP_SENS A0
/**
* ...an einem AMBBRTCB V1.0
* Data: 0
*/
#elif defined(BOARD_AMBBRTCAD)
LedDriverNeoPixel ledDriver(0);
#define PIN_MODE 5
#define PIN_M_PLUS 7
#define PIN_H_PLUS 6
#define BUTTONS_PRESSING_AGAINST LOW
#define PIN_IR_RECEIVER A1
#define PIN_LDR A0
#define IS_INVERTED false
#define PIN_SQW_SIGNAL 10
#define PIN_DCF77_SIGNAL 3
#define PIN_DCF77_PON -1
#define PIN_SQW_LED 1
#define PIN_DCF77_LED 2
#define PIN_SPEAKER -1
#define PIN_TEMP_SENS -1
#endif
/**
Der LED-Treiber fuer DotStars-Stripes an einem BBRTCAD.
Data: 6
Clock: 7
*/
#elif defined (LED_DRIVER_DOTSTAR)
LedDriverDotStar ledDriver(6, 7);
#define PIN_MODE 11
#define PIN_M_PLUS 13
#define PIN_H_PLUS 12
#define BUTTONS_PRESSING_AGAINST LOW
#define PIN_IR_RECEIVER A1
#define PIN_LDR A0
#define IS_INVERTED false
#define PIN_SQW_SIGNAL 2
#define PIN_DCF77_SIGNAL 3
#define PIN_DCF77_PON 4
#define PIN_SQW_LED 9
#define PIN_DCF77_LED 10
#define PIN_SPEAKER -1
#define PIN_TEMP_SENS -1
/**
Der LED-Treiber fuer LPD8806-Stripes...
*/
#elif defined (LED_DRIVER_LPD8806)
/**
* ...an einem BBRTCAD.
* Data: 6
* Clock: 7
*/
#ifdef BOARD_BBRTCAD
LedDriverLPD8806 ledDriver(6, 7);
#define PIN_MODE 11
#define PIN_M_PLUS 13
#define PIN_H_PLUS 12
#define BUTTONS_PRESSING_AGAINST LOW
#define PIN_IR_RECEIVER A1
#define PIN_LDR A0
#define IS_INVERTED false
#define PIN_SQW_SIGNAL 2
#define PIN_DCF77_SIGNAL 3
#define PIN_DCF77_PON 4
#define PIN_SQW_LED 9
#define PIN_DCF77_LED 10
#define PIN_SPEAKER -1
#define PIN_TEMP_SENS -1
/**
...an einer CLT.
Data: 13
Clock: 11
*/
#elif defined(BOARD_CLT)
LedDriverLPD8806 ledDriver(13, 11);
#define PIN_MODE 7
#define PIN_M_PLUS 5
#define PIN_H_PLUS 6
#define BUTTONS_PRESSING_AGAINST HIGH
#define PIN_IR_RECEIVER 10
#define PIN_LDR A3
#define IS_INVERTED true
#define PIN_SQW_SIGNAL 2
#define PIN_DCF77_SIGNAL 9
#define PIN_DCF77_PON -1
#define PIN_SQW_LED 4
#define PIN_DCF77_LED 8
#define PIN_SPEAKER -1
#define PIN_TEMP_SENS -1
#endif
#endif
/**
Der IR-Remote-Control-Receiver.
*/
#ifndef REMOTE_NO_REMOTE
IRrecv irrecv(PIN_IR_RECEIVER);
decode_results irDecodeResults;
#if defined (REMOTE_SPARKFUN)
IRTranslatorSparkfun irTranslator;
#elif defined (REMOTE_MOONCANDLES)
IRTranslatorMooncandles irTranslator;
#elif defined (REMOTE_LUNARTEC)
IRTranslatorLunartec irTranslator;
#elif defined (REMOTE_CLT)
IRTranslatorCLT irTranslator;
#endif
#endif
#ifdef REMOTE_BLUETOOTH
IRTranslatorCLT irTranslatorBT;
#endif
// Ueber die Wire-Library festgelegt:
// Arduino analog input 4 = I2C SDA
// Arduino analog input 5 = I2C SCL
// Werden zur Kommunikation mit der
// RTC verwendet.
/**
Die Real-Time-Clock mit der Status-LED fuer das SQW-Signal.
*/
MyRTC rtc(0x68, PIN_SQW_LED);
volatile byte helperSeconds;
/**
Der Funkempfaenger (DCF77-Signal der PTB Braunschweig).
*/
MyDCF77 dcf77(PIN_DCF77_SIGNAL, PIN_DCF77_LED);
DCF77Helper dcf77Helper;
/**
* Tempsensor
*/
#ifndef TEMP_SENS_NONE
MyTempSens tempSens(PIN_TEMP_SENS);
#endif
/**
Variablen fuer den Alarm.
*/
#ifdef ALARM
Alarm alarm(PIN_SPEAKER);
#endif
/**
Der Helligkeitssensor
*/
LDR ldr(PIN_LDR, IS_INVERTED);
unsigned long lastBrightnessCheck;
/**
Die Helligkeit zum Anzeigen mit den Balken.
*/
byte brightnessToDisplay;
/**
Die Tasten.
*/
Button minutesPlusButton(PIN_M_PLUS, BUTTONS_PRESSING_AGAINST);
Button hoursPlusButton(PIN_H_PLUS, BUTTONS_PRESSING_AGAINST);
Button extModeDoubleButton(PIN_M_PLUS, PIN_H_PLUS, BUTTONS_PRESSING_AGAINST);
Button modeChangeButton(PIN_MODE, BUTTONS_PRESSING_AGAINST);
// Startmode...
Mode mode = STD_MODE_NORMAL;
// Merker fuer den Modus vor der Abschaltung...
Mode lastMode = mode;
// Die Matrix, eine Art Bildschirmspeicher
word matrix[16];
// Hilfsvariable, da I2C und Interrupts nicht zusammenspielen
volatile boolean needsUpdateFromRtc = true;
// Fuer den Bildschirm-Test
byte testColumn;
// Fuer fps-Anzeige
#ifdef DEBUG
word frames = 0;
unsigned long lastFpsCheck = 0;
#endif
#ifdef USE_EXT_MODE_DCF_SYNC
// Fuer die DCF_DEBUG Anzeige
unsigned int dcf77ErrorMinutes;
#endif
// Zähler für fall back timer im Menu
byte fallBackCounter = 0;
// Indiziert, ob Event aktiv ist.
bool evtActive = false;
/**
Aenderung der Anzeige als Funktion fuer den Interrupt, der ueber das SQW-Signal
der Real-Time-Clock gesetzt wird. Da die Wire-Bibliothek benutzt wird, kann man
den Interrupt nicht direkt benutzen, sondern muss eine Hilfsvariable setzen, die
dann in loop() ausgewertet wird.
*/
void updateFromRtc() {
needsUpdateFromRtc = true;
helperSeconds++;
if (fallBackCounter > 0) {
if( mode != STD_MODE_BLANK ){
updateFallBackCounter();
}
}
#ifndef TEMP_SENS_NONE
tempSens.takeSample();
#endif
}
/**
Den freien Specher abschaetzen.
Kopiert von: http://playground.arduino.cc/Code/AvailableMemory
*/
int freeRam() {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
/**
Initialisierung. setup() wird einmal zu Beginn aufgerufen, wenn der
Arduino Strom bekommt.
*/
void setup() {
Serial.begin(SERIAL_SPEED);
// Set Timeout of 50ms for Serial.parseInt()
Serial.setTimeout(50);
DEBUG_PRINTLN(F("Qlockthree is initializing..."));
DEBUG_PRINTLN(F("... and starting in debug-mode..."));
DEBUG_FLUSH();
// DCF konfigurieren
pinMode(PIN_DCF77_PON, OUTPUT);
enableDcf(false);
#ifdef ALARM
if (settings.getEnableAlarm()) {
// als Wecker Display nicht abschalten...
TimeStamp offTime(0, 0, 0, 0, 0, 0);
TimeStamp onTime(0, 0, 0, 0, 0, 0);
}
#endif
// LED-Treiber initialisieren
ledDriver.init();
// Inhalt des Led-Treibers loeschen...
ledDriver.clearData();
// und Inhalt des Bildspeichers loeschen
renderer.clearScreenBuffer(matrix);
// wir brauchen nur 10 Zeilen...
ledDriver.setLinesToWrite(10);
// starte Wire-Library als I2C-Bus Master
Wire.begin();
// RTC-Interrupt-Pin konfigurieren
pinMode(PIN_SQW_SIGNAL, INPUT);
digitalWrite(PIN_SQW_SIGNAL, HIGH);
// DCF77-LED drei Mal als 'Hello' blinken lassen
// und Speaker piepsen kassen, falls ENABLE_ALARM eingeschaltet ist.
for (byte i = 0; i < 3; i++) {
dcf77.statusLed(true);
#ifdef ALARM
if (settings.getEnableAlarm()) {
alarm.buzz(true);
}
#endif
delay(100);
dcf77.statusLed(false);
#ifdef ALARM
if (settings.getEnableAlarm()) {
alarm.buzz(false);
}
#endif
delay(100);
}
DEBUG_PRINT(F("Compiled: "));
DEBUG_PRINT(F(__TIME__));
DEBUG_PRINT(F(" / "));
DEBUG_PRINTLN(F(__DATE__));
// RTC starten...
rtc.readTime();
if ((rtc.getSeconds() >= 60) || (rtc.getMinutes() >= 60) || (rtc.getHours() >= 24) || (rtc.getYear() < 15)) {
// Echtzeituhr enthaelt Schrott, neu mit erkennbaren Zahlen beschreiben...
DEBUG_PRINT(F("Resetting RTC..."));
rtc.set(11, 11, 1, 1, 1, 15);
rtc.setSeconds(11);
}
#ifdef TEMP_SENS_LM35
DEBUG_PRINTLN(F("Temperatursensortyp ist LM35."));
tempSens.initLM35();
#elif defined TEMP_SENS_LM335
DEBUG_PRINTLN(F("Temperatursensortyp ist LM335."));
tempSens.initLM335();
#endif
#ifdef DS1307
DEBUG_PRINTLN(F("Uhrentyp ist DS1307."));
rtc.enableSQWOnDS1307();
#elif defined DS3231
DEBUG_PRINTLN(F("Uhrentyp ist DS3231."));
rtc.enableSQWOnDS3231();
#else
Definition_des_Uhrtyps_fehlt!
In der Configuration.h muss der Uhrentyp angegeben werden!
#endif
rtc.writeTime();
helperSeconds = rtc.getSeconds();
DEBUG_PRINT(F("RTC-Time: "));
DEBUG_PRINT(rtc.getHours());
DEBUG_PRINT(F(":"));
DEBUG_PRINT(rtc.getMinutes());
DEBUG_PRINT(F(":"));
DEBUG_PRINT(helperSeconds);
DEBUG_PRINT(F(" RTC-Date: "));
DEBUG_PRINT(rtc.getDate());
DEBUG_PRINT(F("."));
DEBUG_PRINT(rtc.getMonth());
DEBUG_PRINT(F("."));
DEBUG_PRINTLN(rtc.getYear());
// Den Interrupt konfigurieren,
// nicht mehr CHANGE, das sind 2 pro Sekunde,
// RISING ist einer pro Sekunde, das reicht.
// Auf FALLING geandert, das signalisiert
// den Sekundenwechsel, Danke an Peter.
attachInterrupt(0, updateFromRtc, FALLING);
// Werte vom LDR einlesen und vermuellen, da die ersten nichts taugen...
for (int i = 0; i < 1000; i++) {
analogRead(PIN_LDR);
}
// rtcSQWLed-LED drei Mal als 'Hello' blinken lassen
// und Speaker piepsen kassen, falls ENABLE_ALARM eingeschaltet ist.
for (byte i = 0; i < 3; i++) {
rtc.statusLed(true);
#ifdef ALARM
if (settings.getEnableAlarm()) {
alarm.buzz(true);
}
#endif
delay(100);
rtc.statusLed(false);
#ifdef ALARM
if (settings.getEnableAlarm()) {
alarm.buzz(false);
}
#endif
delay(100);
}
// ein paar Infos ausgeben
DEBUG_PRINTLN(F("... done and ready to rock!"));
Serial.print(F("Version: "));
Serial.println(FIRMWARE_VERSION);
DEBUG_PRINT(F("Driver: "));
ledDriver.printSignature();
#ifndef REMOTE_NO_REMOTE
DEBUG_PRINT(F("Remote: "));
irTranslator.printSignature();
irrecv.enableIRIn();
#else
DEBUG_PRINTLN(F("Remote: disabled."));
#endif
#ifdef ALARM
if (settings.getEnableAlarm()) {
DEBUG_PRINTLN(F("Alarm is enabled"));
}
#endif
if (settings.getDcfSignalIsInverted()) {
DEBUG_PRINTLN(F("DCF77-Signal is inverted."));
}
DEBUG_PRINT(F("Free ram: "));
DEBUG_PRINT(freeRam());
DEBUG_PRINTLN(F(" bytes."));
DEBUG_FLUSH();
// DCF77-Empfaenger einschalten...
enableDcf(true);
// Display einschalten...
ledDriver.wakeUp();
ledDriver.setBrightness(settings.getBrightness());
#ifdef LED_TEST_INTRO_ENABLED
unsigned long initMillis = millis();
while((millis() - initMillis) < 5000){
renderer.setAllScreenBuffer(matrix);
ledDriver.writeScreenBufferToMatrix(matrix, true, eColors::color_white);
}
#endif
}
/**
loop() wird endlos auf alle Ewigkeit vom Microcontroller durchlaufen
*/
void loop() {
//
// FPS
//
#ifdef DEBUG
frames++;
if (lastFpsCheck > millis()) {
// wir hatten einen Ueberlauf...
lastFpsCheck = millis();
}
if (lastFpsCheck + 1000 < millis()) {
DEBUG_PRINT("FPS: ");
DEBUG_PRINTLN(frames);
lastFpsCheck = millis();
frames = 0;
}
#endif
//
// Dimmung.
//
if (settings.getUseLdr()) {
if (millis() < lastBrightnessCheck) {
// wir hatten einen Ueberlauf...
lastBrightnessCheck = millis();
}
if (lastBrightnessCheck + LDR_CHECK_RATE < millis()) { // langsam nachsehen...
byte lv = ldr.value();
if (ledDriver.getBrightness() > lv) {
ledDriver.setBrightness(ledDriver.getBrightness() - 1);
} else if (ledDriver.getBrightness() < lv) {
ledDriver.setBrightness(ledDriver.getBrightness() + 1);
}
lastBrightnessCheck = millis();
}
}
//
// needsUpdateFromRtc wird via Interrupt gesetzt ueber fallende
// Flanke des SQW-Signals von der RTC.
// Oder falls eine Tasten-Aktion eine sofortige Aktualisierung des Displays braucht.
//
if (needsUpdateFromRtc) {
needsUpdateFromRtc = false;
//
// Zeit einlesen...
// ... nur alle 60 Sekunden, um die Minuten und evtl. Stunden zu aktualisieren.
//
if (helperSeconds > 59) {
rtc.readTime();
helperSeconds = rtc.getSeconds();
}
//
// Bildschirmpuffer beschreiben...
//
switch (mode) {
case STD_MODE_NORMAL:
// Event Abfrage
#ifdef EVENTS
byte evtMode;
switch (settings.getEvent()) {
case 0:
evtMode = 5;
break;
case 1:
evtMode = 15;
break;
case 2:
evtMode = 30;
break;
case 3:
evtMode = 45;
break;
case 4:
evtMode = 60;
break;
default:
evtMode = 255;
break;
}
while (!(rtc.getMinutes() % evtMode)) {
for (byte evtID = 0; evtID < EVENT::nbrOfEvts; evtID++) {
Serial.print(evtID);Serial.print(": ");
const Event * e = pgm_read_word_near(&events[evtID]);
if (EVENT::checkDate(e, rtc.getDate(), rtc.getMonth())) {
evtActive = true;
EVENT::show(e);
}
}
rtc.readTime();
if(!evtActive) {
break;
}
}
evtActive = false;
#endif
case EXT_MODE_TIMESET:
renderer.clearScreenBuffer(matrix);
renderer.setMinutes(rtc.getHours() + settings.getTimeShift(), rtc.getMinutes(), settings.getLanguage(), matrix);
renderer.setCorners(rtc.getMinutes(), settings.getRenderCornersCw(), matrix);
break;
#ifdef USE_EXT_MODE_TIME_SHIFT
case EXT_MODE_TIME_SHIFT:
renderer.clearScreenBuffer(matrix);
if (settings.getTimeShift() < 0) {
for (byte x = 0; x < 3; x++) {
ledDriver.setPixelInScreenBuffer(x, 1, matrix);
}
} else if (settings.getTimeShift() > 0) {
for (byte x = 0; x < 3; x++) {
ledDriver.setPixelInScreenBuffer(x, 1, matrix);
}
for (byte y = 0; y < 3; y++) {
ledDriver.setPixelInScreenBuffer(1, y, matrix);
}
}
for (byte i = 0; i < 7; i++) {
matrix[3 + i] |= pgm_read_byte_near(&(ziffern[abs(settings.getTimeShift()) % 10][i])) << 5;
if (abs(settings.getTimeShift()) > 9) {
matrix[3 + i] |= pgm_read_byte_near(&(ziffern[1][i])) << 10;
}
}
break;
#endif
#ifdef ALARM
case STD_MODE_ALARM:
renderer.clearScreenBuffer(matrix);
if (alarm.getShowAlarmTimeTimer() == 0) {
renderer.setMinutes(rtc.getHours() + settings.getTimeShift(), rtc.getMinutes(), settings.getLanguage(), matrix);
renderer.setCorners(rtc.getMinutes(), settings.getRenderCornersCw(), matrix);
renderer.activateAlarmLed(matrix); // Alarm-LED
} else {
renderer.setMinutes(alarm.getHours() + settings.getTimeShift(), alarm.getMinutes(), settings.getLanguage(), matrix);
renderer.setCorners(alarm.getMinutes(), settings.getRenderCornersCw(), matrix);
renderer.cleanWordsForAlarmSettingMode(settings.getLanguage(), matrix); // ES IST weg
if (alarm.getShowAlarmTimeTimer() % 2 == 0) {
renderer.activateAlarmLed(matrix); // Alarm-LED
}
alarm.decShowAlarmTimeTimer();
}
break;
#endif
#ifdef USE_STD_MODE_DATE
case STD_MODE_DATE:
renderer.clearScreenBuffer(matrix);
// Anzeige des Datums
for (byte i = 0; i < 5; i++) {
matrix[0 + i] |= pgm_read_byte_near(&(ziffernB[rtc.getDate() / 10][i])) << 11;
matrix[0 + i] |= pgm_read_byte_near(&(ziffernB[rtc.getDate() % 10][i])) << 6;
matrix[5 + i] |= pgm_read_byte_near(&(ziffernB[rtc.getMonth() / 10][i])) << 11;
matrix[5 + i] |= pgm_read_byte_near(&(ziffernB[rtc.getMonth() % 10][i])) << 6;
}
ledDriver.setPixelInScreenBuffer(10, 4, matrix);
ledDriver.setPixelInScreenBuffer(10, 9, matrix);
break;
#endif
#ifdef USE_STD_MODE_TEMP
case STD_MODE_TEMP:
Serial.println(tempSens.getTempC());
renderer.clearScreenBuffer(matrix);