-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbinclock.c
276 lines (231 loc) · 4.85 KB
/
binclock.c
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
/*
* binclock.c
*
* Created on: 26.08.2013
* Author: tecdroid
*/
#include <avr/io.h>
#include <avr/delay.h>
#include <stdint.h>
/* set this switch if your clock is battery powered
* it will switch off the lights after 10 seconds
*/
#define WITH_ENLIGHT
#define STATE_NONE 0x00
#define STATE_MENU_SECOND 0x10
#define STATE_MENU_MINUTE 0x20
#define STATE_MENU_HOUR 0x30
#define STATE_MENU_END 0x40
#define DDR_HOUR DDRD
#define PORT_HOUR PORTD
#define PORTMASK_HOUR 0b11110000
#define DDR_MINUTE DDRC
#define PORT_MINUTE PORTC
#define PORTMASK_MINUTE 0b00111111
#define DDR_SECOND DDRB
#define PORT_SECOND PORTB
#define PORTMASK_SECOND 0b00111111
#define DDR_INPUTS DDRD
#define PIN_INPUTS PIND
#define PORT_INPUTS PORTD
#define PIN_A (1<<PIND2)
#define PIN_B (1<<PIND3)
typedef struct {
uint8_t second;
uint8_t minute;
uint8_t hour;
} s_time;
uint8_t state;
uint8_t enlight;
s_time time;
void inline add_hour(s_time *time);
void inline add_minute(s_time *time, uint8_t overflow);
void inline add_second(s_time *time, uint8_t overflow);
uint8_t a_pressed(void);
uint8_t b_pressed(void);
void display_seconds(s_time time);
void display_minutes(s_time time);
void display_hours(s_time time);
void set_all_leds (uint8_t set);
void init_timer();
void wait_a_second();
void run_states(uint8_t state, s_time* time);
/**
* main function
*/
int main(int argc, char **argv) {
// initialisiere alle Werte
state = STATE_NONE;
enlight = 10;
time.hour = 1;
time.minute = 0;
time.second = 0;
// Ausgänge für Stundenzeiger
DDR_HOUR |= PORTMASK_HOUR;
// Ausgänge für Minutenzeiger
DDR_MINUTE |= PORTMASK_MINUTE;
// Ausgänge für Sekundenzeiger
DDR_SECOND |= PORTMASK_SECOND;
// Eingänge für Menütaster, aktiviere Pullups
DDRD &= ~(1 << PORTD2 | 1 << PORTD3);
PORTD |= (1 << PORTD2 | 1 << PORTD3);
// timer initialisieren
init_timer();
while (1) {
// State machine zum Ändern der Uhrzeit
run_states(state, &time);
wait_a_second();
// Prüfe ob Menuetaste gedrückt wurde und ändere Status
if (a_pressed()) {
state += 0x10;
if ((state & 0xf0) == STATE_MENU_END) {
state = STATE_NONE;
}
}
#ifdef WITH_ENLIGHT
// schalte die Uhrzeitanzeige an.
if (b_pressed()) {
enlight = 10;
}
#endif
}
}
/**
* State machine for menu and display
*/
void run_states(uint8_t state, s_time* time) {
// State machine zum Ändern der Uhrzeit
switch (0xf0 & state) {
case STATE_MENU_SECOND:
set_all_leds(1);
if (b_pressed()) {
add_second(time, 0);
}
display_seconds(*time);
break;
case STATE_MENU_MINUTE:
set_all_leds(1);
if (b_pressed()) {
add_minute(time, 0);
}
display_minutes(*time);
break;
case STATE_MENU_HOUR:
set_all_leds(1);
if (b_pressed()) {
add_hour(time);
}
display_hours(*time);
break;
case STATE_NONE:
set_all_leds(0);
#ifdef WITH_ENLIGHT
if (enlight > 0) {
#endif
display_seconds(*time);
display_minutes(*time);
display_hours(*time);
#ifdef WITH_ENLIGHT
enlight--;
}
#endif
add_second(time, 1);
break;
}
}
/**
* add one to the hours
*/
void inline add_hour(s_time *time) {
time->hour++;
if (time->hour > 12) {
time->hour = 1;
}
}
/**
* add one to the minutes
*/
void inline add_minute(s_time *time, uint8_t overflow) {
time->minute++;
if (time->minute >= 60) {
time->minute = 0;
if (overflow) {
add_hour(time);
}
}
}
/**
* add one to the seconds
*/
void inline add_second(s_time *time, uint8_t overflow) {
time->second++;
if (time->second >= 60) {
time->second = 0;
if (overflow) {
add_minute(time, 1);
}
}
}
/**
* return true if a has been set
*/
uint8_t a_pressed(void) {
return !(PIND & (1 << PIND2));
}
/**
* return true if b has been set
*/
uint8_t b_pressed(void) {
return !(PIND & (1 << PIND3));
}
/**
* display the seconds of time
*/
void display_seconds(s_time time) {
PORT_SECOND &= ~(PORTMASK_SECOND);
PORT_SECOND |= (PORTMASK_SECOND & time.second);
}
/**
* display minutes of time
*/
void display_minutes(s_time time) {
PORT_MINUTE &= ~(PORTMASK_MINUTE);
PORT_MINUTE |= (PORTMASK_MINUTE & time.minute);
}
/**
* display hours of time
*/
void display_hours(s_time time) {
PORT_HOUR &= ~(PORTMASK_HOUR);
PORT_HOUR |= (PORTMASK_HOUR & (hour << 4));
}
/**
* wait a second (or less if in test mode)
*/
void wait_a_second() {
// zwei mal auf den timer overflow warten (entspricht einer Sekunde)
TIFR |= (1 << TOV0);
while (!(TIFR & (1 << TOV0)))
;
TIFR |= (1 << TOV0);
while (!(TIFR & (1 << TOV0)))
;
}
void set_all_leds (uint8_t set) {
if (set) {
PORT_SECOND |= (PORTMASK_SECOND);
PORT_MINUTE |= (PORTMASK_MINUTE);
PORT_HOUR |= (PORTMASK_HOUR);
} else {
PORT_SECOND &= ~(PORTMASK_SECOND);
PORT_MINUTE &= ~(PORTMASK_MINUTE);
PORT_HOUR &= ~(PORTMASK_HOUR);
}
}
/**
* initialize timer
*/
void init_timer() {
// Timer initialisieren F_CPU/64
TCCR0 |= ((1 << CS01) | (1 << CS00));
}