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.

Project Help and Ideas » LED array help

December 19, 2011
by jfreethy
jfreethy's Avatar

Hello, this is my first post on this forum so please bear with me. I have been working on the nerd kits led array project for a few nights now and I have run into a problem. When I run my ledarray_education code, I get a jumble of LED’s lit of the screen. So I thought that maybe being new to programming I did not write the proper code. So being rather frustrated I ran the code supplied by the fine people at nerd kits and I get an identical jumble!

I have run the test pattern several times and it starts in the upper left corner and worked in way right and down. So I believe that it is working correctly on the hardware side.

Basically I wanted to have the marquee display a very simple display of the words “ There’s room for everyone on the nice list” for my wife’s class room but this is turning into a major project.
Any help would be greatly welcomed!!
Thanks, J

December 19, 2011
by BobaMosfet
BobaMosfet's Avatar

First, go-slow. There's a lot to easily miss when it's all new to you. Secondly, can you please provide either as schematic (not as you want it to work, but as it is really wired) or provide several relatively clear shots, from different angles, of your breadboard? Some source-code here too, is appreciated :P

Welcome and Happy HoHo! We should be able to help you get this going for your wife's class!

BM

December 20, 2011
by jfreethy
jfreethy's Avatar

board setup Video link to the test pattern. http://smg.photobucket.com/albums/v193/skibladerj/?action=view&current=testpattern.mp4 video link to the fallowing code. http://smg.photobucket.com/albums/v193/skibladerj/?action=view&current=ledarray_nerdkitscode.mp4 This is the code copied from my nerd kits template file. (sorry if i post the code wrong);

// 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 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('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);
  //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;
}
December 20, 2011
by hevans
(NerdKits Staff)

hevans's Avatar

Hi jfreethy,

I'm not positive, but I think you might have gotten the anode and cathode columns backwards when you were soldering the kit up. Its tough to be sure from the test patter, but it looks like they are not lighting up in order but instead skipping one and then going back from left to right. You will be able to see this effect more clearly if you slow down the test pattern, just change the calls to delay(30) to delay(500), that should be enough to let you see if that is what is going on.

Humberto

December 20, 2011
by jfreethy
jfreethy's Avatar

Humberto, you are a wise man :) that is my problem! Can this be corrected easier with code or will i have to re solder the leds :?

Jason

December 20, 2011
by jfreethy
jfreethy's Avatar

I think i might have answered my own question LOL.

December 20, 2011
by jfreethy
jfreethy's Avatar

okay well my flash of knowledge didnt last long. I still am at a loss but i believe the answer lies with in this section of code;

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, 3*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));
  }  
}
December 21, 2011
by hevans
(NerdKits Staff)

hevans's Avatar

Hi jfreethy,

It should be solvable in software, and will actually be a pretty good exercise. That is in fact the piece of code that needs to change. Basically you need to swap the direction the column drivers are driving the LED, and also swap the direction the direction the rows are sinking or sourcing current. Give it a shot, and let me know if you get stuck.

Humberto

December 21, 2011
by jfreethy
jfreethy's Avatar

eveving Humberto and et al,

I was unable to manipulate the code to reverse the drivers for the cols. I kinda of needed this project to come to a close for tomorrow morning as its the last day befor school is out for my wife. That being said, if someone could help me, or better yet give me a finalized code that would be greatful! jason

December 22, 2011
by hevans
(NerdKits Staff)

hevans's Avatar

Hi jfreethy,

I think if take the snippet above and swap the 1 and the 0 at the end of lines 17 and 26, it will switch the direction the column drivers go. Then swapping lines 20 and 29 will reverse the direction the row drivers go at every step. I think that should do it.

Humberto

December 23, 2011
by jfreethy
jfreethy's Avatar

Sorry for the delay in response. I spent Wenesday night working on the code all night . . . But found the answeres I seeked. The code supplied with my nerd kits I believe might have a flaw in it. Or it could just have been a problem with my wirining. The original codw lines 52 -80;

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

Code that was modified from the full code at the end of the post lines 52-80;

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

This next modification corrected my mistake and fixed the drivers for cols and rows. This is the original code, lines 104- 126;

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

Followed by my modified code lines 104-126;

  // 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), 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), 0); 
    } 
    // activate row driver SOURCE 
    PORTB |= (1 << (PB1 + real_row)); 
    DDRB |= (1 << (PB1 + real_row)); 
  }   
}

Finaly my working completed code modified from a version that Rick_S produced;

// ledarray.c 
// for NerdKits with ATmega168 
// mrobbins@mit.edu 
// Modified by JASON FREETHY

#define F_CPU 14745600

#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), 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), 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     characters     if it's greater than zero, decrement  
                // both the offset (character display position), and     next_offset(character end position) 
                if(next_offset > 0) { 
                    offset -= 1; 
                    next_offset -= 1; 
                } 
                // display the character at the new position 
                font_display(x, offset);  
            } 
        } else { 
            // 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     shifted into full 
    // 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();

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

    ledarray_blank();

scroll_display(PSTR("THERE IS ROOM FOR EVERYONE ON THE NICE LIST"),150);

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

ledarray_blank();

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

    ledarray_blank();

scroll_display(PSTR("THERE IS ROOM FOR EVERYONE ON THE NICE LIST"),150);

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

Thank you everyone for your help, Merry chirstmas and Happy Holidays

Jaosn

June 09, 2012
by sollows
sollows's Avatar

Many thanks for posting this . I suffered the same problem as you did and this code made everything work. I think I wired up the LED;s in reverse . But the good news is I actually have scrolling words now after many hours of scratching my head and drinking massive amounts of coffee. But I do need further help, HOW CAN I ADD THE TEST PATTERN CODE TO THE ABOVE CODE. I tried copy and paste to the end of this code but it didnt compile . Any suggestions ? I am complete Newbie ? Last time I did programming it was in Commodore basic. Thanks.

June 09, 2012
by jfreethy
jfreethy's Avatar

I will replay with the code when i get home work

June 10, 2012
by jfreethy
jfreethy's Avatar

Being rather new at coding myself I would heed my advice with a gain of salt. The test pattern I used in my code was a modified line of code written by (Rick_S) which produces the "twinkle effect". I take it you want to have it run the test pattern as in they all turn on and then turn off one at a time? If that's the case than the fix is pretty simple. When combining codes I found the first thing to look at is what part of each original code is similar, meaning what don't I need to copy. Then I look at what part of the code is different.

We want to take the "ledarry_testpattern" coding from the original test code which is lines 157-174 on my screen from the ledarray_test code.

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

Now we need to find "ledarray_testpattern" coding in the working scrolling code. We find that in two places lines 197-223 and 421-448.You will have to replace both blocks of coding for it to work properly.

I hope that helps!

Jason

June 10, 2012
by sollows
sollows's Avatar

Thanks Jason, I will give it a try .

Post a Reply

Please log in to post a reply.

Did you know that hobby servos are controlled through a particular kind of PWM (Pulse Width Modulation) signal? Learn more...