It enables a mixture of scrolling text and stationary text on the same display. It is a cut-down modified version of dmd.stepMarquee(). It only handles 'normal' horizontal, right to left, single step scrolling. It allow you to specify exactly what group of rows you want to scroll.
This is an additional function to add to the library so that no other library calls are impacted - fully backward compatible.
To use this, add the following function into the DMD.cpp file:
Code: Select all
//**************************************************************************************
// stepSplitMarquee(int topRow, int bottomRow)
// This is a cut-down modification of stepMarquee(). It steps only the rows specified.
// Only horizontal, single step, left scroll is catered for.
// This function allows you to have only a part of the DMD array scrolling, while the
// remainder stays still and is not cleared during scrolling.
//**************************************************************************************
boolean DMD::stepSplitMarquee(int topRow, int bottomRow)
{
boolean ret=false;
marqueeOffsetX += -1; // only scroll horizontally, 1 place left
if (marqueeOffsetX < -marqueeWidth) { // if text has scrolled off the screen
marqueeOffsetX = DMD_PIXELS_ACROSS * DisplaysWide; // set up to scroll again from the far right
drawFilledBox(0, topRow, DisplaysWide*DMD_PIXELS_ACROSS-1, bottomRow, GRAPHICS_INVERSE); // clear the scroll rows
ret=true; // indicates that this scroll has completed
}
// This is the main change from the original function.
// It splits the left shift task into rows and bytes within a row to allow rows to be identified
// and treated separately.
for (int row=topRow ;row<=bottomRow; row++) { // loop for each row in the scroll area
for (int byteInRow=0; byteInRow<DisplaysWide*4; byteInRow++) { // loop for each byte within a row (4 per DMD across)
int thisIndex = (DisplaysTotal*4)*(row%16) + (4*DisplaysWide*(row/16)) + byteInRow; //calculate index into screen buffer
if ((byteInRow%(DisplaysWide*4)) == (DisplaysWide*4) -1) { // if it's the last byte in a row
bDMDScreenRAM[thisIndex]=(bDMDScreenRAM[thisIndex]<<1)+1;
// shift bits left, and puts a '1' in last position (a '1' = LED OFF)
} else { // if it's NOT the last byte in a row
bDMDScreenRAM[thisIndex]=(bDMDScreenRAM[thisIndex]<<1) +
((bDMDScreenRAM[thisIndex+1] & 0x80) >>7);
// shift bits left as well as the shifting the MSB of the next byte into the LSB
}
}
}
// Redraw last char on screen
// required because
int strWidth=marqueeOffsetX;
for (byte i=0; i < marqueeLength; i++) {
int wide = charWidth(marqueeText[i]);
if (strWidth+wide >= DisplaysWide*DMD_PIXELS_ACROSS) {
drawChar(strWidth, marqueeOffsetY,marqueeText[i],GRAPHICS_NORMAL);
return ret;
}
strWidth += wide+1;
}
return ret;
}
Code: Select all
//Move the marquee left 1 place - special case of stepMarquee()
// which only scrolls a limited portion of the display
boolean stepSplitMarquee(int topRow, int bottomRow);
Here is a little demo sketch to demonstrate what it does and how to use it.
Code: Select all
/*
Test sketch for split screen scrolling
NOTE that this sketch uses the Freetronics version of the DMD library available here:
https://github.com/freetronics/DMD/
but with the additional dmd.stepSplitMarquee() function.
I also suggest that you make sure this has been changed DMD.cpp
change the line:
SPI.setClockDivider(SPI_CLOCK_DIV128);
to:
SPI.setClockDivider(SPI_CLOCK_DIV2); // system clock / 2 = 8MHz SPI CLK to shift registers
This provides a marked improvement in the DMD update time within the interrupt routine.
*/
#include "SPI.h"
#include "DMD.h"
#include "TimerOne.h"
#include "SystemFont5x7.h"
#define DISPLAYS_ACROSS 1
#define DISPLAYS_DOWN 1
DMD dmd( DISPLAYS_ACROSS , DISPLAYS_DOWN);
void ScanDMD()
{
dmd.scanDisplayBySPI();
}
void setup()
{
Timer1.initialize( 4000 ); // I find the default 5000 gives a visible flicker
Timer1.attachInterrupt( ScanDMD );
dmd.selectFont(SystemFont5x7);
dmd.clearScreen( true ); // start with a blank screen
}
void loop()
{
unsigned long time;
int n;
boolean ret = false;
// Show some stationary text on the bottom half, and scrolling text on the top half
// scrolls 3 times
dmd.drawString(0,8,"Stays still",11,GRAPHICS_NORMAL); // the stationary string
dmd.drawMarquee("Scrolling text",14,0,0); // set up the marquee
time = millis();
n=0;
while(n<3) {
while (!ret) {
if ((time+30) < millis()) {
ret = dmd.stepSplitMarquee(0,7); // parameters are the top & bottom rows to be scrolled
time = millis();
}
}
ret = false;
n++;
}
dmd.clearScreen( true );
// Now some stationary text on the top half, and scrolling text on the bottom half
// scrolls for 10 seconds
dmd.drawString(0,0,"Stays still",11,GRAPHICS_NORMAL); // stationary text
dmd.drawMarquee("Scrolling text",14,0,8); // set up the marquee
time = millis();
while ((millis() - time)<10000){ // loop for 10 seconds
dmd.stepSplitMarquee(8,15); // only scroll rows 8 to 15
delay(30);
} // a slightly different way to loop for stepping the marquee
// note that this does not test for completion of the scroll, but continues until
// the 10 second time has expired
dmd.clearScreen( true );
// Now a bit of fun
dmd.drawString(0,-4,"vvvvvvvvvvv",11,GRAPHICS_NORMAL); // note the position is above a single DMD so
// only part of the text will be visible
dmd.drawString(0,13,"^^^^^^^^^^^",11,GRAPHICS_NORMAL); // and this is too far down a single DMD so
// only part will be visible
// these 2 lines above use partial characters displayed on the screen by placing the text at non-standard positions
// to give a graphical highlight effect.
dmd.drawMarquee("Scrolling text",14,0,5);
time = millis();
while ((millis() - time)<10000){ // again we will scroll for 10 seconds
dmd.stepSplitMarquee(5,11);
delay(30);
}
dmd.clearScreen( true );
}
I hope someone else finds a use for it.
UPDATE:
I updated the stepSplitMarquee() code above to allow for multi-dimensional DMD arrays. Original version only worked for single DMD high but multiple DMDs wide.
Brissieboy