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 » multi_panel_array_spi

February 05, 2010
by ton_mit
ton_mit's Avatar
 Hello all again...I am trying to program multi array with spi and am having trouble.................with the programs from(ledarray_spi)master, slave and extras I downloaded from nerdkits all I have changed is the number of arrays.I have built and flashed the Atmega 328p's master and slave controllers and wired only one array until I get the programing down. When I turn it on a question mark (?) will scroll across the array then nothing else. Is this normal for not being hooked up to a stream? If so.....that will mean that I actually built it right(the first time) and I can proceed.

What I really want is to have a character string that can be edited to say "whatever I want" like I did with just the single led array I have been working on. I am learning C through Nerdkits and am loving all the projects they have to offer. I know Basic, QBasic, Visual Basic but its been a while. Here is the code that I used for the single array build. How do I integrate this into the ledarray_spi master and slave programs? btw all of the Atmega 328p's that I use were preloaded and purchased from nerdkits and I am using Programers Notepad. // This program will make text scroll //atmega328p

#include <stdio.h>

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

#include "../libnerdkits/io_328p.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);
    }
  }
}

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

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 scroll_display(const char *s) {
  // clear display
  ledarray_blank();
  int8_t offset = 0 , next_offset = 0;
  uint8_t is_started = 0;
  uint8_t i=0;
  char x=' ';

  // 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(90);
                // 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(90);
        ledarray_left_shift(); 
        if(next_offset > 0) {
            offset -= 1;
        next_offset -= 1;
    }
    font_display(x, offset); 
    }

   delay_ms(90);
   // this final loop shifts the display all the way off.
   for(i=0;i<COLS;i++){
    ledarray_left_shift();
    delay_ms(90);
    }

    return;
}
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////

int main() {
  ledarray_init();

  // activate interrupts
  sei();

  uint8_t i, j;

  while(1)
    for(i=0;i<ROWS;i++) {
      for(j=0;j<COLS;j++) {
        ledarray_set(i,j, 0);
        delay_ms(30);
      }
     scroll_display(PSTR("WHATEVER I WANT"));
     }

   for(i=0;i<ROWS;i++) {
      for(j=0;j<COLS;j++) {
        ledarray_set(i,j, 0);
        delay_ms(30);
        return(0);
      }
     }
    }
February 08, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi ton_mit,

The ? that runs across the screen when you first turn it on is normal. This happens because there is a character sent when the serial port starts up. The easiest way to see if you have built the spi array correctly is to send characters to it over the serial port. With the current "ledarray_master" code on our website you should be able to send characters using Putty to the master chip, who should then send the characters to your led_arrays.

Humberto

February 08, 2010
by ton_mit
ton_mit's Avatar

Thank you, I will try that.

February 15, 2010
by ton_mit
ton_mit's Avatar

Still working on the multi panel array.....will keep ya'll posted.

                                      ton_mit

Post a Reply

Please log in to post a reply.

Did you know that Morse code is a compact way to transmit human-readable text over binary channels? Learn more...