2

I am using an Adafruit 64x32 RGB LED panel with my Arduino Mega 2560. I tried to find/construct working examples of a 32x32 or wider scrolling text/bitmap but have failed.

The smaller version is working and is calling two functions for it to implement:

loadSprite(IMAGES2,60);
bildmittig_sprite(data,dpink,300);
  • IMAGES2 is of type const PROGMEM byte IMAGES2[][8] and is an array of several 8x8 bitmaps
  • data is a buffer data array element, containing the dynamic movement of bitmaps, called in the void loop()

For the whole code here. For the video clip smaller scroller here.

For the video clip to what I would like to extend to:

Russian Letters: http://dropbox.com/s/n2ilxqgubn83ii9/MOV_0056.mp4?dl=0
Or Chinese Letters: http://dropbox.com/s/9rad116adc575u1/MOV_0057.mp4?dl=0

loadSprite() looks like this:

void loadSprite(const PROGMEM byte bild[][8],int anzahl) {
  for(int row=0; row < 8; row++) {
    //iterate through each row
    data[row] = 0;
    //reset the row we're working on
    for(int column=0; column < 8; column++) {
      //iterate through each column
      data[row] = data[row] + ((powers[column] & (pgm_read_byte(&(bild[index][row])) << offset)));
      //loads the current charachter offset by offset pixels
      data[row] = data[row] + (powers[column] & (pgm_read_byte(&(bild[index+1][row])) >> (8-offset)));
      //loads the next charachter offset by offset pixels
    }
  }
  offset++;
  //increment the offset by one row
  if(offset==8){offset = 0; index++; if(index==anzahl){index=0;}}
  //if offset is 8 load the next character pair for the next time through
}

The displaying function (places it i the middle of 32x32 panel) like this:

void bildmittig_sprite (byte bild[8],word cchsv, int duration) {
  for(int i = 0; i <8; i++) {
    for(int ii = 0; ii<8; ii++) {
      int bit = (bild[i] >> ii) & 1;
      if(bit == 0) {
        matrix.drawPixel(7-ii+12, 12+i, black);
      } else {
        matrix.drawPixel(7-ii+12, 12+i, cchsv);
      }
    }
  }
  delay(duration);
}

Working for 8x8 bitmaps, It eludes me how I could possible extend the coding (scrolling) for bitmaps like this:

const PROGMEM unsigned char rus5[] = {
  0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0xff, 0x03, 
  0x00, 0x00, 0x78, 0x00, 
  0x00, 0x00, 0x38, 0x00, 
  0x00, 0x00, 0x3c, 0x00, 
  0x00, 0x00, 0x1c, 0x00, 
  0x00, 0x00, 0x1c, 0x00, 
  0x00, 0x00, 0x1e, 0x00, 
  0x00, 0xfc, 0xde, 0x0f, 
  0x00, 0x8f, 0xef, 0x1f, 
  0x80, 0x07, 0x3f, 0x3c, 
  0xc0, 0x03, 0x0f, 0x3c, 
  0xe0, 0x01, 0x0f, 0x3c, 
  0xe0, 0x01, 0x07, 0x3c, 
  0xf0, 0x80, 0x07, 0x3c, 
  0xf0, 0x80, 0x03, 0x3c, 
  0x70, 0x80, 0x03, 0x1e, 
  0x78, 0xc0, 0x03, 0x1e, 
  0x78, 0xc0, 0x03, 0x0f, 
  0x78, 0xe0, 0x01, 0x0f, 
  0x78, 0xf0, 0x81, 0x07, 
  0xf0, 0xf8, 0xc3, 0x03, 
  0xf0, 0xef, 0xf6, 0x01, 
  0xe0, 0xf7, 0x7c, 0x00, 
  0x00, 0xf0, 0x00, 0x00, 
  0x00, 0x70, 0x00, 0x00, 
  0x00, 0x70, 0x00, 0x00, 
  0x00, 0x78, 0x00, 0x00, 
  0x00, 0x78, 0x00, 0x00, 
  0x00, 0x7c, 0x00, 0x00, 
  0x80, 0xff, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0x00
};

I tried variants of concatenation, like:

  • 4 bytes as a row, stitching together several with beforehand created data (data1 ... data4) elements (also adjust coherence for vertical elements).
  • And then have them displayed at the correct place to be able to use the existing code but so far only vertical concatenation seemed to work briefly.

I am at the end of my wits for this project, but maybe somebody else sees a better way.

1 Answer 1

0

I've looked at your code briefly, long enough to get the impression that each array like rus5[] contains 32 groups of 4 bytes each, with each 4-byte group representing a row of a character. [If not, let me know.] Also, I read the question a time or two, but don't see specified what direction you want to scroll, and whether you will scroll a string of characters or just one character. Anyhow, in following I suppose you want to scroll a string horizontally with characters entering at the right end of the display and scrolling off the left end.

To support horizontal scrolling, arrange your bit maps such that each group of 4 bytes represents the 32 bits of a single column of the display. Regarding four bytes as an unsigned long, suppose the LSB (least significant bit) corresponds to the top LED in a column. Use code like the following to set pixels, supposing cn = current column number; d = number of character columns already scrolled off, in range 0 to 31; maxCol = number of display columns; and t[] is a three-character string corresponding to three characters currently on the 64x32 display. [That is, a right-hand part of t[0] is at the left end of display; then all of t[1] appears; then a left-hand part of t[2].] [Generally, where this sets cc=0, you would set it to point at a current-character in a longer string, instead of at the first character in a three-character array t[]; and would advance one character each time d gets up to 32.]

cc = 0;     // index of first character to display
c = t[cc];  // first character to display
e = d;      // how far we have scrolled so far
for (cn=0; cn<maxCol; ++cn) {
  unsigned long colData = pgm_read_dword(charData[c][e]);
  for (ro=0; ro<32; ++ro) {
    matrix.drawPixel(cn, ro, (colData&1)? cchsv : black);
    colData >>= 1; // discard used-up bit
  }
  ++e;
  if (e >= 32) {  // Done with current character?
    c = t[++cc];  // Set c to next character
    e = 0;        // Start with leftmost col of character
  }
}

Edit 1: In the code above, charData[c][e] is an unsigned long int. Its 32 bits represent column e of ascii character c, with the LSB representing the top-row pixel. To create charData[][], write a program on your development system that reads whatever bitmaps you have now and writes out code to properly set up charData[][] in ProgMem.

Note, for initial scroll-testing, you could skip writing a development-system program to re-orient characters and instead test with character-data arrays as they are. Characters might display sideways or upside down, but would scroll ok anyway. Or, if bytes are not in proper Endianness to be an unsigned long, they would display in four mis-ordered slices.

Edit 2 With the following code,

void  scroller (const PROGMEM byte bildo1[][4],const PROGMEM byte bildo2[][4],int maxCol, word cchsv) {

int d = 0;
int cc = 0; 
unsigned long c[32];

for(int ii=0;ii<32;ii++) {
  c[ii]=0;      
  c[ii] += (long) pgm_read_byte(&(bildo1[ii][0]))<< 24;
  c[ii] += (long) pgm_read_byte(&(bildo1[ii][1]))<< 16;
  c[ii] += (long) pgm_read_byte(&(bildo1[ii][2]))<< 8;
  c[ii] += (long) pgm_read_byte(&(bildo1[ii][3]));
}
int e = d;      // how far we have scrolled so far
for (int cn=0; cn<maxCol; ++cn) {
  unsigned long colData = c[e];
  for (int ro=0; ro<32; ++ro) {
    matrix.drawPixel(cn, ro, (colData&1)? cchsv : black);
    colData >>= 1; // discard used-up bit
  }
  ++e;
  if (e >= 32) {  // Done with current character?
    for(int ii=0;ii<32;ii++) {
      c[ii]=0;       
      c[ii] += (long) pgm_read_byte(&(bildo2[ii][0]))<< 24;
      c[ii] += (long) pgm_read_byte(&(bildo2[ii][1]))<< 16;
      c[ii] += (long) pgm_read_byte(&(bildo2[ii][2]))<< 8;
      c[ii] += (long) pgm_read_byte(&(bildo2[ii][3]));
    }
    e = 0;        // Start with leftmost col of character
  }
}}

chrisoutwright reports getting an image like the following [cropped from a larger dropbox.com image]:

mixed up house

Cutting this into 4 equal-size horizontal slices and swapping slices top to bottom, we get: mirrored house

That image suggests packing the bytes in reverse order, eg via

c[ii] += (long) pgm_read_byte(&(bildo2[ii][0]));
c[ii] += (long) pgm_read_byte(&(bildo2[ii][1]))<< 8;
c[ii] += (long) pgm_read_byte(&(bildo2[ii][2]))<< 16;
c[ii] += (long) pgm_read_byte(&(bildo2[ii][3]))<< 24;

Continuing on, if we rotate the left half of the above 90° then flip the rotated image left to right we get a reasonable facsimile of the letter 春 :

ok Chinese character for house

The "flip left to right" amounts to reading bits out MSB first instead of LSB first. During testing, one might do that by saying

matrix.drawPixel(cn, ro, (colData&(1<<31))? cchsv : black); colData <<= 1;

instead of

matrix.drawPixel(cn, ro, (colData&1)? cchsv : black); colData >>= 1;

but in the longer run, a development-system program should be used to re-orient characters instead of using up MCU memory space and time for bitmap organizing.


To make the characters scroll, add a parameter (eg, byte escroll) to the calling sequence. Discard variable d if it isn't used within scroller, and instead of initializing e to d (which is always zero hence does not allow for scrolling) initialize it via

e = escroll;

In the routine that calls scroller(), say something like

byte es=0;
while (scrolling) {
  scroller(bildo1, bildo2, maxCol, cchsv, es);
  delay(msPerScrollStep);
  ++es;
  if (es >= 32) {
    es = 0;
    // do stuff here about next characters to display
  }
}

That is, call scroller() within a scroll-timing loop (or perhaps put the timing into scroller(), whichever meshes better with overall design).

Note, with the code as it stands, plus suggested changes, bildo2 will scroll in a second time1 unless a third character is supplied to scroll in.

1For example, with maxCol of 64, if es is 16, whenscroller() is called, e will go from 16 to 31 displaying the second half of bildo1, then from 0 to 31 displaying all of bildo2, then from 0 to 15 displaying the front half of bildo2.

9
  • I have taken a brief look at the code above. How is charData[c][e] defined exactly? Also is it true that one would not see a combination of "bitmaps" with the code above, as the column-scanning needs finishing the first letter? Nevertheless I will have a go with it as soon as I am at the working table. Thank you very much so far jwpat7 Feb 7, 2017 at 20:24
  • @chrisoutwright, see edit 1. The code shown displays characters adjacently as it scrolls them across, so portions of first and third characters show up, plus all of the middle, 1-2-3 left to right. If you need a blank column between chars, do that within the “Done with current character” section. Feb 7, 2017 at 21:37
  • at jwpat7, would you mind to integrate the code into a callable function? I tried it myself but am getting invalid types when trying to obviate the charData[c][e] step (can I use a pointer variable to store rus5[] and others together to get something like the mentioned t[cc] ?) Feb 7, 2017 at 22:28
  • I suppose, for testing purposes only testing two bitmap[32][4], such a function would not work? Feb 7, 2017 at 22:54
  • In that code the type of c[][] isn't shown, but probably should instead be unsigned long c[32], with the loop that loads c something like for(int j=0; j<32; ++j) { c[j]=0; for(int i=0; i<4; ++i) { c[j] = (c[j]<<8) | pgm_read_byte(&(bildo1[j][i]));}} (if I correctly understand bildo1) and if an endianness problem occurs, try bildo1[j][4-i] instead. Feb 7, 2017 at 23:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.