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 Array questions

March 28, 2012
by amartinez
amartinez's Avatar

Hello everyone. I've been playing with the LED Array kit. I got all the lights working and tested them with the ledarray_test files. All lights work great.

I have a few questions on the project, it seems to be blinking instead of scrolling (HELLO) on me and it seems a bit slow when I use the ledarray_template files.

I have to read the pdf file again but as I was fooling with the program I found a problem with it. If you change the time from 1000 ms to 10ms by the font_display commands at around line 245 the chip stops working alltogether. I couldn't get the chip to work again. I had to replace it.

If any of you guys have an extra 168, try this. I changed every delay to 10 from 1000. Why? I don't know, just fooling around, I didn't think it would be a problem. OOPS!

My hookup is a bit different. I'm using AVR DUDE's make.exe file to create the hex file. Once I see that there are no errors (except the connectivity error) I take the hex file and push it to the chip using the AVR Dragon via ISP. Yes, some wires have to come off while it's programming because LED lights connected to what should be ISP ports don't allow ISP programming. But that's the way I chose to do it.

Let me know if this happens to you. The code asks a lot out of the chip, lots of math. Maybe I overloaded the circuits inside???? I've seen these chips blow up when you divide by 0. Sounds like a small firecracker.

March 30, 2012
by amartinez
amartinez's Avatar

I'm up to page 40 where it says "Remove the test pattern from your main loop, and instead write a message letter by letter to your LED array." I'm assuming this is the template directory's ledarray.c file. If so, I need some help.

I read the PDF file several times up until the UART portion. I'm working with the ledarray.c program in the template subdirectory. I'm trying to do a simple scrolling message starting from the right.

The code below gives me the word MOSFET on the array but blinks slowly, probably because there is still some code in it that calls for the test pattern, but I remarked both test pattern routines out and I just don't see any reference to the test pattern, so how could this be giving me a test pattern after printing the word MOSFET on the LED array without scrolling? I am trying to wrap my head around this problem.

All of the header files import properly. No errors. The HEX file compiles nicely.

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

#include "../avr/include/stdio.h"

#include "../avr/include/avr/io.h"
#include "../avr/include/avr/interrupt.h"
#include "../avr/include/avr/pgmspace.h"
#include "../avr/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 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) {
    // 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, 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));
    }
  }
}

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

  for(i=0;i<ROWS;i++) {
    for(j=0;j<COLS;j++) {
      ledarray_set(i,j, 1 - ledarray_get(i,j));
      delay_ms(30);
    }
  }

  for(i=0;i<ROWS;i++) {
    for(j=0;j<COLS;j++) {
      ledarray_set(i,j, 1 - ledarray_get(i,j));
      delay_ms(30);
    }
  }
}

*/

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 do_testpattern() {
  // mode 1: test pattern
  int8_t offset=0;
  while(1) {
    // 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('H', offset); offset += font_width('H')+1; delay_ms(1000);
    font_display('E', offset); offset += font_width('E')+1; delay_ms(1000);
    font_display('L', offset); offset += font_width('L')+1; delay_ms(1000);
    font_display('L', offset); offset += font_width('L')+1; delay_ms(1000);
    font_display('O', offset); offset += font_width('O')+1; delay_ms(1000);

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

*/

void do_scrolling_display() {
  ledarray_blank();
  int8_t offset = 0, next_offset = 0;
  uint8_t is_started = 0;
  char x=' ';

  while(1) {
    if(is_started) {
      delay_ms(125);
      ledarray_left_shift(); 
      if(next_offset > 0) {
        offset -= 1;
        next_offset -= 1;
      } else {
        is_started = 0;
      }
      font_display(x, offset); 
    } else {
      offset = COLS-1;
    }
    // if we can now accept a new character, tell the computer
    if(next_offset == COLS)
      uart_write('n');

    while(uart_char_is_waiting()) {
      if(is_started)
        offset = next_offset;

      x = uart_read(); 
      if(x=='a') {
        ledarray_blank();
        return;
      }
      font_display(x, offset);
      next_offset = offset + font_width(x)+1;
      is_started = 1;  
      // if we can now accept a new character, tell the computer
      if(next_offset <= COLS)
        uart_write('n');
    }
  }
}

void do_simple_display() {
  ledarray_blank();
  uint8_t offset = 0;
  char x = ' ';

  while(1){
    x = uart_read();
    if(x == 'z'){
      ledarray_blank();
      offset = 0;
    } else {
      //render the charater we just got
      font_display(x,offset);
      //adjust the offset for the next character
      offset += font_width(x)+1;
    }
  }
}

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

  // test letters    
   ledarray_blank();   
   uint8_t offset=0;
   font_display('M', offset); offset += font_width('M')+1; delay_ms(1000);
   font_display('O', offset); offset += font_width('O')+1; delay_ms(1000);
   font_display('S', offset); offset += font_width('S')+1; delay_ms(1000);
   font_display('F', offset); offset += font_width('F')+1; delay_ms(1000);
   font_display('E', offset); offset += font_width('E')+1; delay_ms(1000);
   font_display('T', offset); offset += font_width('T')+1; delay_ms(1000);
   uint8_t i,j;

   for(i=0;i<ROWS;i++) {
    for(j=0;j<COLS;j++) {
      ledarray_set(i,j, 1);
      delay_ms(30);
    }
    }

  while(1) {
    // do_simple_display();
    do_scrolling_display();
  }
  return 0;
}
March 30, 2012
by amartinez
amartinez's Avatar

I guess a better way to describe it that after the word MOSFET is printed on the array the test pattern starts to display and overlays on the existing word.

I appreciate all your help on this.

Post a Reply

Please log in to post a reply.

Did you know that binary numbers use base 2 to represent numbers, and these are important for understanding microcontroller registers? Learn more...