Code to Rotate a Font

DISCLAIMER: I’m an Arduino Newbie, so please don’t take anything I post here as gospel. With the disclaimer aside, I’ll share a challenge I encountered recently and a quick solution I came up with.

I wanted to make one of those cool scrolling text displays, out of some WS2812B light strips. There’s already a fair amount of documentation on these types of projects, so I won’t get into the wiring schematics or project specifics here.

After I had completed the hardware build and was able to get some basic colorwipe() tests working on the strips, I was ready to proceed with some code to make a text scroller.

My LED matrix is 48 pixels wide, by 8 pixels tall, so one of my next steps was to find a simple 8x8 pixel font, which would allow me to display about 6 characters on the screen horizontally, at any given time.

There’s a decent selection of 8x8 fonts out there and they’re generally setup as header files, which makes them easy to #include into your Arduino sketch.

I wrote some simple code to enumerate the font characters in the serial monitor window, so I could get a better idea of what they’d eventually look like on my LED matrix.

Code to Enumerate Font Characters:

#include "/.../font8x8.h" // use any 8x8 font here
;
void setup() {
  Serial.begin(9600);
  while (!Serial);  // wait for serial port to connect. Needed for native USB
  
  int  timer         = millis();
  byte tempChrByte   = 0;
  char tempChr       = ' ';

  for(int charNum=0; charNum <=100; charNum++) {
    Serial.println("Character #:" + String(charNum));
    for(int i=0; i<8; i++) {
      tempChrByte = pgm_read_byte_near(c64_font + (charNum * 8) + i);
      for(int j=7; j>=0; j--) {
          if(tempChrByte & (int)pow(2, j)) tempChr='*'; else tempChr=' ';
          Serial.print(tempChr);
      }
      Serial.print(" | 0x");
      Serial.println(tempChrByte, HEX);
    }
    Serial.println("");
  }
  Serial.println("Elapsed Byte Rotation Time: " + String(millis() - timer) + "ms");
  Serial.println("\n");
}

void loop() {
}

I was a bit surprised to see the output in my serial monitor window, which looked like this…

Character #:10
         | 0x0
         | 0x0
 *****   | 0x7C
 ******  | 0x7E
    * ** | 0xB
    * ** | 0xB
 ******  | 0x7E
 *****   | 0x7C

Character #:11
         | 0x0
         | 0x0
 ******* | 0x7F
 ******* | 0x7F
 *  *  * | 0x49
 *  *  * | 0x49
 ******* | 0x7F
  ** **  | 0x36

If you squint your eyes a bit, you’ll notice that the characters are are actually rotated onto their right side, which was a bit of a surprise.

I decided to write some quick and dirty code to rotate the characters to the left, into a more natural upright position, that would be easier for me to use with the LED matrix scroller.

Here’s what I came up with:

#include "/.../font8x8.h" // use any 8x8 font here

void setup() {
  Serial.begin(9600);
  while (!Serial);  // wait for serial port to connect. Needed for native USB
  
  int  timer         = millis();
  byte tempChrByte   = 0;
  char tempChr       = ' ';
  byte tempBuf[8]    = {0, 0, 0, 0, 0, 0, 0, 0};
  byte fontBuf[800];
  int  fontBufCtr    = 0; 

  for(int charNum=0; charNum <=100; charNum++) {
    Serial.println("Character #:" + String(charNum));
    for(int i=0; i<8; i++) {
      tempChrByte = pgm_read_byte_near(c64_font + (charNum * 8) + i);
      for(int j=7; j>=0; j--) {
          if(tempChrByte & (int)pow(2, j)) {
            tempChr='*';
            tempBuf[j] = tempBuf[j] << 1;
            tempBuf[j] = tempBuf[j] | 1;
          } else {
            tempChr=' ';
            tempBuf[j] = tempBuf[j] << 1;
          }
          Serial.print(tempChr);
      }
      Serial.print(" | 0x");
      Serial.println(tempChrByte, HEX);
    }
    Serial.println("");

    Serial.println("<< ROTATED LEFT <<");
    for(int k=0; k<8; k++) {
      for(int l=7; l>=0; l--){
        if(tempBuf[k] & (int)pow(2, l)) tempChr='*'; else tempChr=' ';
        Serial.print(tempChr);
      }
      fontBuf[fontBufCtr] = tempBuf[k];
      fontBufCtr++;
      Serial.print(" | 0x");
      Serial.println(tempBuf[k], HEX);
    }
    Serial.println("");
  }
  Serial.println("Elapsed Byte Rotation Time: " + String(millis() - timer) + "ms");
  Serial.println("\n");

  Serial.println("<< LEFT ROTATED CHARACTER BYTES <<\n");
  for(int m=0; m<=100; m++) {
    Serial.print("/* Char:" + String (m) + " */ " );
    for(int n=0; n<8; n++) {
      Serial.print("0x" + String(fontBuf[(m * 8) + n], HEX) + ", ");
    }
    Serial.println("");
  }
  Serial.println("");
}


void loop() {
}

This code will enumerate through each of the original font characters, followed by their left rotated versions, then it dumps hex-code at the bottom of the serial monitor, for a complete version of the font with rotated character.

Character #:10
         | 0x0
         | 0x0
 *****   | 0x7C
 ******  | 0x7E
    * ** | 0xB
    * ** | 0xB
 ******  | 0x7E
 *****   | 0x7C

<< ROTATED LEFT <<
    **   | 0xC
   ****  | 0x1E
  **  ** | 0x33
  ****** | 0x3F
  **  ** | 0x33
  **  ** | 0x33
  **  ** | 0x33
         | 0x0

Character #:11
         | 0x0
         | 0x0
 ******* | 0x7F
 ******* | 0x7F
 *  *  * | 0x49
 *  *  * | 0x49
 ******* | 0x7F
  ** **  | 0x36

<< ROTATED LEFT <<
  *****  | 0x3E
  **  ** | 0x33
  **  ** | 0x33
  *****  | 0x3E
  **  ** | 0x33
  **  ** | 0x33
  *****  | 0x3E
         | 0x0


<< LEFT ROTATED CHARACTER BYTES <<

/* Char:10 */ 0xc, 0x1e, 0x33, 0x3f, 0x33, 0x33, 0x33, 0x0, 
/* Char:11 */ 0x3e, 0x33, 0x33, 0x3e, 0x33, 0x33, 0x3e, 0x0,

You can simply code & paste this hex code into a new header file for your sketch.

There may be WAY better ways to do this, but the approach worked for me, so I thought I’d share.

Cheers and good luck!

Not at all to disparage your effort, it’s just that there is another forum for this kind of demonstration, the “showcase” forum.

by the way, this:

pow(2, j)

is not a reliable or efficient way to obtain integer powers of two. Because it uses a float representation, it can easily fail due to truncation error, and is orders of magnitude slower, and uses much more memory, than a simple bit shift left e.g.

1<<j

Thanks for letting me know about the showcase and the for the performance tip re: the pow() function!

Cheers!