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.

Support Forum » Led Array Code

November 26, 2011
by SirHobbes3
SirHobbes3's Avatar

So im doing the Ledarray educational code, and i think i have it finished, i flash it to the mcu and when i plug it in, the only 4 colummns light up(or 5, and they have one unlit colummn in between them). So i was wondering what the final result of the finished code is SUPPOSED to be, that way i know what to aim for.

November 26, 2011
by SirHobbes3
SirHobbes3's Avatar

Okay let me rephrase that, i did the ledarray educational code and flashed it to the mcu no problem, but when i plug it in , only 4 colummns light up(maybe 5), and there is a colummn in between them, so it's like this(cl=lit colummn, nl=not lit colummn) cl, nl, cl,nl, cl,nl,cl,nl,cl?,nl,nl,nl...... So i don't know what exactly to do here. If it helps, here is the code...

// ledarray.c
// for NerdKits with ATmega168
// Austin Moss

#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 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));
      if (sense) {
        PORTD |= (1 << (PD2 + j));
        } else {
        PORTD &= ~(1 << (PD2 + j));
        }
    } else { //led off, ping in high impedance
     DDRC &= ~(1 << (PD2 +j));
     DDRC &= ~(1 << (PD2 +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 low 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) {
    // set the row of led_array at the right offset.
        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_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 {

        //fill in code to render character here

    }
  }

}

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;

  uint8_t i, j;

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

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

 //do_simple_display();
    //do_scrollint_display();
November 26, 2011
by Rick_S
Rick_S's Avatar

Why don't you try and load proven code to make sure your display is wired and working correctly? Then if you want, you can try to code it yourself - at least at that point, you'll know you have a working setup and if you have problems then you'll know 100% that the problem is in your code. There are several working iterations of led array software floating in the forums and the tutorial page.

I have posted full code with updated and extra functions on the forums. If you search by my username and LED array, you'll find it.

Rick

December 03, 2011
by SirHobbes3
SirHobbes3's Avatar

I seem to be getting somewhere. The "completed" code, when put on the mcu, displays a scrolling question mark (?) which I see on line # 192 of the "ledarray.c" code. On my code the "?" appears on line 193, the cause of that should just be spacing error, but unfortunately, i get different results.(as described in my 2nd post) I will be looking into this.......

December 03, 2011
by SirHobbes3
SirHobbes3's Avatar

or if you look in the example above, the "?" appears in line 191.

December 04, 2011
by Rick_S
Rick_S's Avatar

The question mark gets displayed if the font_get function doesn't find a match for the character in your font file. If you are getting this, then the display seems to be working electrically.

When you say "completed" code, what code do you mean? Code you wrote or proven code from the forum?

Rick

December 04, 2011
by SirHobbes3
SirHobbes3's Avatar

When I say "completed" code, i am referring to the finished code that you get when you download the files for the led array. I say "completed" because Isn't the code supposed to display something like Hello? I'm still checking MY code for errors, and will report back.(maybe today(Sunday))

December 04, 2011
by SirHobbes3
SirHobbes3's Avatar

Hey Rick, I finally fixed the problems and now figured out how to write the characters to the array. I also found one of your modded codes and am also using it!!

December 04, 2011
by SirHobbes3
SirHobbes3's Avatar

YAY, my code is fixed and the test pattern works! But now I'm slightly stuck. I need someone to explain a little more on writing characters to the array.

Post a Reply

Please log in to post a reply.

Did you know that the microcontroller's crystal oscillator can be used to keep accurate time? Learn more...