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
}