You are on page 1of 17

// ledarray.c // for NerdKits with ATmega168 // mrobbins@mit.

edu // Modified by Rick Shear

#define F_CPU 14745600 #include "../libnerdkits/io_328p.h"

#include <stdio.h> #include <avr/io.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include <inttypes.h>

#include "../libnerdkits/delay.h" // #include "../libnerdkits/uart.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

volatile uint8_t la_row, real_row; volatile uint8_t la_data[COLS];

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) );

PORTB &= ~( (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();

// increment row number if(++la_row == 2*ROWS) la_row = 0;

// 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));

} } // blank bottom line to prevent 'smearing' for(j=0;j<COLS;j++){ ledarray_set(4,j,0); } }

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;

for(i=0; i<FONT_SIZE; i++) { memcpy_P(&p, &font[i], sizeof(PGM_P));

if(memcmp_P(&match, p,1)==0) { memcpy_P(buf, p, 7); return; } }

// NO MATCH? font_get('?', buf); }

uint8_t font_width(char c) { char buf[7]; buf[1] = 0;

font_get(c, buf);

return buf[1]; }

void font_display(char c, uint8_t offset) { char buf[7]; font_get(c, buf);

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); } }

void font_display_ud(char c, uint8_t offset, uint8_t up) {

char buf[7]; // get font data for the current character and place it into the buffer

font_get(c, buf);

uint8_t width = buf[1]; uint8_t i, j, s,n;

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); } }

void scroll_display(const char *s,uint8_t speed) { // clear display ledarray_blank();

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() {

int8_t offset=0; int8_t i=0; while(1) {

//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);

for(i=0;i<5;i++){ ledarray_shift_up(); delay_ms(80); } // for(i=0;i<COLS;i++){ // ledarray_left_shift(); // delay_ms(50); //}

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);

for(i=0;i<5;i++){ ledarray_shift_down(); delay_ms(80); }

} }

int main() { ledarray_init();

// activate interrupts sei();

/* // init serial port uart_init(); FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW); stdin = stdout = &uart_stream; */

// mode 1: test pattern do_testpattern();

return 0; }

You might also like