Code to Rotate a 8x8 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 & 1<<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 & 1<<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] & 1<<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!

*NOTE: Special thanks for @AARG for pointing out a much faster way to handle powers of two!

aarg:

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