-
Notifications
You must be signed in to change notification settings - Fork 2
/
WordClock.ino
371 lines (326 loc) · 9.69 KB
/
WordClock.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
/*
Copyright 2014 Daniel Esteban - [email protected]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <Wire.h>
// Arduino pins to connect to MAX7219
int dataIn = 2;
int load = 3;
int clock = 5;
// Buttons to change the time without need of a computer
int hourBtn = 12;
int minuteBtn = 11;
boolean hourState = 0;
boolean minState = 0;
// Default time
int hours = 0;
int minutes = 0;
int seconds = 0;
int maxInUse = 1;
int e = 0; // just a varialble
// define max7219 registers - DO NOT TOUCH unless you know what you're doing
byte max7219_reg_noop = 0x00;
byte max7219_reg_digit0 = 0x01;
byte max7219_reg_digit1 = 0x02;
byte max7219_reg_digit2 = 0x03;
byte max7219_reg_digit3 = 0x04;
byte max7219_reg_digit4 = 0x05;
byte max7219_reg_digit5 = 0x06;
byte max7219_reg_digit6 = 0x07;
byte max7219_reg_digit7 = 0x08;
byte max7219_reg_decodeMode = 0x09;
byte max7219_reg_intensity = 0x0a;
byte max7219_reg_scanLimit = 0x0b;
byte max7219_reg_shutdown = 0x0c;
byte max7219_reg_displayTest = 0x0f;
//*******************************
// AUX. FUNCTION TO HANDLE MAX7219 EASILY
// I left original comments there
//*******************************
void putByte(byte data) {
byte i = 8;
byte mask;
while(i > 0) {
mask = 0x01 << (i - 1); // get bitmask
digitalWrite( clock, LOW); // tick
if (data & mask){ // choose bit
digitalWrite(dataIn, HIGH);// write 1
}else{
digitalWrite(dataIn, LOW); // write 0
}
digitalWrite(clock, HIGH); // tock
--i; // move to lesser bit
}
}
void maxSingle( byte reg, byte col) {
//maxSingle is the "easy" function to use for a //single max7219
digitalWrite(load, LOW); // begin
putByte(reg); // specify register
putByte(col);//((data & 0x01) * 256) + data >> 1); // put data
digitalWrite(load, LOW); // and load da shit
digitalWrite(load,HIGH);
}
void maxAll (byte reg, byte col) { // initialize all MAX7219's in the system
int c = 0;
digitalWrite(load, LOW); // begin
for ( c =1; c<= maxInUse; c++) {
putByte(reg); // specify register
putByte(col);//((data & 0x01) * 256) + data >> 1); // put data
}
digitalWrite(load, LOW);
digitalWrite(load,HIGH);
}
void maxOne(byte maxNr, byte reg, byte col) {
//maxOne is for adressing different MAX7219's,
//whilele having a couple of them cascaded
int c = 0;
digitalWrite(load, LOW); // begin
for ( c = maxInUse; c > maxNr; c--) {
putByte(0); // means no operation
putByte(0); // means no operation
}
putByte(reg); // specify register
putByte(col);//((data & 0x01) * 256) + data >> 1); // put data
for ( c =maxNr-1; c >= 1; c--) {
putByte(0); // means no operation
putByte(0); // means no operation
}
digitalWrite(load, LOW); // and load da shit
digitalWrite(load,HIGH);
}
//*******************************
// END OF AUX MAX7219 FUNCTIONS
//*******************************
void setup () {
// MAX 7219
pinMode(dataIn, OUTPUT);
pinMode(clock, OUTPUT);
pinMode(load, OUTPUT);
// Buttons to change the time
pinMode(hourBtn, INPUT);
pinMode(minuteBtn, INPUT);
// connection to DS3231
Wire.begin();
// clear /EOSC bit
// Sometimes necessary to ensure that the clock
// keeps running on just battery power. Once set,
// it shouldn't need to be reset but it's a good
// idea to make sure.
Wire.beginTransmission(0x68); // address DS3231
Wire.write(0x0E); // select register
Wire.write(0b00011100); // write register bitmap, bit 7 is /EOSC
Wire.endTransmission();
//initiation of the max 7219
maxAll(max7219_reg_scanLimit, 0x07);
maxAll(max7219_reg_decodeMode, 0x00); // using an led matrix (not digits)
maxAll(max7219_reg_shutdown, 0x01); // not in shutdown mode
maxAll(max7219_reg_displayTest, 0x00); // no display test
for (e=1; e<=8; e++) { // empty registers, turn all LEDs off
maxAll(e,0);
}
maxAll(max7219_reg_intensity, 0x0f & 0x0f); // the first 0x0f is the value you can set
// range: 0x00 to 0x0f
}
// Aux. function to set the time
void set_time()
{
Wire.beginTransmission(104);
Wire.write(0);
Wire.write(decToBcd(seconds));
Wire.write(decToBcd(minutes));
Wire.write(decToBcd(hours));
Wire.endTransmission();
}
byte decToBcd(byte val)
{
return ( (val/10*16) + (val%10) );
}
// Main loop
void loop () {
// write request to read data starting at register 0
Wire.beginTransmission(0x68); // 0x68 is DS3231 device address
Wire.write(0); // start at register 0
Wire.endTransmission();
Wire.requestFrom(0x68, 3); // request three bytes (seconds, minutes, hours)
// Get time from RTC
while(Wire.available())
{
seconds = Wire.read(); // get seconds
minutes = Wire.read(); // get minutes
hours = Wire.read(); // get hours
seconds = (((seconds & 0b11110000)>>4)*10 + (seconds & 0b00001111)); // convert BCD to decimal
minutes = (((minutes & 0b11110000)>>4)*10 + (minutes & 0b00001111)); // convert BCD to decimal
hours = (((hours & 0b00110000)>>4)*10 + (hours & 0b00001111)); // convert BCD to decimal (assume 24 hour mode)
}
// Button is pressed, change hour (+1)
if(digitalRead(hourBtn)==1 && hourState==0) {
hours = hours+1;
if(hours>23) {
hours = 0;
}
set_time();
}
hourState = digitalRead(hourBtn);
// Button is pressed, change minutes (+1)
if(digitalRead(minuteBtn)==1 && minState==0) {
minutes = minutes+1;
if(minutes>59) {
minutes = 0;
}
set_time();
}
minState = digitalRead(minuteBtn);
// Reset variables
int a1 = 0;
int a2 = 0;
int a3 = 0;
int a4 = 0;
int a5 = 0;
int a6 = 0;
/*************
** MINUTES **
*************/
if(minutes>=0 && minutes<=4) {
// O'clock
} else if(minutes>=5 && minutes<=9) {
// (y)CINCO
a6 = a6+64;
} else if(minutes>=10 && minutes<=14) {
// (y)DIEZ
a5 = a5+14;
} else if(minutes>=15 && minutes<=19) {
// (y)CUARTO
a5 = a5+224;
} else if(minutes>=20 && minutes<=24) {
// (y)VEINTE
a5 = a5+16;
} else if(minutes>=25 && minutes<=29) {
// (y)VEINTICINCO
a3 = a3+136;
a4 = a4+68;
a5 = a5+68;
a6 = a6+64;
// VEINTICINCO shares some chars with a few hours, adjust the variables
if(hours==9 || hours==21) { a3 = a3-128; }
if(hours==7 || hours==19) { a3 = a3-8; }
if(hours==6 || hours==18) { a4 = a4-64; }
} else if(minutes>=30 && minutes<=34) {
// (y)MEDIA
a6 = a6+128;
} else if(minutes>=35 && minutes<=39) {
// (menos)VEINTICINCO
a3 = a3+136;
a4 = a4+64;
a5 = a5+68;
a6 = a6+64;
// VEINTICINCO shares some chars with a few hours, adjust the variables
if(hours==8 || hours==20) { a3 = a3-128; }
if(hours==6 || hours==18) { a3 = a3-8; }
if(hours==5 || hours==17) { a4 = a4-64; }
} else if(minutes>=40 && minutes<=44) {
// (menos)VEINTE
a5 = a5+16;
} else if(minutes>=45 && minutes<=49) {
// (menos)CUARTO
a5 = a5+224;
} else if(minutes>=50 && minutes<=54) {
// (menos)DIEZ
a5 = a5+14;
} else if(minutes>=55 && minutes<=59) {
// (menos)CINCO
a6 = a6+64;
}
if(minutes>=5 && minutes<=34) {
// Y
a4 = a4+16;
} else if(minutes>=35) {
// MENOS
a4 = a4+14;
}
// Move the hour if it's past 35 minutes as 7:35 is "OCHO(8) MENOS ..."
if(minutes>=35) {
hours++;
}
// SHOW none, 1,2,3 or 4 corner leds to exactly tell the time 7:17 -> SIETE Y CUARTO + 2 leds on
if((minutes%5)==1) {
a6 = a6+8;
} else if((minutes%5)==2) {
a6 = a6+8+4;
} else if((minutes%5)==3) {
a6 = a6+16+8+4;
} else if((minutes%5)==4) {
a6 = a6+32+16+8+4;
}
/*************************
** HOURS (follow table) **
*************************/
if(hours==0 || hours==12 || hours==24) {
a1 = a1+96;
a1 = a1+24;
a3 = a3+2;
} else if(hours==1 || hours==13) {
a1 = a1+192;
a1 = a1+16;
a1 = a1+4;
} else if(hours==2 || hours==14) {
a1 = a1+96;
a1 = a1+24;
a1 = a1+2;
} else if(hours==3 || hours==15) {
a1 = a1+96;
a1 = a1+24;
a2 = a2+16;
} else if(hours==4 || hours==16) {
a1 = a1+96;
a1 = a1+24;
a2 = a2+8;
} else if(hours==5 || hours==17) {
a1 = a1+96;
a1 = a1+24;
a3 = a3+32;
} else if(hours==6 || hours==18) {
a1 = a1+96;
a1 = a1+24;
a4 = a4+224;
} else if(hours==7 || hours==19) {
a1 = a1+96;
a1 = a1+24;
a3 = a3+28;
} else if(hours==8 || hours==20) {
a1 = a1+96;
a1 = a1+24;
a2 = a2+192;
} else if(hours==9 || hours==21) {
a1 = a1+96;
a1 = a1+24;
a2 = a2+2;
a3 = a3+192;
} else if(hours==10 || hours==22) {
a1 = a1+96;
a1 = a1+24;
a2 = a2+4;
} else if(hours==11 || hours==23) {
a1 = a1+96;
a1 = a1+24;
a2 = a2+96;
}
// Tell MAX7219 to print it pretty
maxSingle(1, a1);
maxSingle(2, a2);
maxSingle(3, a3);
maxSingle(4, a4);
maxSingle(5, a5);
maxSingle(6, a6);
// loop every second, as it doesn't need to be very precise
delay(1000);
// This 1second delay makes it a bit harder to update the time with the buttons, as it doesn't feel very friendly
// but you will not be changing the time very frequently, so not a big problem (for me)
}