NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Led Marquee triggered by a button question

January 22, 2010
by saleem
saleem's Avatar

Hi All,

I would like to switch on the Marquee by press of a button. I would like to put the button on PD7 (PCINT23) I have included my complete code, can some please tell me what I have to change or add to this code to make this possible. I have removed the column wire from PD7 PIN 13 of MCU.

Thx a million

Sal

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

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 F_CPU 14745600

define ROWS 5

define COLS 23 //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); } } }

//sense variable indicates direction of LED: sense == 1 indicates COL wire must be //hight for LED to turn on. sense == 0, COL wire must be low to turn LED on 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){ //led on DDRC |= (1 << (PC0 + j)); if(sense) { PORTC |= (1 << (PC0 + j)); } else { PORTC &= ~(1<< (PC0 + j)); } } else { // led off, pins to high impedance DDRC &= ~(1 << (PC0 + j)); PORTC &= ~(1 << (PC0 + j)); } } else { if(onoff){ //led on DDRD |= (1 << (PD2 + (j-6))); if(sense) { PORTD |= (1 << (PD2 + (j-6))); } else { PORTD &= ~(1 << (PD2 + (j-6))); } } else { // led off, pins to high impedance DDRC &= ~(1 << (PC0 + j)); DDRC &= ~(1 << (PC0 + j)); } } }

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

SIGNAL(SIG_OVERFLOW0) { // 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) { //this else is to turn ON odd columns 0,2,4... // 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, 2j), 1); } // activate row driver SINK PORTB &= ~(1 << (PB1 + real_row)); DDRB |= (1 << (PB1 + real_row)); } else { //this else is to turn ON odd columns 1,3,5... // odd la_row number: fill odd columns real_row = (la_row-1)/2; for(j=0; j<COLS/2; j++) { ledarray_set_columndriver(j, ledarray_get(real_row, 2j + 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)); } } }

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 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_down(char c, uint8_t offset) { char buf[7]; font_get(c, buf);

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

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(15); n++; s++; } }

// blank the next column to the right for(i=0; i<ROWS; i++) { ledarray_set(i, offset+width, 0); } }

/*********** Function name : font_display_ud Returns : None Parameters : c: character to diplay offset: column position for beginning of character up: boolean variable =1 character scrolls up =0 character scrolls down Purpose : Display text on marquee display scrolling the character up or down into view ************/

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

//this will flash "THANK" every second for a second

void do_testpattern() { // mode 1: test pattern int8_t offset=0; uint8_t delay = 10;//increas delay to scroll from left to right e.g 100 uint8_t i;

while(1) { //for(i=0; i<3; i++){ // break out? if(uart_char_is_waiting()) break;

// test pattern
//ledarray_testpattern();

// break out?
if(uart_char_is_waiting()) break;

// test letters    
ledarray_blank();
offset=0;
font_display('T', offset); offset += font_width('T')+1; delay_ms(delay);
font_display('H', offset); offset += font_width('H')+1; delay_ms(delay);
font_display('A', offset); offset += font_width('A')+1; delay_ms(delay);
font_display('N', offset); offset += font_width('N')+1; delay_ms(delay);
font_display('K', offset); offset += font_width('K')+1; delay_ms(delay);
//font_display('S', offset); offset += font_width('S')+1; delay_ms(delay);

delay_ms(500); //leave the display ON for 3 secs
ledarray_blank();
ledarray_all_off();
delay_ms(500); //add this delay so that the display flashes on the screen
// break out?
if(uart_char_is_waiting()) break;

} }

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;

do_testpattern();

ledarray_blank();

return 0; }

January 22, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi Saleem,

If you put the LED Array together you are doing a great job, and I think you can figure out how to do this yourself with a little guidance. First of all, realize that there are several ways to achieve what you ultimately want.

You can setup a button that is being read by the MCU as part of the main loop. When a button press is detected, the MCU can shutdown the interrupts so the array does not update itself anymore and sit in a while loop until the button is pressed again. Then you re-enable interrupts and exit the while loop to let the main loop continue. If you go that route you will want to figure out how to connect and detect a button press. We have one example of wiring up the pushbutton the Making Music with a Microcontroller tutorial.

The other (much easier) way to set up what you want is to put a switch into your circuit that just cuts off the power to the chip. You want to set it up so that power goes from your battery through the voltage regulator, and ultimately to your chip, but you want to put your switch somewhere in there to cut off the circuit when you flip the switch. I'm going to let you think about exactly how to do that and do a little experimenting yourself.

Let us know if you have any additional questions. I'm sure people on these forums would be glad to help.

Humberto

Post a Reply

Please log in to post a reply.

Did you know that a flyback diode is important when driving a motor or any inductive load? Learn more...