-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMulti_Clock_1_5_5.ino
3245 lines (2683 loc) · 91.3 KB
/
Multi_Clock_1_5_5.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
/***********************************************************************
Multi Clock v 1.5.5, Jan 2016 by SRDWA
Distributed under the terms of the GPL.
Based on Pong Clock v 5.1 by Nick Hall
For more informations and original Release Notes visit:
http://123led.wordpress.com/
-----------------------------------------------------------------------
Release Notes for v1.0 , updated January 2016 by SRDWA:
*rename from Prong Clock tu Multi Clock and initial release of Multi Clock
*lot of changes which SRDWA does, and i can't restore because
*start translating the Menus to german
-----------------------------------------------------------------------
Release Notes for v1.1 , updated April 2016 by NeoRame:
*add new german translatings
-----------------------------------------------------------------------
Release Notes for v1.2 , updated April 2016 by NeoRame:
* adding the "Special Event" function from Matock to display a welcome message every 30 min on specific
days (ex: New Year Day, Christmas, etc..., cf. is_special_event() function)
* rename some Settings
* remove Word Clock
* add Temperature to "Print Day of Week" Screen
* add new tiny chars
* tiny Font for Menu and Settings
-----------------------------------------------------------------------
Release Notes for v1.4 , updated April 2016 by NeoRame:
* edit Random Menu
* edit Invaders Watchface
* edit Normal Watchface
* edit Temperature Watchface
* remove Matrix Watchface
* add new icons to Temperature
-----------------------------------------------------------------------
Release Notes for v1.5 , updated April 2016 by NeoRame:
* add new created Icon Font
* edit the way of showing icons on Weather Watchface
* add new icons for Special Events ;)
* add Special Events on Weather Watchface
* delete 12/24h Menu
-----------------------------------------------------------------------
Release Notes for v1.5.3 , updated April 2016 by NeoRame:
* add new created Invaders Font
* edit the way the invaders are created (new font)
* edit the 7px invaders spaceschips to 8px original design
* change the big font to a new 6x14 big font
* add Binary Watchface [BCD Style (Binary Coded Decimal)]
* add BCD Font
-----------------------------------------------------------------------
Release Notes for v1.5.4 , updated May 2016 by NeoRame:
* change Digits Watchface
-----------------------------------------------------------------------
Release Notes for v1.5.5 , updated October 2016 by NeoRame:
* add Halloween Special Event
* some cosmetic changes
-----------------------------------------------------------------------
Uses 2x Sure 2416 LED modules, arduino and DS1307 clock chip.
Distributed under the terms of the GPL.
Holtek HT1632 LED driver chip code:
As implemented on the Sure Electronics DE-DP016 display board (16*24 dot matrix LED module.)
Nov, 2008 by Bill Westfield ("WestfW")
Copyrighted and distributed under the terms of the Berkely license (copy freely, but include this notice of original author.)
***********************************************************************/
//include libraries
#include <ht1632c.h> // Holtek LED driver by WestFW - updated to HT1632C by Nick Hall
#include <avr/pgmspace.h> // Enable data to be stored in Flash Mem as well as SRAM
#include <Font.h> // Font library
#include <Wire.h> // DS1307 clock
#include "RTClib.h" // DS1307 clock
#include <Button.h> // Button library by Alexander Brevig
//define constants
#define ASSERT(condition) // Nothing
#define X_MAX 47 // Matrix X max LED coordinate (for 2 displays placed next to each other)
#define Y_MAX 15 // Matrix Y max LED coordinate (for 2 displays placed next to each other)
#define NUM_DISPLAYS 2 // Num displays for shadow ram data allocation
#define FADEDELAY 30 // Time to fade display to black
#define NUM_MODES 10 // Number of clock & display modes (conting zero as the first mode)
#define NUM_SETTINGS_MODES 4 // Number settings modes = 6 (conting zero as the first mode)
#define NUM_DISPLAY_MODES 6 // Number display modes = 5 (conting zero as the first mode)
#define BAT1_X 2 // Pong left bat x pos (this is where the ball collision occurs, the bat is drawn 1 behind these coords)
#define BAT2_X 45 // Pong right bat x pos (this is where the ball collision occurs, the bat is drawn 1 behind these coords)
#define plot(x,y,v) ht1632_plot(x,y,v) // Plot LED
#define cls ht1632_clear // Clear display
#define SLIDE_DELAY 20 // The time in milliseconds for the slide effect per character in slide mode. Make this higher for a slower effect
#define NEXT_DATE_MIN 10 // After the date has been displayed automatically, the next time it's displayed is at least 10 mintues later
#define NEXT_DATE_MAX 15 // After the date has been displayed automatically, the next time it's displayed is at most 15 mintues later
//global variables
static const byte ht1632_data = 10; // Data pin for sure module
static const byte ht1632_wrclk = 11; // Write clock pin for sure module
static const byte ht1632_cs[2] = {4,5}; // Chip_selects one for each sure module. Remember to set the DIP switches on the modules too.
Button buttonA = Button(2,BUTTON_PULLUP); // Setup button A (using button library)
Button buttonB = Button(3,BUTTON_PULLUP); // Setup button B (using button library)
RTC_DS1307 ds1307; //RTC object
int rtc[7]; // Holds real time clock output
byte clock_mode = 0; // Default clock mode. Default = 0 (Invaders)
byte old_mode = clock_mode; // Stores the previous clock mode, so if we go to date or whatever, we know what mode to go back to after.
bool ampm = 0; // Define 12 or 24 hour time. 0 = 24 hour. 1 = 12 hour
bool random_mode = 1; // Define random mode - changes the display type every hours. Default = 0 (on)
bool daylight_mode = 0; // Define if DST is on or off. Default = 0 (off).
byte change_mode_time = 0; // Holds hour when clock mode will next change if in random mode.
byte brightness = 9; // Screen brightness - default is 15 which is brightest.
byte next_display_date; // Holds the minute at which the date is automatically next displayed
byte old_mins = 99; // holds minutes when the last special event was displayed
char days[7][4] = {
"So.","Mo.","Di.", "Mi.", "Do.", "Fr.", "Sa."}; //day array - used in slide, normal and matrix modes (The DS1307 outputs 1-7 values for day of week)
char daysfull[7][9]={
"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donner.", "Freitag", "Samstag" };
int TMP36 = A0;
int temperatur = 0;
int temp[10];
int tempcorr = 3; // If your Temerature are incorecct adjust here
//intial setup
void setup ()
{
digitalWrite(2, HIGH); // turn on pullup resistor for button on pin 2
digitalWrite(3, HIGH); // turn on pullup resistor for button on pin 3
Serial.begin(57600); // Setup serial output
ht1632_setup(); // Setup display (uses flow chart from page 17 of sure datasheet)
randomSeed(analogRead(1)); // Setup random number generator
ht1632_sendcmd(0, HT1632_CMD_PWM + brightness);
ht1632_sendcmd(1, HT1632_CMD_PWM + brightness);
//Setup DS1307 RTC
#ifdef AVR
Wire.begin();
#else
Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino
#endif
ds1307.begin(); //start RTC Clock
if (! ds1307.isrunning()) {
Serial.println(F("RTC is NOT running!"));
ds1307.adjust(DateTime(__DATE__, __TIME__)); // sets the RTC to the date & time this sketch was compiled
}
printver(); // Display clock software version
}
// ****** MAIN LOOP ******
void loop ()
{
//run the clock with whatever mode is set by clock_mode - the default is set at top of code.
switch (clock_mode){
case 0:
invaders();
break;
case 1:
pong();
break;
case 2:
digits();
break;
case 3:
normal();
break;
case 4:
thermo();
break;
case 5:
slide();
break;
case 6:
binary();
break;
case 7:
setup_menu();
break;
}
}
// ****** DISPLAY-ROUTINES ******
//ht1632_chipselect / ht1632_chipfree
//Select or de-select a particular ht1632 chip. De-selecting a chip ends the commands being sent to a chip.
//CD pins are active-low; writing 0 to the pin selects the chip.
void ht1632_chipselect(byte chipno)
{
DEBUGPRINT("\nHT1632(%d) ", chipno);
digitalWrite(chipno, 0);
}
void ht1632_chipfree(byte chipno)
{
DEBUGPRINT(" [done %d]", chipno);
digitalWrite(chipno, 1);
}
//ht1632_writebits
//Write bits (up to 8) to h1632 on pins ht1632_data, ht1632_wrclk Chip is assumed to already be chip-selected
//Bits are shifted out from MSB to LSB, with the first bit sent being (bits & firstbit), shifted till firsbit is zero.
void ht1632_writebits (byte bits, byte firstbit)
{
DEBUGPRINT(" ");
while (firstbit) {
DEBUGPRINT((bits&firstbit ? "1" : "0"));
digitalWrite(ht1632_wrclk, LOW);
if (bits & firstbit) {
digitalWrite(ht1632_data, HIGH);
}
else {
digitalWrite(ht1632_data, LOW);
}
digitalWrite(ht1632_wrclk, HIGH);
firstbit >>= 1;
}
}
// ht1632_sendcmd
// Send a command to the ht1632 chip. A command consists of a 3-bit "CMD" ID, an 8bit command, and one "don't care bit".
// Select 1 0 0 c7 c6 c5 c4 c3 c2 c1 c0 xx Free
static void ht1632_sendcmd (byte d, byte command)
{
ht1632_chipselect(ht1632_cs[d]); // Select chip
ht1632_writebits(HT1632_ID_CMD, 1<<2); // send 3 bits of id: COMMMAND
ht1632_writebits(command, 1<<7); // send the actual command
ht1632_writebits(0, 1); // one extra dont-care bit in commands.
ht1632_chipfree(ht1632_cs[d]); //done
}
//ht1632_senddata
//send a nibble (4 bits) of data to a particular memory location of the
//ht1632. The command has 3 bit ID, 7 bits of address, and 4 bits of data.
// Select 1 0 1 A6 A5 A4 A3 A2 A1 A0 D0 D1 D2 D3 Free
//Note that the address is sent MSB first, while the data is sent LSB first!
//This means that somewhere a bit reversal will have to be done to get
//zero-based addressing of words and dots within words.
static void ht1632_senddata (byte d, byte address, byte data)
{
ht1632_chipselect(ht1632_cs[d]); // Select chip
ht1632_writebits(HT1632_ID_WR, 1<<2); // Send ID: WRITE to RAM
ht1632_writebits(address, 1<<6); // Send address
ht1632_writebits(data, 1<<3); // Send 4 bits of data
ht1632_chipfree(ht1632_cs[d]); // Done.
}
//ht1632_setup
//setup the ht1632 chips
void ht1632_setup()
{
for (byte d=0; d<NUM_DISPLAYS; d++) {
pinMode(ht1632_cs[d], OUTPUT);
digitalWrite(ht1632_cs[d], HIGH); // Unselect (active low)
pinMode(ht1632_wrclk, OUTPUT);
pinMode(ht1632_data, OUTPUT);
ht1632_sendcmd(d, HT1632_CMD_SYSON); // System on
ht1632_sendcmd(d, HT1632_CMD_LEDON); // LEDs on
ht1632_sendcmd(d, HT1632_CMD_COMS01); // NMOS Output 24 row x 24 Com mode
for (byte i=0; i<128; i++)
ht1632_senddata(d, i, 0); // clear the display!
}
}
//we keep a copy of the display controller contents so that we can know which bits are on without having to (slowly) read the device.
//Note that we only use the low four bits of the shadow ram, since we're shadowing 4-bit memory. This makes things faster, and we
//use the other half for a "snapshot" when we want to plot new data based on older data...
byte ht1632_shadowram[NUM_DISPLAYS * 96]; // our copy of the display's RAM
//plot a point on the display, with the upper left hand corner being (0,0).
//Note that Y increases going "downward" in contrast with most mathematical coordiate systems, but in common with many displays
//No error checking; bad things may happen if arguments are out of bounds! (The ASSERTS compile to nothing by default
void ht1632_plot (char x, char y, char val)
{
char addr, bitval;
ASSERT(x >= 0);
ASSERT(x <= X_MAX);
ASSERT(y >= 0);
ASSERT(y <= y_MAX);
byte d;
//select display depending on plot values passed in
if (x >= 0 && x <=23 ) {
d = 0;
}
if (x >=24 && x <=47) {
d = 1;
x = x-24;
}
/*
* The 4 bits in a single memory word go DOWN, with the LSB (first transmitted) bit being on top. However, writebits()
* sends the MSB first, so we have to do a sort of bit-reversal somewhere. Here, this is done by shifting the single bit in
* the opposite direction from what you might expect.
*/
bitval = 8>>(y&3); // compute which bit will need set
addr = (x<<2) + (y>>2); // compute which memory word this is in
if (val) { // Modify the shadow memory
ht1632_shadowram[(d * 96) + addr] |= bitval;
}
else {
ht1632_shadowram[(d * 96) + addr] &= ~bitval;
}
// Now copy the new memory value to the display
ht1632_senddata(d, addr, ht1632_shadowram[(d * 96) + addr]);
}
//get_shadowram
//return the value of a pixel from the shadow ram.
byte get_shadowram(byte x, byte y)
{
byte addr, bitval, d;
//select display depending on plot values passed in
if (x >= 0 && x <=23 ) {
d = 0;
}
if (x >=24 && x <=47) {
d = 1;
x = x-24;
}
bitval = 8>>(y&3); // compute which bit will need set
addr = (x<<2) + (y>>2); // compute which memory word this is in
return (0 != (ht1632_shadowram[(d * 96) + addr] & bitval));
}
//snapshot_shadowram
//Copy the shadow ram into the snapshot ram (the upper bits)
//This gives us a separate copy so we can plot new data while
//still having a copy of the old data. snapshotram is NOT
//updated by the plot functions (except "clear")
void snapshot_shadowram()
{
for (byte i=0; i< sizeof ht1632_shadowram; i++) {
ht1632_shadowram[i] = (ht1632_shadowram[i] & 0x0F) | ht1632_shadowram[i] << 4; // Use the upper bits
}
}
//get_snapshotram
//get a pixel value from the snapshot ram (instead of
//the actual displayed (shadow) memory
byte get_snapshotram(byte x, byte y)
{
byte addr, bitval;
byte d = 0;
//select display depending on plot values passed in
if (x >=24 && x <=47) {
d = 1;
x = x-24;
}
bitval = 128>>(y&3); // user upper bits!
addr = (x<<2) + (y>>2); // compute which memory word this is in
if (ht1632_shadowram[(d * 96) + addr] & bitval)
return 1;
return 0;
}
//ht1632_clear
//clear the display, and the shadow memory, and the snapshot
//memory. This uses the "write multiple words" capability of
//the chipset by writing all 96 words of memory without raising
//the chipselect signal.
void ht1632_clear()
{
char i;
for(byte d=0; d<NUM_DISPLAYS; d++)
{
ht1632_chipselect(ht1632_cs[d]); // Select chip
ht1632_writebits(HT1632_ID_WR, 1<<2); // send ID: WRITE to RAM
ht1632_writebits(0, 1<<6); // Send address
for (i = 0; i < 96/2; i++) // Clear entire display
ht1632_writebits(0, 1<<7); // send 8 bits of data
ht1632_chipfree(ht1632_cs[d]); // done
for (i=0; i < 96; i++)
ht1632_shadowram[96*d + i] = 0;
}
}
/*
* fade_down
* fade the display to black
*/
void fade_down() {
char intensity;
for (intensity=brightness; intensity >= 0; intensity--) {
ht1632_sendcmd(0, HT1632_CMD_PWM + intensity); //send intensity commands using CS0 for display 0
ht1632_sendcmd(1, HT1632_CMD_PWM + intensity); //send intensity commands using CS0 for display 1
delay(FADEDELAY);
}
//clear the display and set it to full brightness again so we're ready to plot new stuff
cls();
ht1632_sendcmd(0, HT1632_CMD_PWM + brightness);
ht1632_sendcmd(1, HT1632_CMD_PWM + brightness);
}
/*
* fade_up
* fade the display up to full brightness
*/
void fade_up() {
char intensity;
for ( intensity=0; intensity < brightness; intensity++) {
ht1632_sendcmd(0, HT1632_CMD_PWM + intensity); //send intensity commands using CS0 for display 0
ht1632_sendcmd(1, HT1632_CMD_PWM + intensity); //send intensity commands using CS0 for display 1
delay(FADEDELAY);
}
}
/* ht1632_putchar
* Copy a 5x7 character glyph from the myfont data structure to display memory, with its upper left at the given coordinate
* This is unoptimized and simply uses plot() to draw each dot.
*/
void ht1632_putchar(byte x, byte y, char c)
{
byte dots;
// if (c >= 'A' && c <= 'Z' || (c >= 'a' && c <= 'z') ) {
// c &= 0x1F; // A-Z maps to 1-26
// }
if (c >= 'A' && c <= 'Z' ) {
c &= 0x1F; // A-Z maps to 1-26
}
else if (c >= 'a' && c <= 'z') {
c = (c - 'a') + 41; // A-Z maps to 41-67
}
else if (c >= '0' && c <= '9') {
c = (c - '0') + 31;
}
else if (c == ' ') {
c = 0; // space
}
else if (c == '.') {
c = 27; // full stop
}
else if (c == '/') {
c = 28; // single quote mark
}
else if (c == ':') {
c = 29; // clock_mode selector arrow
}
else if (c == '>') {
c = 30; // clock_mode selector arrow
}
else if (c == '#') {
c = 67; // grad celsius
}
else if (c == ';') {
c = 68; // ä
}
else if (c == ',') {
c = 69; // ü
}
for (char col=0; col< 5; col++) {
dots = pgm_read_byte_near(&myfont[c][col]);
for (char row=0; row < 7; row++) {
//check coords are on screen before trying to plot
if ((x >= 0) && (x <= X_MAX) && (y >= 0) && (y <= Y_MAX)){
if (dots & (64>>row)) { // only 7 rows.
plot(x+col, y+row, 1);
} else {
plot(x+col, y+row, 0);
}
}
}
}
}
//ht1632_putbigchar
//Copy a 6x14 character glyph from the myfont data structure to display memory, with its upper left at the given coordinate
//This is unoptimized and simply uses plot() to draw each dot.
void ht1632_putbigchar(byte x, byte y, char c)
{
byte dots;
if (c >= 'A' && c <= 'Z' || (c >= 'a' && c <= 'z') ) {
return; //return, as the 10x14 font contains only numeric characters
}
if (c >= '0' && c <= '9') {
c = (c - '0');
c &= 0x1F;
}
for (byte col=0; col< 6; col++) {
dots = pgm_read_byte_near(&mybigfont[c][col]);
for (char row=0; row < 8; row++) {
if (dots & (128>>row))
plot(x+col, y+row, 1);
else
plot(x+col, y+row, 0);
}
dots = pgm_read_byte_near(&mybigfont[c][col+6]);
for (char row=0; row < 8; row++) {
if (dots & (128>>row))
plot(x+col, y+row+8, 1);
else
plot(x+col, y+row+8, 0);
}
}
}
// ht1632_puttinychar
// Copy a 3x5 character glyph from the myfont data structure to display memory, with its upper left at the given coordinate
// This is unoptimized and simply uses plot() to draw each dot.
void ht1632_puttinychar(byte x, byte y, char c)
{
byte dots;
if (c >= 'A' && c <= 'Z' || (c >= 'a' && c <= 'z') ) {
c &= 0x1F; // A-Z maps to 1-26
}
else if (c >= '0' && c <= '9') {
c = (c - '0') + 31;
}
else if (c == ' ') {
c = 0; // space
}
else if (c == '.') {
c = 27; // full stop
}
else if (c == '/') {
c = 28; // single quote mark
}
else if (c == '!') {
c = 29; // single quote mark
}
else if (c == '?') {
c = 30; // single quote mark
}
// add symbols
else if (c == '-') {
c = 41; // minus
}
else if (c == '>') {
c = 42; // arrow
}
for (byte col=0; col< 3; col++) {
dots = pgm_read_byte_near(&mytinyfont[c][col]);
for (char row=0; row < 5; row++) {
if (dots & (16>>row))
plot(x+col, y+row, 1);
else
plot(x+col, y+row, 0);
}
}
}
//ht1632_puticonchar
//Copy a 11x11 character glyph from the myfont data structure to display memory, with its upper left at the given coordinate
//This is unoptimized and simply uses plot() to draw each dot.
void ht1632_puticonchar(byte x, byte y, char c)
{
byte dots;
if (c == ' ') {
c = 0; // space
}
else if (c == '1') {
c = 1; // Sun
}
else if (c == '2') {
c = 2; // Moon
}
else if (c == '3') {
c = 3; // Ghost
}
else if (c == '4') {
c = 4; // Scull
}
else if (c == '5') {
c = 5; // B-Day Present
}
else if (c == '6') {
c = 6; // XMAS Tree
}
else if (c == '7') {
c = 7; // Dont Panic
}
else if (c == '8') {
c = 8; // Schniblo
}
else if (c == '9') {
c = 9; // Kitty
}
else if (c == 'a') {
c = 10; // Beer
}
for (byte col=0; col< 11; col++) {
dots = pgm_read_byte_near(&myiconfont[c][col]);
for (char row=0; row < 8; row++) {
if (dots & (128>>row))
plot(x+col, y+row, 1);
else
plot(x+col, y+row, 0);
}
dots = pgm_read_byte_near(&myiconfont[c][col+11]);
for (char row=0; row < 8; row++) {
if (dots & (128>>row))
plot(x+col, y+row+8, 1);
else
plot(x+col, y+row+8, 0);
}
}
}
//ht1632_invaders
//Copy the 8x12 character glyph from the myfont data structure to display memory, with its upper left at the given coordinate
//This is unoptimized and simply uses plot() to draw each dot.
void ht1632_invaders(byte x, byte y, char c)
{
byte dots;
if (c == ' ') {
c = 0; // space
}
else if (c >= -9 && c<= -2) {
c *= -1;
}
for (char col=0; col< 12; col++) {
dots = pgm_read_byte_near(&myinvaders[c][col]);
for (char row=0; row < 8; row++) {
//check coords are on screen before trying to plot
if ((x >= 0) && (x <= X_MAX) && (y >= 0) && (y <= Y_MAX)){
if (dots & (128>>row)) { // only 8 rows.
plot(x+col, y+row, 1);
} else {
plot(x+col, y+row, 0);
}
}
}
}
}
//ht1632_putbinarychar
//Copy a 3x16 character glyph from the myfont data structure to display memory, with its upper left at the given coordinate
//This is unoptimized and simply uses plot() to draw each dot.
void ht1632_putbinarychar(byte x, byte y, char c)
{
byte dots;
if (c >= 'A' && c <= 'Z' || (c >= 'a' && c <= 'z') ) {
return; //return, as the 10x14 font contains only numeric characters
}
if (c >= '0' && c <= '9') {
c = (c - '0');
c &= 0x1F;
}
for (byte col=0; col< 3; col++) {
dots = pgm_read_byte_near(&mybinaryfont[c][col]);
for (char row=0; row < 8; row++) {
if (dots & (128>>row))
plot(x+col, y+row, 1);
else
plot(x+col, y+row, 0);
}
dots = pgm_read_byte_near(&mybinaryfont[c][col+3]);
for (char row=0; row < 8; row++) {
if (dots & (128>>row))
plot(x+col, y+row+8, 1);
else
plot(x+col, y+row+8, 0);
}
}
}
//************ CLOCK MODES ***************
void invaders()
{
byte hours = 0;
byte mins = 0;
byte old_mins = 100; // holds old seconds value - from last time seconds were updated o display - used to check if seconds have changed
cls();
// run clock main loop as long as run_mode returns true
while (run_mode()) {
// check buttons
if (buttonA.wasPressed()) {
switch_mode();
return; // exit this mode back to loop(), so the new clock mode function is called
}
if (buttonB.wasPressed()) {
display_date();
fade_down();
return; // exit this mode back to loop(), then we re-enter the function and the clock mode starts again. This refreshes the display.
}
// get the time from the clock chip
get_time();
// udate mins and hours with the new time
mins = rtc[1];
hours = rtc[2];
//print "Score"
byte i = 0;
char text[9] = "SCORE 00";
while(text[i]) {
ht1632_puttinychar((i*4), 0, text[i]);
i++;
}
plot(20,1,1);
plot(20,3,1);
// do 12/24 hour conversion if ampm set to 1
if (hours > 12) {
hours = hours - ampm * 12;
}
if (hours < 1) {
hours = hours + ampm * 12;
}
// if mins changed then update them on the display
if (mins != old_mins) {
char buffer[3];
// convert hours to string
itoa(hours, buffer, 10);
// fix - as otherwise if num has leading zero, e.g. "03" hours, itoa coverts this to chars with space "3 "
if (hours < 10) {
buffer[1] = buffer[0];
// if we are in 12 hour mode blank the leading zero
if (ampm) {
buffer[0] = '0';
}
else{
buffer[0] = '0';
}
}
// update the display
ht1632_puttinychar(32, 0, buffer[0]);
ht1632_puttinychar(36, 0, buffer[1]);
// convert mins to string
itoa(mins, buffer, 10);
// fix - as otherwise if num has leading zero, e.g. "03" mins, itoa converts this to chars with space "3 "
if (mins < 10) {
buffer[1] = buffer[0];
buffer[0] = '0';
}
// update the display
ht1632_puttinychar(40, 0, buffer[0]);
ht1632_puttinychar(44, 0, buffer[1]);
old_mins = mins;
}
byte invader_typ = random(1, 4);
// scroll from left to right
if (! scroll_invader(7, 0, 36,invader_typ)) {
return;
}
// then, scroll from right to left
if (! scroll_invader(7, 36, 0, invader_typ)) {
return;
}
delay(50);
}
fade_down();
}
// (called by invaders)
boolean scroll_invader (byte ypos, char xstart, char xend, byte invader_type)
{
boolean wiggle = false;
char xstep;
char xreset;
if (xstart < xend) {
xstep = 1;
xreset = -1;
}
else {
xstep = -1;
xreset = 12;
}
for (char i = xstart; i != (xend + xstep); i += xstep) {
// check buttons
if (buttonA.uniquePress() || buttonB.uniquePress()) {
return false;
}
display_invader(i, ypos, invader_type, wiggle);
wiggle = (!wiggle);
// display off the column at the left or the right of the glyph (for moving effect)
for (byte y = ypos; y < ypos + 8; y++) {
// check coords are on screen before trying to plot
if ((i + xreset >= 0) && (i + xreset <= X_MAX) && (y >= 0) && (y <= Y_MAX)) {
plot(i + xreset, y, 0);
}
}
delay(100);
}
return true;
}
// (called by scroll_invader)
void display_invader (byte xpos, byte ypos, byte invader_type, boolean wiggle)
{
// base invaders are at: -67, -71, -75 wiggle is -2 from each
char invader = -1 - (invader_type*2);
if (wiggle) {
invader -= 1;
}
// update the display
ht1632_invaders(xpos, ypos, invader);
// ht1632_invaders(xpos+5, ypos, invader-1);
}
// digits()
// show the time in 6x14 characters and update it whilst the loop runs
void digits()
{
cls();
char buffer[3]; //for int to char conversion to turn rtc values into chars we can print on screen
byte offset = 0; //used to offset the x postition of the digits and centre the display when we are in 12 hour mode and the clock shows only 3 digits. e.g. 3:21
byte x, y; //used to draw a clear box over the left hand "1" of the display when we roll from 12:59 -> 1:00am in 12 hour mode.
//do 12/24 hour conversion if ampm set to 1
byte hours = rtc[2];
if (hours > 12) {
hours = hours - ampm * 12;
}
if (hours < 1) {
hours = hours + ampm * 12;
}
//set the next minute we show the date at
set_next_date();
// initially set mins to value 100 - so it wll never equal rtc[1] on the first loop of the clock, meaning we draw the clock display when we enter the function
byte secs = rtc[0]; //seconds
byte old_secs = secs; //holds old seconds value - from last time seconds were updated o display - used to check if seconds have changed
byte mins = 100;
int count = 0;
//run clock main loop as long as run_mode returns true
while (run_mode()) {
//get the time from the clock chip
get_time();
//check to see if the buttons have been pressed
if (buttonA.uniquePress()) {
switch_mode(); // pick the new mode via the menu
return; //exit this mode back to loop(), so the new clock mode function is called.
}
if (buttonB.uniquePress()) {
display_date();
fade_down();
return; //exit the mode back to loop(), Then we reenter the function and the clock mode starts again. This refreshes the display
}
if (is_special_event()) {
fade_down();
return; // exit this mode back to loop(), then we re-enter the function and the clock mode starts again. This refreshes the display.
}
//check whether it's time to automatically display the date
check_show_date();
//draw the flashing : as on if the secs have changed.
if (secs != rtc[0]) {
//update secs with new value
secs = rtc[0];
//draw :
plot (20 - offset, 13, 1); //bottom point
plot (20 - offset, 14, 1);
plot (21 - offset, 13, 1);
plot (21 - offset, 14, 1);
count = 400;
}
//if count has run out, turn off the :
if (count == 0) {
plot (20 - offset, 13, 0); //bottom point
plot (20 - offset, 14, 0);
plot (21 - offset, 13, 0);
plot (21 - offset, 14, 0);
}
else {
count--;
}
//re draw the display if mins != rtc[1] i.e. if the time has changed from what we had stored in mins, (also trigggered on first entering function when mins is 100)
if (mins != rtc[1]) {
//update secs, mins and hours with the new values
secs = rtc[0];
mins = rtc[1];
hours = rtc[2];
//adjust hours of ampm set to 12 hour mode
if (hours > 12) {
hours = hours - ampm * 12;
}
if (hours < 1) {
hours = hours + ampm * 12;
}
itoa(hours, buffer, 10);
//if hours < 10 the num e.g. "3" hours, itoa coverts this to chars with space "3 " which we dont want
if (hours < 10) {
buffer[1] = buffer[0];
buffer[0] = '0';
}
//print hours
//if we in 12 hour mode and hours < 10, then don't print the leading zero, and set the offset so we centre the display with 3 digits.
if (ampm && hours < 10) {
offset = 5;
//if the time is 1:00am clear the entire display as the offset changes at this time and we need to blank out the old 12:59
if ((hours == 1 && mins == 0) ) {
cls();
}
}
else {
//else no offset and print hours tens digit
offset = 0;
//if the time is 10:00am clear the entire display as the offset changes at this time and we need to blank out the old 9:59
if (hours == 10 && mins == 0) {
cls();
}
ht1632_putbigchar(4, 1, buffer[0]);
}