Below is an Arduino sketch for a basic animation, taken from the book Beginning Arduino by Michael McRoberts. Also, the connections have been shown. From what I have read elsewhere, this is the standard kind of code used to drive a LED dot matrix using the 595 shift registry, or the like (for example the MAX7219). Regarding the functioning of the code, I have two questions.
For what percentage of the time will the LED stay lit? In the
screenupdate()
there are no set delays. Hence, each row will stay lit only for the time it takes for the Arduino to execute the remaining loop and come back with the updated row values. How do we know for what time will the LEDs be lit, and hence predict their brightness, or for what can we do to set a particular value for this?As I understand from the code, it works assuming that the ISR will fire as the code is running and will include all stages of the
led[]
. Although in this case it is not much significant, but how do we know that the ISR will fire including all the stages?If say we are updating each row of the matrix, to give a scroll effect, we would need the ISR to fire after each modification. How do we ensure this? If the ISR is too frequent, it may not let the code run. Or if it is too dispersed, the code may skip lines giving a jagged animation. Also, since the code would have some periodicity, is it not possible that some LED rows are always skipped? How do we determine the time of ISR firing perfect for the code or modify the code to ensure these do not happen(except trial and error)?
#include <TimerOne.h>
int latchPin = 8; //Pin connected to Pin 12 of 74HC595 (Latch)
int clockPin = 12; //Pin connected to Pin 11 of 74HC595 (Clock)
int dataPin = 11; //Pin connected to Pin 14 of 74HC595 (Data)
byte led[8]; // 8 element unsigned integer array to hold the sprite
void setup() {
// set the 3 digital pins to outputs
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
// Load the binary representation of the image into the array
led[0] = B11111111;
led[1] = B10000001;
led[2] = B10111101;
led[3] = B10100101;
led[4] = B10100101;
led[5] = B10111101;
led[6] = B10000001;
led[7] = B11111111;
// set a timer of length 10000 microseconds (1/100th of a second)
// and attach the screenUpdate function to the interrupt timer
Timer1.initialize(10000);
Timer1.attachInterrupt(screenUpdate);
}
// invert each row of the binary image and wait 1/4 second
void loop() {
for (int i = 0; i < 8; i++) {
led[i] = ~led[i];
}
delay (250);
}
// Display the image
void screenUpdate() {
byte row = B10000000; // row 1
for (byte k = 0; k < 8; k++) {
shiftOut(dataPin, clockPin, LSBFIRST, led[k] ); // LED array
shiftOut(dataPin, clockPin, LSBFIRST, ~row); // row binary number (active low)
// latch low to high to output data
digitalWrite(latchPin, LOW);
digitalWrite(latchPin, HIGH);
// bitshift right
row = row >> 1;
}
// Turn all rows off until next interrupt
shiftOut(dataPin, clockPin, LSBFIRST, 0);
shiftOut(dataPin, clockPin, LSBFIRST, ~0);
// latch low to high to output data
digitalWrite(latchPin, LOW);
digitalWrite(latchPin, HIGH);
}
ADDENDUM
In the above code, I tried putting Serial.println(micros())
in the screenUpdate()
loop, but I git a very confusing results in which the time displayed seemed to increase and then decrease randomly. I did not understand why. Has it got to do something with ISRs? Sorry for the apparently clumsy question.
I executed the following code (from the same book) out, which includes a MAX7219 driver (with the usual setup) and creates scrollable text. It worked perfectly well. And I just want to understand how this ISR and multiplexing go together, and how do we make sure the frequency is appropriate. More of an academic question rather than a practical one.
#include <avr/pgmspace.h>
#include <TimerOne.h>
int DataPin = 2; // Pin 1 on MAX
int LoadPin = 3; // Pin 12 on MAX
int ClockPin = 4; // Pin 13 on MAX
byte buffer[8];
#define SCAN_LIMIT_REG 0x0B
#define DECODE_MODE_REG 0x09
#define SHUTDOWN_REG 0x0C
#define INTENSITY_REG 0x0A
static byte font[][8] PROGMEM = {
// The printable ASCII characters only (32-126)
}
void clearDisplay() {
for (byte x=0; x<8; x++) {
buffer[x] = B00000000;
}
screenUpdate();
}
void initMAX7219() {
pinMode(DataPin, OUTPUT);
pinMode(LoadPin, OUTPUT);
pinMode(ClockPin, OUTPUT);
clearDisplay();
writeData(SCAN_LIMIT_REG, B00000111); // scan limit set to 0:7
writeData(DECODE_MODE_REG, B00000000); // decode mode off
writeData(SHUTDOWN_REG, B00000001); // Set shutdown register to normal operation
intensity(15); // Values 0 to 15 only (4 bit)
}
void intensity(int intensity) {
writeData(INTENSITY_REG, intensity); //B0001010 is the Intensity Register
}
void writeData(byte msb, byte lsb) {
digitalWrite(LoadPin, LOW); // set loadpin ready to receive data
shiftOut(DataPin, ClockPin, MSBFIRST, (msb));
shiftOut(DataPin, ClockPin, MSBFIRST, (lsb));
digitalWrite(LoadPin, HIGH); // latch the data
}
void scroll(char myString[], int rate) {
byte firstChrRow, secondChrRow;
byte ledOutput;
byte chrIndex = 0; // Initialise the string position index
byte Char1, Char2;
byte scrollBit = 0;
byte strLength = 0;
unsigned long time;
unsigned long counter;
while (myString[strLength]) { // Increment count till we reach the end of the string
strLength++;}
counter = millis();
while (chrIndex < (strLength)) {
time = millis();
if (time > (counter + rate)) {
Char1 = constrain(myString[chrIndex],32,126);
Char2 = constrain(myString[chrIndex+1],32,126);
for (byte y= 0; y<8; y++) {
firstChrRow = pgm_read_byte(&font[Char1 - 32][y]);
secondChrRow = (pgm_read_byte(&font[Char2 - 32][y])) << 1
ledOutput = (firstChrRow << scrollBit)
| (secondChrRow >> (8 - scrollBit) );
buffer[y] = ledOutput;
}
scrollBit++;
if (scrollBit > 6) {
scrollBit = 0;
chrIndex++;
}
counter = millis();
}
}
}
void screenUpdate() {
for (byte row = 0; row < 8; row++) {
writeData(row+1, buffer[row]);
}
}
void setup() {
initMAX7219();
Timer1.initialize(10000); // initialize timer1 and set interrupt period
Timer1.attachInterrupt(screenUpdate);
Serial.begin(9600);
}
void loop() {
clearDisplay();
scroll(" BEGINNING ARDUINO ", 45);
scroll(" Chapter 7 - LED Displays ", 45);
scroll(" HELLO WORLD!!! :) ", 45);
}