Professional Documents
Culture Documents
#include <stdio.h> #include <avr/io.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include <inttypes.h>
#include "font.h"
// PIN DEFINITIONS: // // PB1-5 ROW DRIVERS (0-4) // PC0-5,PD2-7: COLUMN DRIVERS (0-11) #define ROWS 5 #define COLS 24
inline uint8_t ledarray_get(uint8_t i, uint8_t j) { if(i < ROWS && j < COLS) { if((la_data[j] & (1<<i)) != 0) { return 1; } else { return 0; } } else { return 0; } }
inline void ledarray_set(uint8_t i, uint8_t j, uint8_t onoff) { if(i < ROWS && j < COLS) { if(onoff) { la_data[j] |= (1<<i); } else { la_data[j] &= ~(1<<i); } } }
inline void ledarray_set_columndriver(uint8_t j, uint8_t onoff, uint8_t sense) { // cols 0-5: PC0-5 // cols 6-11: PD2-7 if(j < 6) { if(onoff) {
PORTC |= (1 << (PC0 + j)); } else { PORTC &= ~(1<< (PC0 + j)); } if(sense == onoff) { DDRC |= (1 << (PC0 + j)); } else { DDRC &= ~(1 << (PC0 + j)); PORTC &= ~(1 << (PC0 + j)); } } else { if(onoff) { PORTD |= (1 << (PD2 + (j-6))); } else { PORTD &= ~(1<< (PD2 + (j-6))); } if(sense == onoff) { DDRD |= (1 << (PD2 + (j-6))); } else { DDRD &= ~(1 << (PD2 + (j-6))); PORTD &= ~(1 << (PD2 + (j-6))); } } }
inline void ledarray_all_off() { // turn off all row drivers DDRB &= ~( (1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5) );
// turn off all column drivers DDRC &= ~( (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4) | (1<<PC5) ); PORTC &= ~( (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4) | (1<<PC5) ); DDRD &= ~( (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7) ); PORTD &= ~( (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7) ); }
ISR(TIMER0_OVF_vect) { // turn off old row driver DDRB &= ~(1 << (PB1 + real_row)); PORTB &= ~(1 << (PB1 + real_row)); ledarray_all_off();
// set column drivers appropriately uint8_t j; if(la_row%2 == 0) { // even la_row number: fill even columns real_row = la_row / 2; for(j=0; j<COLS/2; j++) { ledarray_set_columndriver(j, ledarray_get(real_row, 2*j), 1);
} // activate row driver SINK PORTB &= ~(1 << (PB1 + real_row)); DDRB |= (1 << (PB1 + real_row)); } else { // odd la_row number: fill odd columns real_row = (la_row-1)/2; for(j=0; j<COLS/2; j++) { ledarray_set_columndriver(j, 1 - ledarray_get(real_row, 2*j + 1), 0); } // activate row driver SOURCE PORTB |= (1 << (PB1 + real_row)); DDRB |= (1 << (PB1 + real_row)); } }
void ledarray_init() { // Timer0 CK/64 (900Hz) TCCR0B = (1<<CS01) | (1<<CS00); TIMSK0 = (1<<TOIE0);
// outputs (set row drivers high for off) DDRC &= ~( (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4) | (1<<PC5) ); DDRD &= ~( (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7) ); DDRB &= ~( (1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5) ); }
void ledarray_left_shift() { // shift everything one position left uint8_t i, j; for(i=0; i<ROWS; i++) { for(j=0; j<COLS-1; j++) { ledarray_set(i,j, ledarray_get(i, j+1)); } ledarray_set(i,23,0); } }
void ledarray_right_shift(){ // shift everything right one position uint8_t i, j; for(i=0; i<ROWS; i++) { for(j=COLS-1; j>0; j--) { ledarray_set(i,j, ledarray_get(i, j-1)); } ledarray_set(i,0,0); } }
void ledarray_shift_up(){ // shift everything up one position uint8_t i,j; for(i=0;i<ROWS-1;i++){ for(j=0;j<COLS;j++){ ledarray_set(i,j,ledarray_get(i+1,j));
void ledarray_shift_down(){ // shift everything down one position uint8_t i,j; for(i=4;i>0;i--){ for(j=0;j<COLS;j++){ ledarray_set(i,j,ledarray_get(i-1,j)); } } // blank top line to prevent 'smearing' for(j=0;j<COLS;j++){ ledarray_set(0,j,0); } }
void ledarray_blank() { uint8_t i, j; for(i=0; i<ROWS; i++) { for(j=0; j<COLS; j++) { ledarray_set(i,j,0); }
} }
void ledarray_testpattern() { uint8_t i, j, ct; ledarray_blank(); // set initital pattern (every other LED on) for(i=0;i<ROWS;i++) { for(j=i%2;j<COLS;j += 2) { ledarray_set(i,j, 1 - ledarray_get(i,j)); } } //wait 50ms delay_ms(50);
// toggle the pattern turning what was on off then back on again 10 times for(ct=0;ct<10;ct++){ for(i=0;i<ROWS;i++) { for(j=0;j<COLS;j++) { ledarray_set(i,j, 1 - ledarray_get(i,j)); } } delay_ms(50); for(i=0;i<ROWS;i++) { for(j=0;j<COLS;j++){ ledarray_set(i,j, 1 - ledarray_get(i,j)); } }
delay_ms(50); } }
void font_get(char match, char *buf) { // copies the character "match" into the buffer uint8_t i; PGM_P p;
font_get(c, buf);
return buf[1]; }
uint8_t width = buf[1]; uint8_t i, j; for(i=0; i<ROWS; i++) { for(j=0; j<width; j++) { if((offset + j) < COLS) { if( (buf[2+j] & (1<<i)) != 0) { ledarray_set(i,offset + j,1); } else { ledarray_set(i,offset + j,0); } } } }
// blank the next column to the right for(i=0; i<ROWS; i++) { ledarray_set(i, offset+width, 0); } }
char buf[7]; // get font data for the current character and place it into the buffer
font_get(c, buf);
if(up){ for(i=0; i<ROWS; i++) { n=0; s=4-i; while(s<ROWS){ for(j=0; j<width; j++) { if((offset + j) < COLS) { if( (buf[2+j] & (1<<n)) != 0) { ledarray_set(s,offset + j,1); } else { ledarray_set(s,offset + j,0); } } } delay_ms(7); n++; s++; } } } else{
for(i=0; i<ROWS; i++) { n=4-i; s=0; while(s<=i){ for(j=0; j<width; j++) { if((offset + j) < COLS) { if( (buf[2+j] & (1<<n)) != 0) { ledarray_set(s,offset + j,1); } else { ledarray_set(s,offset + j,0); } } } delay_ms(7); n++; s++; } } } // blank the next column to the right for(i=0; i<ROWS; i++) { ledarray_set(i, offset+width, 0); } }
int8_t offset = 0 , next_offset = 0; uint8_t is_started = 0; uint8_t i=0; char x=' '; if(speed==0) speed=90;
// begin loop and continue until nul character at end of string while(pgm_read_byte(s) != 0x00){
// have we read a character? if(is_started) { // if so, place and shift the character until it is clear of column 24 while(next_offset>23){ delay_ms(speed); // shift the display one place ledarray_left_shift(); // check the end of the currently displayed than zero, decrement characters if it's greater
// both the offset (character display position), and end position) if(next_offset > 0) { offset -= 1; next_offset -= 1; } // display the character at the new position font_display(x, offset); } } else {
next_offset(character
// if not, set offset to # of columns -1 (23) offset = COLS-1; } // read the next character in the string x = pgm_read_byte(s++);
// if we have already started, set the current display position to where the last character ended if(is_started) offset = next_offset; // display the character font_display(x, offset); // create the new character end position next_offset = offset + font_width(x)+1; // set flag to show we have been through the loop is_started = 1; } // Process the last character. This is neccessary since the while bails as soon as it reads // the null character. At that point, the last read character has not yet into full shifted
// view. The following while loop shifts the final string character into full view. while(next_offset>23){ delay_ms(speed); ledarray_left_shift(); if(next_offset > 0) { offset -= 1; next_offset -= 1; } font_display(x, offset);
delay_ms(speed); // this final loop shifts the display all the way off. for(i=0;i<COLS;i++){ ledarray_left_shift(); delay_ms(speed); }
return; }
void do_testpattern() {
//ledarray_testpattern();
ledarray_blank(); offset=0; font_display_ud('H', 2,1); delay_ms(100); font_display_ud('A', 6,0); delay_ms(100); font_display_ud('P', 10,1); delay_ms(100); offset=14; font_display_ud('P', offset,0); offset += font_width('P')+1; delay_ms(100); font_display_ud('Y', offset,1); offset += font_width('Y')+1; delay_ms(1500);
ledarray_blank();
scroll_display(PSTR("BIRTHDAY"),80);
ledarray_blank(); offset=1; font_display_ud('D', offset,1); offset += font_width('D')+1; //delay_ms(1000); font_display_ud('O', offset,1); offset += font_width('O')+1; //delay_ms(1000); font_display_ud('N', offset,1); offset += font_width('N')+1; //delay_ms(1000); font_display_ud('N', offset,1); offset += font_width('N')+1; //delay_ms(1000); font_display_ud('A', offset,1); offset += font_width('A')+1; delay_ms(1500);
} }
/* // init serial port uart_init(); FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW); stdin = stdout = &uart_stream; */
return 0; }