Step 5Code
The display code is interrupt driven, and uses the Timer1 library . Timer1 isn't bundled in the Arduino software installation. Therefore, to install it, you must download TimerOne.zip , and unzip its contents into your sketchbook/libraries/TimerOne.
A Frame is a screenful of data. A very straightforward and common way of storing the data would be to use a byte for each LED. This would use 25 bytes per frame. To save memory, we define it as an array of 5 bytes. Each byte represents an entire row of our display. Since a byte is composed of 8 bits, and we only have 5 LED's per row, we only use the bottom 5 bits, and the top 3 bits are ignored. There are 5 bytes because we have 5 rows. We could save another byte by packing 25 bits into 4 bytes, but that complicates the code unnecessarily, and makes it impossible to graphically view the frame declarations in frames.h.
#define DIM 5 // x/y dimension - 5x5 matrix
typedef byte Frame[DIM];
The column LED pins are defined in the cols array.
int cols[DIM] = {12,11,10,9,8};
The row LED pins are defined in the rows array.
int rows[DIM] = {7,6,5,4,3};
To turn on a particular LED, we set its cols pin HIGH and its rows pin LOW. This causes current to flow through the selected LED. The most straightforward way to do this would be to use the digitalWrite() function on each LED in sequence. So to turn on the top left LED, we could use
digitalWrite(cols[0],HIGH);
digitalWrite(rows[0],LOW);
and do that for each LED. However, that's not very efficient. Instead we use direct port manipulation to turn on the columns. The PORTB register corresponds to digital pins 8 to 13.
Note the ordering which we used in our declaration of the cols array above: 12,11,10,9,8. This way, bit0 of PORTB corresponds to the far right column, bit1 corresponds to the next column to the left, until bit4, which corresponds to the far left column. If we set a particular bit to 1, it's the same as calling digitalWrite() with HIGH, and setting a bit to 0 is equivalent to calling digitalWrite() with LOW. Therefore, we could theoretically replace calling digitalWrite() 5 times to set all 5 columns with one write to PORTB. But since we are allowed to turn on at most only 2 LED's at a time, we have to loop 3 times for each column, scanning 2 bits at a time.
// Interrupt routine
// each time display() is called, it turns off the previous row
// and turns on the next row
byte bitMask = B00000011;
void display() {
digitalWrite(rows[row], HIGH); // Turn whole previous row off
if (bitMask == B00010000) {
bitMask = B00000011; // light the right 2 columns (pins 9,8)
// increment row and wrap if necessary
if (++row == DIM) {
row = 0;
}
}
else if (bitMask == B00000011) {
bitMask = B00001100; // light the middle 2 columns (pins 11,10)
}
else { // bitMaskIdx == B00001100
bitMask = B00010000; // light the leftmost column (pin 12)
}
// direct port manipulation.
// PORTB is a pseudo variable for digital pins 8 to 13 The two high bits (6 & 7) map to the crystal pins and are not usable
// the bottom 5 bits are our columns. We don't want to change the other bits,
// so we first mask the bits we ignore, and then set the bits we want to light
PORTB &= B11100000;
PORTB |= curFrame[row] & bitMask;
digitalWrite(rows[row], LOW); // turn on the row
}
Note that our comment above says that display() is an interrupt routine. This is because instead of handling the scanning in our loop() function, we call it in the background via the Timer1 library.
// interrupt interval in uSec
// this determines how long to keep each row turned on
// so if we have 5 rows, we redraw the whole screen
// once every 5 rows * 3 cycles per row * 1000 usec = .015 sec -> 66.67Hz
// if you perceive flickering you can decrease to 500 for a 133.33Hz rate
Timer1.initialize(1000); // fire the interrupt every 1000 microseconds
Timer1.attachInterrupt(display); // call display() at every interrupt.
The main loop simply steps through all of our animation frames.
void loop() {
// increment the frame index and wrap if necessary
if (++curFrameIdx == FRAMECNT) {
curFrameIdx = 0;
}
// select frame for display
setFrame(curFrameIdx);
delay(400); // wait time between frames in ms - reduce this value to speed up the animation, increase it to slow it down
}
The entire sketch is attached below.
| « Previous Step | Download PDFView All Steps | Next Step » |
















































it says this was never declared
ive added two buttons to the program which are ment to display two different patterns depending on which button is pushed. currently i have it so when a button is pushed it displays the first frame and when it is pushed again it shows next frame, though i want it to display the full sequence. Any help would be greatly appreciated!
Many Thanks,
holmez
p.s. great post!
Brilliant project!
thanks again!
When i write
digitalWrite(cols[0],HIGH);
digitalWrite(rows[0],LOW);
entire 0 row lights up, not just (0,0) LED
//#define TESTMODE
by removing the leading // like this:
#define TESTMODE
and run the sketch and tell me what it looks like.
But before i proceed...
Does display () function must follow digitalWrite statements? I can fire up only one LED if display() follows them.
display() does all the writing to the ports. the columns are controlled from PORTB and the rows are controlled by digitalWrite().
back to your example yesterday:
digitalWrite(cols[0],HIGH);
digitalWrite(rows[0],LOW);
entire 0 row lights up, not just (0,0) LED
This is because you need to use digitalWrite(cols[i],LOW) to turn off all the other columns where i=1,2,3,4
Now it's ok.
Thank you very much for your help and great project.
The TimerOne Library wasn`t in the right place....
I´m working on a mac and there is no Arduino folder except in the dokuments folder..
Thank you for your help...
Make sure to use resistors, though! Also, their code turns on a whole row at a time instead, so unless you modify it to only turn on 2 LED's at a time, you will need to limit the current to 5mA each LED (40mA/8 = 5mA).
Did you unzip the Timer1 library to the libraries folder ?
i wan`t to run some frames from the file frames.h
but my Arduino only runs the testmode.
Could somebody help me?
(I am a newbie)
Hi, add " // " before " #define TESTMODE " to disable it.