1 | #include <avr/io.h>
|
2 | #include <avr/pgmspace.h>
|
3 |
|
4 | #ifndef FONT_H_
|
5 | #define FONT_H_
|
6 |
|
7 | #define MAX_CHARS 59
|
8 | #define CHAR_OFFSET 0x20
|
9 |
|
10 | const uint8_t font[] PROGMEM = {
|
11 | // 3 chars bitmap, 1 char length
|
12 | 0x00, 0x00, 0x00, 0x01 , // 0x20, 32, ' '
|
13 | 0x17, 0x00, 0x00, 0x01 , // 0x21, 33, !
|
14 | 0x03, 0x00, 0x03, 0x03 , // 0x22, 34, "
|
15 | 0x00, 0x00, 0x00, 0x03 , // 0x23, 35, #
|
16 | 0x00, 0x00, 0x00, 0x03 , // 0x24, 36, $
|
17 | 0x00, 0x00, 0x00, 0x03 , // 0x25, 37, %
|
18 | 0x00, 0x00, 0x00, 0x03 , // 0x26, 38, &
|
19 | 0x03, 0x00, 0x00, 0x01 , // 0x27, 39, '
|
20 | 0x0e, 0x11, 0x00, 0x02 , // 0x28, 40, (
|
21 | 0x11, 0x0e, 0x00, 0x02 , // 0x29, 41, )
|
22 | 0x00, 0x00, 0x00, 0x03 , // 0x2A, 42, *
|
23 | 0x08, 0x1c, 0x08, 0x03 , // 0x2B, 43, +
|
24 | 0x18, 0x00, 0x00, 0x01 , // 0x2C, 44, ,
|
25 | 0x04, 0x04, 0x00, 0x03 , // 0x2D, 45, -
|
26 | 0x10, 0x00, 0x00, 0x01 , // 0x2E, 46, .
|
27 | 0x18, 0x04, 0x03, 0x03 , // 0x2F, 47, /
|
28 | 0x1f, 0x11, 0x1f, 0x03 , // 0x30, 48, 0
|
29 | 0x01, 0x1f, 0x00, 0x02 , // 0x31, 49, 1
|
30 | 0x1d, 0x15, 0x17, 0x03 , // 0x32, 50, 2
|
31 | 0x15, 0x15, 0x0e, 0x03 , // 0x33, 51, 3
|
32 | 0x0f, 0x08, 0x1f, 0x03 , // 0x34, 52, 4
|
33 | 0x17, 0x15, 0x1d, 0x03 , // 0x35, 53, 5
|
34 | 0x1f, 0x12, 0x1e, 0x03 , // 0x36, 54, 6
|
35 | 0x11, 0x09, 0x07, 0x03 , // 0x37, 55, 7
|
36 | 0x1f, 0x15, 0x1f, 0x03 , // 0x38, 56, 8
|
37 | 0x0f, 0x09, 0x1f, 0x03 , // 0x39, 57, 9
|
38 | 0x0a, 0x00, 0x00, 0x01 , // 0x3A, 58, :
|
39 | 0x1a, 0x00, 0x00, 0x01 , // 0x3B, 59, ;
|
40 | 0x08, 0x14, 0x00, 0x02 , // 0x3C, 60, <
|
41 | 0x14, 0x14, 0x00, 0x02 , // 0x3D, 61, =
|
42 | 0x14, 0x08, 0x00, 0x02 , // 0x3E, 62, >
|
43 | 0x15, 0x05, 0x02, 0x03 , // 0x3F, 63, ?
|
44 | 0x0e, 0x17, 0x16, 0x03 , // 0x40, 64, @
|
45 | 0x1f, 0x09, 0x1e, 0x03 , // 0x41, 65, A
|
46 | 0x1f, 0x15, 0x0a, 0x03 , // 0x42, 66, B
|
47 | 0x0e, 0x11, 0x11, 0x03 , // 0x43, 67, C
|
48 | 0x1f, 0x11, 0x0e, 0x03 , // 0x44, 68, D
|
49 | 0x0e, 0x15, 0x15, 0x03 , // 0x45, 69, E
|
50 | 0x1e, 0x05, 0x05, 0x03 , // 0x46, 70, F
|
51 | 0x0e, 0x11, 0x1d, 0x03 , // 0x47, 71, G
|
52 | 0x1f, 0x04, 0x1f, 0x03 , // 0x48, 72, H
|
53 | 0x1f, 0x00, 0x00, 0x01 , // 0x49, 73, I
|
54 | 0x08, 0x10, 0x0f, 0x03 , // 0x4A, 74, J
|
55 | 0x1f, 0x04, 0x1b, 0x03 , // 0x4B, 75, K
|
56 | 0x0f, 0x10, 0x10, 0x03 , // 0x4C, 76, L
|
57 | 0x1f, 0x02, 0x1f, 0x03 , // 0x4D, 77, M
|
58 | 0x1f, 0x01, 0x1e, 0x03 , // 0x4E, 78, N
|
59 | 0x0e, 0x11, 0x0e, 0x03 , // 0x4F, 79, O
|
60 | 0x1f, 0x09, 0x06, 0x03 , // 0x50, 80, P
|
61 | 0x06, 0x19, 0x06, 0x03 , // 0x51, 81, Q
|
62 | 0x1f, 0x09, 0x16, 0x03 , // 0x52, 82, R
|
63 | 0x12, 0x15, 0x09, 0x03 , // 0x53, 83, S
|
64 | 0x01, 0x1f, 0x01, 0x03 , // 0x54, 84, T
|
65 | 0x0f, 0x10, 0x0f, 0x03 , // 0x55, 85, U
|
66 | 0x1f, 0x10, 0x0f, 0x03 , // 0x56, 86, V
|
67 | 0x1f, 0x08, 0x1f, 0x03 , // 0x57, 87, W
|
68 | 0x1b, 0x04, 0x1b, 0x03 , // 0x58, 88, X
|
69 | 0x03, 0x1c, 0x03, 0x03 , // 0x59, 89, Y
|
70 | 0x19, 0x15, 0x13, 0x03 , // 0x5A, 90, Z
|
71 | 0x1f, 0x11, 0x00, 0x02 , // 0x5B, 91, [
|
72 | 0x03, 0x04, 0x18, 0x03 , // 0x5C, 92,
|
73 | 0x11, 0x1f, 0x00, 0x02 , // 0x5D, 93, [
|
74 | 0x11, 0x1f, 0x00, 0x02 , // 0x5E, 94, ^
|
75 | 0x1f, 0x1f, 0x1f, 0x03 // 0x5F, 95, _, used as block, all on
|
76 | };
|
77 |
|
78 | /* -----------------------------------------------------------------------
|
79 | * Title: 8x8 LED dot matrix animations
|
80 | * Author: Alexander Weber alex@tinkerlog.com
|
81 | * Date: 21.12.2008
|
82 | * Hardware: ATtiny2313V
|
83 | * Software: AVRMacPack
|
84 | *
|
85 | */
|
86 |
|
87 | #include <inttypes.h>
|
88 | #include <stdlib.h>
|
89 | #include <string.h>
|
90 | #include <avr/io.h>
|
91 | #include <avr/interrupt.h>
|
92 | #include <avr/eeprom.h>
|
93 | #include <util/delay.h>
|
94 | #include <avr/pgmspace.h>
|
95 | #include "font.h"
|
96 |
|
97 | // Change these values to adjust scroll speeds and animation iterations
|
98 | #define ANIMATION_SCROLL_SPEED 80 // how fast to scroll the animations
|
99 | #define TEXT_SCROLL_SPEED 120 // how fast to scrill the text
|
100 | #define REPEAT_ANIMATION 10 // how often to repeat the animation if in cycling mode
|
101 | #define REPEAT_TEXT 5 // how often to repeat the text if in cycling mode
|
102 | #define F_CPU
|
103 | // How to add a new message:
|
104 | // * add the new message (only upper case, see font.h)
|
105 | // * adjust MAX_MESSAGES
|
106 | // * add the new message to messages
|
107 | // NOTE: messages may not be longer than 59 chars. Otherwise they will not fit in the buffer.
|
108 | // 123456789012345678901234567890123456789012345678901234567890
|
109 | const prog_char PROGMEM message_00[] PROGMEM = " WTF!?! ";
|
110 | const prog_char PROGMEM message_01[] PROGMEM = " I AM NO BOMB! ";
|
111 | const prog_char PROGMEM message_02[] PROGMEM = " 5 4 3 2 1 ... BOOM! ";
|
112 | const prog_char PROGMEM message_03[] PROGMEM = " I'M SORRY DAVE, I'M AFRAID I CAN'T DO THAT. ";
|
113 | const prog_char PROGMEM message_04[] PROGMEM = " NOW BYE ME A SOLDERING STATION ";
|
114 | const prog_char PROGMEM message_05[] PROGMEM = " MAKE STUFF ";
|
115 | const prog_char PROGMEM message_06[] PROGMEM = " IF YOU CAN'T OPEN IT, YOU DON'T OWN IT ";
|
116 | const prog_char PROGMEM message_07[] PROGMEM = " 1337 3L3X7RON!C5 !1!! ";
|
117 | const prog_char PROGMEM message_08[] PROGMEM = " MY KUNG FU IS BETTER THAN YOURS ";
|
118 | const prog_char PROGMEM message_09[] PROGMEM = " SUDO MAKE ME A SANDWICH ";
|
119 | const prog_char PROGMEM message_10[] PROGMEM = " ZOMBIES AHEAD ";
|
120 | const prog_char PROGMEM message_11[] PROGMEM = " HTTP://TINKERLOG.COM ";
|
121 |
|
122 | #define MAX_MESSAGES 12
|
123 | PGM_P PROGMEM messages[] = {
|
124 | message_00
|
125 | ,message_01
|
126 | ,message_02
|
127 | ,message_03
|
128 | ,message_04
|
129 | ,message_05
|
130 | ,message_06
|
131 | ,message_07
|
132 | ,message_08
|
133 | ,message_09
|
134 | ,message_10
|
135 | ,message_11
|
136 | };
|
137 |
|
138 | #define MAX_ANIMATIONS 3
|
139 | const prog_uint8_t PROGMEM sprite_00[] =
|
140 | {
|
141 | 0x18, // ___XX___
|
142 | 0x3C, // __XXXX__
|
143 | 0x7E, // _XXXXXX_
|
144 | 0xDB, // X_XXXX_X
|
145 | 0xFF, // XXXXXXXX
|
146 | 0x24, // __X__X__
|
147 | 0x5A, // _X_XX_X_
|
148 | 0xA5 // X_X__X_X
|
149 | };
|
150 |
|
151 | const prog_uint8_t PROGMEM sprite_01[8] =
|
152 | {
|
153 | 0x18, // ___XX___
|
154 | 0x3C, // __XXXX__
|
155 | 0x7E, // _XXXXXX_
|
156 | 0xDB, // X_XXXX_X
|
157 | 0xFF, // XXXXXXXX
|
158 | 0x24, // __X__X__
|
159 | 0x42, // _X____X_
|
160 | 0x24 // __X__X__
|
161 | };
|
162 | const prog_uint8_t PROGMEM sprite_02[8] =
|
163 | {
|
164 | 0x00, // ________
|
165 | 0x00, // ________
|
166 | 0x14, // ___X_X__
|
167 | 0x3E, // __XXXXX_
|
168 | 0x3E, // __XXXXX_
|
169 | 0x1C, // ___XXX__
|
170 | 0x08, // ____X___
|
171 | 0x00 // ________
|
172 | };
|
173 |
|
174 | const prog_uint8_t PROGMEM sprite_03[8] =
|
175 | {
|
176 | 0x00, // ________
|
177 | 0x66, // _XX__XX_
|
178 | 0xFF, // XXXXXXXX
|
179 | 0xFF, // XXXXXXXX
|
180 | 0xFF, // XXXXXXXX
|
181 | 0x7E, // _XXXXXX_
|
182 | 0x3C, // __XXXX__
|
183 | 0x18 // ___XX___
|
184 | };
|
185 |
|
186 | const prog_uint8_t PROGMEM sprite_04[8] =
|
187 | {
|
188 | 0x24, // __X__X__
|
189 | 0x7E, // _XXXXXX_
|
190 | 0xDB, // XX_XX_XX
|
191 | 0xFF, // XXXXXXXX
|
192 | 0xA5, // X_X__X_X
|
193 | 0x99, // X__XX__X
|
194 | 0x81, // X______X
|
195 | 0xC3 // XX____XX
|
196 | };
|
197 |
|
198 | const prog_uint8_t PROGMEM sprite_05[8] =
|
199 | {
|
200 | 0x24, // __X__X__
|
201 | 0x18, // ___XX___
|
202 | 0x7E, // X_XXXX_X
|
203 | 0xDB, // XX_XX_XX
|
204 | 0xFF, // XXXXXXXX
|
205 | 0xDB, // X_XXXX_X
|
206 | 0x99, // X__XX__X
|
207 | 0xC3 // XX____XX
|
208 | };
|
209 |
|
210 |
|
211 |
|
212 | uint8_t mode_ee EEMEM = 0; // stores the mode in eeprom
|
213 | static uint8_t screen_mem[8]; // screen memory
|
214 | static uint8_t active_row; // active row
|
215 | static uint8_t buffer[60]; // stores the active message or sprite
|
216 | static uint8_t message_ptr = 0; // points to the active char in the message
|
217 | static uint8_t message_displayed = 0; // how often has the message been displayed?
|
218 | static uint8_t active_char = 0; // stores the active char
|
219 | static uint8_t message_length = 0; // stores the length of the active message
|
220 | static uint8_t char_ptr = 0; // points to the active col in the char
|
221 | static uint8_t char_length = 0; // stores the length of the active char
|
222 | static volatile uint16_t counter = 0; // used for delay function
|
223 |
|
224 | // prototypes
|
225 | void delay_ms(uint16_t delay);
|
226 | void copy_to_display(int8_t x, int8_t y, uint8_t sprite[]);
|
227 | void display_active_row(void);
|
228 | void show_char();
|
229 | void clear_screen(void);
|
230 | void copy_to_buffer(const prog_uint8_t sprite[8]);
|
231 | void scroll_animation(const prog_uint8_t sprite_1[], const prog_uint8_t sprite_2[]);
|
232 |
|
233 |
|
234 |
|
235 | /*
|
236 | * ISR TIMER0_OVF_vect
|
237 | * Handles overflow interrupts of timer 0.
|
238 | *
|
239 | * 4MHz
|
240 | * ----
|
241 | * Prescaler 8 ==> 1953.1 Hz
|
242 | * Complete display = 244 Hz
|
243 | *
|
244 | */
|
245 | ISR(TIMER0_OVF_vect) {
|
246 | display_active_row();
|
247 | counter++;
|
248 | }
|
249 |
|
250 |
|
251 |
|
252 | /*
|
253 | * delay_ms
|
254 | * Uses the counter that is incremented by the ISR.
|
255 | * Max delay is 32767ms.
|
256 | */
|
257 | void delay_ms(uint16_t delay) {
|
258 | while (!(PIND & (1 << PD6))) {} // used to stop the animation when PD6 goes LOW
|
259 | uint16_t t = delay * 2;
|
260 | counter = 0;
|
261 | while (counter < t) {}
|
262 | }
|
263 |
|
264 |
|
265 |
|
266 | /*
|
267 | * copy_to_display
|
268 | * Copies sprite data to the screen memory at the given position.
|
269 | */
|
270 | void copy_to_display(int8_t x, int8_t y, uint8_t sprite[8]) {
|
271 | int8_t i, t;
|
272 | uint8_t row;
|
273 | for (i = 0; i < 8; i++) {
|
274 | t = i-y;
|
275 | row = ((t >= 0) && (t < 8)) ? sprite[t] : 0x00;
|
276 | row = (x >= 0) ? (row >> x) : (row << -x);
|
277 | screen_mem[i] = row;
|
278 | }
|
279 | }
|
280 |
|
281 |
|
282 |
|
283 | /*
|
284 | * display_active_col
|
285 | * Deactivates the active column and displays the next one.
|
286 | * Data is read from screen_mem.
|
287 | *
|
288 | * ATtiny2313
|
289 | * 16 - PD0 PB7 - 1
|
290 | * 15 - PD1 PB6 - 2
|
291 | * 14 - PA1 PB5 - 3
|
292 | * 13 - PA0 PB4 - 4
|
293 | * 12 - PD2 PB3 - 5
|
294 | * 11 - PD3 PB2 - 6
|
295 | * 10 - PD4 PB1 - 7
|
296 | * 9 - PD5 PB0 - 8
|
297 | *
|
298 | * NFM-12883 common anode |
|
299 | * A0B5B4D4B2D3D1D0 +-----+
|
300 | * PD5 o o o o o o o o | |
|
301 | * PA1 o o o o o o o o _+_ |
|
302 | * PB0 o o o o o o o o \ / |
|
303 | * PD2 o o o o o o o o __V__ |
|
304 | * PB7 o o o o o o o o | |
|
305 | * PB1 o o o o o o o o ---+-----C---
|
306 | * PB6 o o o o o o o o |
|
307 | * PB3 o o o o o o o o
|
308 | *
|
309 | */
|
310 | void display_active_row(void) {
|
311 |
|
312 | uint8_t row;
|
313 |
|
314 | // shut down all rows and columns
|
315 | PORTA = (0 << PA0) | (1 << PA1);
|
316 | PORTB = (0 << PB5) | (0 << PB4) | (0 << PB2) | (1 << PB0) |
|
317 | (1 << PB7) | (1 << PB1) | (1 << PB6) | (1 << PB3);
|
318 | PORTD = (0 << PD4) | (0 << PD3) | (0 << PD1) | (0 << PD0) |
|
319 | (1 << PD5) | (1 << PD2) | (1 << PD6);
|
320 |
|
321 | // next row
|
322 | active_row = (active_row+1) % 8;
|
323 | row = screen_mem[active_row];
|
324 |
|
325 | // output all columns, switch leds on.
|
326 | // column 1
|
327 | if ((row & 0x80) == 0x80) {
|
328 | PORTA |= (1 << PA0);
|
329 | }
|
330 | // column 2
|
331 | if ((row & 0x40) == 0x40) {
|
332 | PORTB |= (1 << PB5);
|
333 | }
|
334 | // column 3
|
335 | if ((row & 0x20) == 0x20) {
|
336 | PORTB |= (1 << PB4);
|
337 | }
|
338 | // column 4
|
339 | if ((row & 0x10) == 0x10) {
|
340 | PORTD |= (1 << PD4);
|
341 | }
|
342 | // column 5
|
343 | if ((row & 0x08) == 0x08) {
|
344 | PORTB |= (1 << PB2);
|
345 | }
|
346 | // column 6
|
347 | if ((row & 0x04) == 0x04) {
|
348 | PORTD |= (1 << PD3);
|
349 | }
|
350 | // column 7
|
351 | if ((row & 0x02) == 0x02) {
|
352 | PORTD |= (1 << PD1);
|
353 | }
|
354 | // column 8
|
355 | if ((row & 0x01) == 0x01) {
|
356 | PORTD |= (1 << PD0);
|
357 | }
|
358 |
|
359 | // activate row
|
360 | switch (active_row) {
|
361 | case 0:
|
362 | PORTD &= ~(1 << PD5);
|
363 | break;
|
364 | case 1:
|
365 | PORTA &= ~(1 << PA1);
|
366 | break;
|
367 | case 2:
|
368 | PORTB &= ~(1 << PB0);
|
369 | break;
|
370 | case 3:
|
371 | PORTD &= ~(1 << PD2);
|
372 | break;
|
373 | case 4:
|
374 | PORTB &= ~(1 << PB7);
|
375 | break;
|
376 | case 5:
|
377 | PORTB &= ~(1 << PB1);
|
378 | break;
|
379 | case 6:
|
380 | PORTB &= ~(1 << PB6);
|
381 | break;
|
382 | case 7:
|
383 | PORTB &= ~(1 << PB3);
|
384 | break;
|
385 | }
|
386 |
|
387 | }
|
388 | /*
|
389 | * Use this method, if you have a common cathode matrix.
|
390 | */
|
391 | /*
|
392 | void display_active_row(void) {
|
393 |
|
394 | uint8_t row;
|
395 |
|
396 | // shut down all rows and columns
|
397 | PORTB = 0x34;
|
398 | PORTD = 0x1B;
|
399 | PORTA = 0x01;
|
400 |
|
401 | // next row
|
402 | active_row = (active_row+1) % 8;
|
403 | row = screen_mem[active_row];
|
404 |
|
405 | // output all columns, switch leds on.
|
406 | // column 1
|
407 | if ((row & 0x80) == 0x80) {
|
408 | PORTA &= ~(1 << PA0);
|
409 | }
|
410 | // column 2
|
411 | if ((row & 0x40) == 0x40) {
|
412 | PORTB &= ~(1 << PB5);
|
413 | }
|
414 | // column 3
|
415 | if ((row & 0x20) == 0x20) {
|
416 | PORTB &= ~(1 << PB4);
|
417 | }
|
418 | // column 4
|
419 | if ((row & 0x10) == 0x10) {
|
420 | PORTD &= ~(1 << PD4);
|
421 | }
|
422 | // column 5
|
423 | if ((row & 0x08) == 0x08) {
|
424 | PORTB &= ~(1 << PB2);
|
425 | }
|
426 | // column 6
|
427 | if ((row & 0x04) == 0x04) {
|
428 | PORTD &= ~(1 << PD3);
|
429 | }
|
430 | // column 7
|
431 | if ((row & 0x02) == 0x02) {
|
432 | PORTD &= ~(1 << PD1);
|
433 | }
|
434 | // column 8
|
435 | if ((row & 0x01) == 0x01) {
|
436 | PORTD &= ~(1 << PD0);
|
437 | }
|
438 |
|
439 | // activate row
|
440 | switch (active_row) {
|
441 | case 0:
|
442 | PORTD |= (1 << PD5);
|
443 | break;
|
444 | case 1:
|
445 | PORTA |= (1 << PA1);
|
446 | break;
|
447 | case 2:
|
448 | PORTB |= (1 << PB0);
|
449 | break;
|
450 | case 3:
|
451 | PORTD |= (1 << PD2);
|
452 | break;
|
453 | case 4:
|
454 | PORTB |= (1 << PB7);
|
455 | break;
|
456 | case 5:
|
457 | PORTB |= (1 << PB1);
|
458 | break;
|
459 | case 6:
|
460 | PORTB |= (1 << PB6);
|
461 | break;
|
462 | case 7:
|
463 | PORTB |= (1 << PB3);
|
464 | break;
|
465 | }
|
466 |
|
467 | }
|
468 | */
|
469 |
|
470 |
|
471 | /*
|
472 | * show_char
|
473 | * Displays the actual message.
|
474 | * Scrolls the screen to the left and draws new pixels on the right.
|
475 | */
|
476 | void show_char() {
|
477 | uint8_t i;
|
478 | uint8_t b;
|
479 |
|
480 | // blit the screen to the left
|
481 | for (i = 0; i < 8; i++) {
|
482 | screen_mem[i] <<= 1;
|
483 | }
|
484 | // advance a char if needed
|
485 | if (char_ptr == char_length) {
|
486 | message_ptr++;
|
487 | if (message_ptr == message_length) {
|
488 | message_ptr = 0;
|
489 | message_displayed++;
|
490 | }
|
491 | active_char = buffer[message_ptr] - CHAR_OFFSET;
|
492 | char_length = pgm_read_byte(&font[active_char * 4 + 3]);
|
493 | char_ptr = 0;
|
494 | return; // this makes the space between two chars
|
495 | }
|
496 | // read pixels for current column of char
|
497 | b = pgm_read_byte(&font[active_char * 4 + char_ptr++]);
|
498 | // write pixels into screen memory
|
499 | for (i = 0; i < 7; i++) {
|
500 | if ((b & (1 << i)) == (1 << i)) {
|
501 | screen_mem[i+1] |= 0x01;
|
502 | }
|
503 | }
|
504 | }
|
505 |
|
506 |
|
507 |
|
508 | /*
|
509 | * clear_screen
|
510 | */
|
511 | void clear_screen(void) {
|
512 | uint8_t i;
|
513 | for (i = 0; i < 8; i++) {
|
514 | screen_mem[i] = 0x00;
|
515 | }
|
516 | }
|
517 |
|
518 |
|
519 |
|
520 | /*
|
521 | * copy_to_buffer
|
522 | * Copies the given sprite from PROGMEM to RAM.
|
523 | */
|
524 | void copy_to_buffer(const prog_uint8_t sprite[8]) {
|
525 | memcpy_P(buffer, sprite, 8);
|
526 | }
|
527 |
|
528 |
|
529 |
|
530 | /*
|
531 | * scroll_animation
|
532 | * Uses sprite_1 and sprite_2 to draw a simple animation.
|
533 | */
|
534 | void scroll_animation(const prog_uint8_t sprite_1[8], const prog_uint8_t sprite_2[8]) {
|
535 | uint8_t i;
|
536 | int8_t x;
|
537 | for (i = 0; i < REPEAT_ANIMATION; i++) {
|
538 | copy_to_buffer(sprite_1);
|
539 | for (x = -8; x <= 0; x++) {
|
540 | copy_to_display(x, 0, buffer);
|
541 | delay_ms(ANIMATION_SCROLL_SPEED);
|
542 | }
|
543 | delay_ms(200);
|
544 | copy_to_buffer(sprite_2);
|
545 | copy_to_display(0, 0, buffer);
|
546 | delay_ms(200);
|
547 | copy_to_buffer(sprite_1);
|
548 | copy_to_display(0, 0, buffer);
|
549 | delay_ms(200);
|
550 | copy_to_buffer(sprite_2);
|
551 | copy_to_display(0, 0, buffer);
|
552 | delay_ms(200);
|
553 | copy_to_buffer(sprite_1);
|
554 | for (x = 0; x < 8; x++) {
|
555 | copy_to_display(x, 0, buffer);
|
556 | delay_ms(ANIMATION_SCROLL_SPEED);
|
557 | }
|
558 | }
|
559 | }
|
560 |
|
561 |
|
562 |
|
563 | int main(void) {
|
564 |
|
565 | uint8_t i = 0;
|
566 | uint8_t mode = 0;
|
567 | uint8_t cycle = 0;
|
568 |
|
569 | // timer 0 setup, prescaler 8
|
570 | TCCR0B |= (1 << CS01);
|
571 |
|
572 | // enable timer 0 interrupt
|
573 | TIMSK |= (1 << TOIE0);
|
574 |
|
575 | // define outputs
|
576 | DDRA |= 0x03;
|
577 | DDRB |= 0xFF;
|
578 | DDRD |= 0x3F;
|
579 |
|
580 | // shut down all rows and columns, enable column 1
|
581 | PORTA = (1 << PA0) | (1 << PA1);
|
582 | PORTB = (0 << PB5) | (0 << PB4) | (0 << PB2) | (1 << PB0) |
|
583 | (1 << PB7) | (1 << PB1) | (1 << PB6) | (1 << PB3);
|
584 | PORTD = (0 << PD4) | (0 << PD3) | (0 << PD1) | (0 << PD0) |
|
585 | (1 << PD5) | (1 << PD2);
|
586 |
|
587 | // enable pull ups
|
588 | PORTD |= (1 << PD6);
|
589 |
|
590 | // say hello, toggle row 1 (pixel 0,0)
|
591 | for (i = 0; i < 5; i++) {
|
592 | PORTD &= ~(1 << PD5);
|
593 | _delay_ms(50);
|
594 | PORTD |= (1 << PD5);
|
595 | _delay_ms(50);
|
596 | }
|
597 |
|
598 | // read last mode from eeprom
|
599 | // 0 mean cycle through all modes and messages
|
600 | mode = eeprom_read_byte(&mode_ee);
|
601 | if ((mode == 0) || (mode >= (MAX_ANIMATIONS + MAX_MESSAGES + 1))) {
|
602 | mode = 1;
|
603 | cycle = 1;
|
604 | }
|
605 | eeprom_write_byte(&mode_ee, mode + 1);
|
606 |
|
607 | sei();
|
608 |
|
609 | while (1) {
|
610 |
|
611 | switch (mode) {
|
612 | case 1:
|
613 | scroll_animation(sprite_00, sprite_01);
|
614 | break;
|
615 | case 2:
|
616 | for (i = 0; i < REPEAT_ANIMATION; i++) {
|
617 | copy_to_buffer(sprite_03);
|
618 | copy_to_display(0, 0, buffer);
|
619 | delay_ms(750);
|
620 | copy_to_buffer(sprite_02);
|
621 | copy_to_display(0, 0, buffer);
|
622 | delay_ms(180);
|
623 | }
|
624 | break;
|
625 | case 3:
|
626 | scroll_animation(sprite_04, sprite_05);
|
627 | break;
|
628 | default:
|
629 | strcpy_P(buffer, (uint8_t*)pgm_read_word(&(messages[mode - (MAX_ANIMATIONS+1)])));
|
630 | message_length = strlen(buffer);
|
631 | while (message_displayed < REPEAT_TEXT) {
|
632 | show_char();
|
633 | delay_ms(TEXT_SCROLL_SPEED);
|
634 | }
|
635 | message_displayed = 0;
|
636 | break;
|
637 | }
|
638 |
|
639 | // cycle through all modes
|
640 | if (cycle) {
|
641 | mode++;
|
642 | clear_screen();
|
643 | if (mode >= (MAX_ANIMATIONS + MAX_MESSAGES + 1)) {
|
644 | mode = 1;
|
645 | }
|
646 | }
|
647 |
|
648 | }
|
649 |
|
650 | return 0;
|
651 |
|
652 | }
|