Scott Gardner
Scott Gardner

Reputation: 41

LED Matrix using AVR Controller

I have created a 8x8 LED Matrix that is controlled by a mircocontroller (specifically Atmega8), an 8-bit shift register (HEF4794), and a driver array (MIC2981). The problem I having is that the pattern that is supposed to be displayed is not centered. It needs to be shifted to the left one column and down two rows. Any help would be much appreciated.

I got the idea for this project from here: http://www.instructables.com/id/LED-matrix-using-shift-registers/

/*
 * AVRGCC3.c
 *
 * Created: 4/28/2012 1:39:29 PM
 *  Author: Scott
 */ 

#define F_CPU 12000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include "font8x8.h"

#define ShiftPort   PORTC
#define ShiftDDR    DDRC
#define LatchPin    (1 << 0)
#define DataPin     (1 << 1)
#define ClkPin      (1 << 2)
#define OE          (1 << 3)

#define RowPort     PORTD
#define RowDDR      DDRD
#define RowPin0     (1 << 0)
#define RowPin1     (1 << 1)
#define RowPin2     (1 << 2)
#define RowPin3     (1 << 3)
#define RowPin4     (1 << 4)
#define RowPin5     (1 << 5)
#define RowPin6     (1 << 6)
#define RowPin7     (1 << 7)

#define ScrollSpeed 75  //How many milliseconds to pause before shifting columns left

typedef unsigned char u8;
typedef unsigned int u16;

u8 row_track = 0;

volatile u8 row_buffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

void Delay_ms(int cnt)  //Function delays a give number of milliseconds.  Depends on F_CPU being defined
{
  while (cnt-->0) _delay_ms(1);
}   

static inline void InitPorts(void)  //Function used once to initialize the ports
{
  ShiftDDR |= (LatchPin | ClkPin | DataPin | OE);   //Setup shift register control pins
  RowDDR |= (RowPin0 | RowPin1 | RowPin2 | RowPin3 | RowPin4 | RowPin5 | RowPin6 | RowPin7); //Setup row driver pins

  ShiftPort |= OE;
  RowPort |= RowPin0;               //Drive first row and enable shift registers

  ShiftPort |= LatchPin;                //Set latch pin high
  ShiftPort &= ~(ClkPin | DataPin);             //Set ClkPin and DataPin low
}

static inline void InitTimers(void) //Function used once to set up the timer
{
  TCCR1B |= 1<<WGM12 | 1<<CS11 | 1<<CS10;       //Start timer1 in CTC mode with prescaler of 64
  TIMSK |= 1<<OCIE1A;                   //Enable compare match interrupt
  OCR1A = 0x00BB;                   //Set compare value for 1 mSec
  sei();                        //Enable global interrupts
}

void Shift_Int(u8 shiftData)        //Function used to shift in data
{
  ShiftPort &= ~(LatchPin | ClkPin | DataPin);      //All pins low: LatchPin low signals a write operation

  for (char i=0; i<8; i++)
  {
    ShiftPort &= ~ClkPin;               //Set ClkPin low

    if (shiftData & (1<<i)) ShiftPort |= DataPin;       //Set DataPin high if current bit is 1
    else ShiftPort &= ~DataPin;             //Set DataPin low if current bit is 0

    ShiftPort |= ClkPin;                //Set ClkPin high to increment shift register
    ShiftPort &= ~DataPin;              //Set DataPin low to prepare for next write
  }

  ShiftPort |= LatchPin;                //Set LatchPin high to signal end of write operation
  ShiftPort &= ~(ClkPin | DataPin);             //Reset ClkPin and DataPin to low
}

void Write_Char(u8 pattern)     //Function that writes one pattern to the LED Matrix
{
  //Writes a char to the led matrix
  //Patterns come from font8x8[] in progmem (font8x8.h)
  pattern -= 32;                        
  char temp;
  for (char i=0; i<8; i++)              //Read one column of char at a time
  {
    temp = pgm_read_byte((char *)((int)font8x8 + (8 * pattern) + i));   //Get column from progmem
    for (char j=0; j<8; j++)                        //Cycle through each bit in column
    {
      //Write bits to appropriate row_buffer location
      if (temp & (1<<j)) row_buffer[8-j] |= 1<<(8-i);
      else row_buffer[8-j] &= ~(1<<(8-i));
    }
  }
}

int main(void)
{
    InitPorts();
    InitTimers();
    while(1)
    {
        for (char x = 0; x<255; x++)
        {
            Write_Char(x);
            Delay_ms(500);
        }

    }
}

ISR(TIMER1_COMPA_vect)              //Interrupt Service Routine handles the display.
{
  if(++row_track == 8) row_track = 0;       //Row tracking
  Shift_Int(row_buffer[row_track]);     //Shift in data for next row

  ShiftPort &= ~OE;             //Used to prevent ghosting
  if (row_track == 0)               //Shut down high side controller
  {
    RowPort &= ~(1<<7);             //If Row0 is next, shutdown Row7
  }
  else
  {
    RowPort &= ~(1<<(row_track-1));     //Shutdown previous row
  }

  ShiftPort |= LatchPin;            //Latch low side shift registers
  RowPort |= (1<<row_track);            //Drive high side controller
  ShiftPort |= OE;              //Used to prevent ghosting
}

Upvotes: 4

Views: 4001

Answers (1)

Justin
Justin

Reputation: 2372

It seems like you should be able to just change this code:

  //Write bits to appropriate row_buffer location
  if (temp & (1<<j)) row_buffer[8-j] |= 1<<(8-i);
  else row_buffer[8-j] &= ~(1<<(8-i));

Maybe to this, just a guess:

  //Write bits to appropriate row_buffer location
  if (temp & (1<<j)) row_buffer[6-j] |= 1<<(7-i);
  else row_buffer[6-j] &= ~(1<<(7-i));

Changing the 8's to 6's for the rows and the 8's to 7's for the columns. It is possible you might have to mess with the loops so you don't end up writing to out of bounds memory, but that is where it looks like it is setting pixels, so just see what changing the row and column numbers does and you should be able to figure out how to center it.

Upvotes: 3

Related Questions