Select a specific character from a font

Hello,

I would like to get help for getting a character from a font.

I have a Flipdot display with 28x28 "pixels" and want to display text on it.
The display and the selfmade driver board is running well.
I can switch on/off single dots and as well send patterns in byte format via SPI to the shift registers and
sink/source drivers will then flip the dots.

For displaying text my ideas is to

  1. create a user string
  2. select character by character of the user string
  3. get the ASCII code of the character
  4. select with this ASCII code the byte sequence of the font
  5. sent this byte sequence via SPI

I think that could be a way how to do it - but for point 3 and 4 I don't know how.

That's the font I want to use:

What I have done already is following. For testing I copied the byte sequence for some characters
from the font directly to my code and sent this via SPI. This works.

static unsigned char A5x7[] = {
0x7C, 0x12, 0x11, 0x12, 0x7C,       // A
};

static unsigned char B5x7[] = {
0x7F, 0x49, 0x49, 0x49, 0x36,       // B 
};

static unsigned char C5x7[] = {
0x3E, 0x41, 0x41, 0x41, 0x22,      // C 
};

static unsigned char P5x7[] = {
0x7F, 0x09, 0x09, 0x09, 0x06,       // P 
};

But now I want to do somethink like this:

String userstring = "Hello World!";


get ascii of H = 72 (this is the DEC of "H", or 0x48 in HEX);


Look into the font5x7.h where I can find DEC 72 or HEX 0x48;


H = 0x7F, 0x08, 0x08, 0x08, 0x7F;


SPI.transfer;

Loop for next character of the userstring.

When I check the font5x7.h I can't find the DEC 71 or HEX 0x48 where I can look for to select the correct bytes for "H".

I have no clue how to do it and also not if this is a good way. May be it is possible to get the complete userstring
at once in ASCII and byte sequence?

Many thanks for your help,
Theo

Hello

Something like this, will point to the first byte of 'H'

unsigned char * p = font5x7 + 5 * 'H';

Here an example : https://ideone.com/VHAJ13

Font tables are commonly declared as two-dimensional arrays, that tends to make the code a little simpler to implement because you can use the ASCII value as the 1st dimension, then cycle through the elements of the 2nd dimension.

// standard ascii 5x7 font
static unsigned char font5x7[256][5] = {
  {0x00, 0x00, 0x00, 0x00, 0x00},  // 0x00 (nul)
  {0x3E, 0x5B, 0x4F, 0x5B, 0x3E},  // 0x01 (soh)
  {0x3E, 0x6B, 0x4F, 0x6B, 0x3E},  // 0x02 (stx)
  {0x1C, 0x3E, 0x7C, 0x3E, 0x1C},  // 0x03 (etx)
  {0x18, 0x3C, 0x7E, 0x3C, 0x18},  // 0x04 (eot)
  {0x1C, 0x57, 0x7D, 0x57, 0x1C},  // 0x05 (enq)
  {0x1C, 0x5E, 0x7F, 0x5E, 0x1C},  // 0x06 (ack)
  {0x00, 0x18, 0x3C, 0x18, 0x00},  // 0x07 (bel)
  {0xFF, 0xE7, 0xC3, 0xE7, 0xFF},  // 0x08 (bs)
  {0x00, 0x18, 0x24, 0x18, 0x00},  // 0x09 (tab)
  {0xFF, 0xE7, 0xDB, 0xE7, 0xFF},  // 0x0A (lf)
  {0x30, 0x48, 0x3A, 0x06, 0x0E},  // 0x0B (vt)
  {0x26, 0x29, 0x79, 0x29, 0x26},  // 0x0C (np)
  {0x40, 0x7F, 0x05, 0x05, 0x07},  // 0x0D (cr)
  {0x40, 0x7F, 0x05, 0x25, 0x3F},  // 0x0E (so)
  {0x5A, 0x3C, 0xE7, 0x3C, 0x5A},  // 0x0F (si)
  {0x7F, 0x3E, 0x1C, 0x1C, 0x08},  // 0x10 (dle)
 .....

font5x7.h (11.8 KB)

Hello guix and hello david_2018,

many thanks for the quick and efficient help! :slight_smile:

Cheers,
Theo

NP,

Note that my example will only work for non-extended ASCII characters (0 to 127).

For characters above that, it will be much more complicated because in a char array, those characters are stored as multiple bytes (for example, 'é' is stored as 2 bytes)

It is fairly unusual to see a font that includes extended ASCII and non-printing characters, so I've modified the font file to show the bitmap pattern of the characters. Note that the characters are rotated 90 degrees.

font5x7.h (31.1 KB)

Wow, I hope you did not by hand :wink:

Many thanks for this!

guix,

I tried out your code and figured out that the code will not work for a string that has 3 or less characters. It just happend nothing.

May I ask you to take a look on the code?

Theo

Hello david_2018,

I tried your extended font5x7 file with the bitmaps in it, but it doesn't work with the code from guix.
It is now a 2 dimensional array as you said and the pointers will not work anymore.

This will lead me to the initial question: how can I search this font file for an ASCII code of a specific character and select the byte sequence for this character which I store than in an array.

Again, many thanks!!

Yes, show your code...

With his 2D array, you access the byte n of a character c, like this

font5x7[c][n]

For example, the second byte for 'H' is in...

font5x7['H'][1]

theodore_odore:
Wow, I hope you did not by hand :wink:

Many thanks for this!

No, I used a text editor with a few creative search and replace commands. I was mainly curious what was being displayed for the characters that are not part of the standard ASCII code.

Hello guix,

here is the code, it is mainly yours (I use it for en ESP8266 Wemos D1 mini).
I am currently using for this test not the extended font5x5 from david_2018.

In the code here in the post I am not showing the complete font5x7 as message said it is too large.

If am using in the string only an "A" the code is doing nothing.....

//  #include <iostream>
  
    static unsigned char font5x7[] = {
      0x00, 0x00, 0x00, 0x00, 0x00,  // 0x00 (nul)
      0x3E, 0x5B, 0x4F, 0x5B, 0x3E,  // 0x01 (soh)
      .....
      0x3E, 0x41, 0x41, 0x41, 0x22,  // 0x43 C
      0x7F, 0x41, 0x41, 0x41, 0x3E,  // 0x44 D
      0x7F, 0x49, 0x49, 0x49, 0x41,  // 0x45 E
      .....

    };


     
    
void setup() {

delay(1000);
  
Serial.begin(115200);

delay(1000);

Serial.print("Start");


//char str[] = "Hello World";
char str[] = "A";
     
      // store a pointer to the first character of the string
      char * p = str;
     
      // while the pointed character is not a null terminator
      while (*p)
      {
        // store the character, and increase pointer to the next character. c stored "H", "e", etc.
        char c = *p++;
        
        printf("'%c' = ", c);
        
        // store a pointer to the first byte for this character
        unsigned char * p2 = font5x7 + 5 * c;
     
        // print 5 bytes, from p2 to p2+4
        for (uint8_t i = 0; i < 5; i++)
        {
          printf("%02X ", *(p2+i));
          
          //test
          //char buf[20];
          //Serial.println("My try");
          //sprintf(buf, "0x%02X, ", *(p2+i));
          //printf("%s", buf);
          // end test
          
        }
     
        printf("\n");
      }
     
 //     return 0;


Serial.print("End");

}


void loop() {
}

I can't see why it wouldn't work, except that you have to replace printf by Serial.printf, of course (or alternatively, add Serial.setDebugOutput(true)).

That's strange.

If I am using the code with Serial.printf() then it works for an single character, e.g. "A".
If I am using the code with printf() then it works for equal or more then character only.

Both will print it to serial monitor.

Anyway: thank you again!

How do I bring the content of the pointer into an array?
I tried some code but I couldn't get it working.

On the serial monitor it is fine, but I want to create an array with the byte sequence for a character of the font.

I think I am mixing the types and the serial monitor is doing also a translation of the type of the pointer so that it is readable?

char buf[60];


//char str[] = "Hello World";
char str[] = "m";
     
// store a pointer to the first character of the string
char * p = str;
     
// while the pointed character is not a null terminator
while (*p)
{
    // store the character, and increase pointer to the next character. c stored "H", "e", etc.
    char c = *p++;
        
    Serial.printf("'%c' = ", c);
        
    // store a pointer to the first byte for this character
    unsigned char * p2 = font5x7 + 5 * c;
     
    // print 5 bytes, from p2 to p2+4
    for (uint8_t i = 0; i < 5; i++)
    {
        Serial.printf("0x%02X, ", *(p2+i));

 
        buf[i] = '0x' + *(p2+i);  
//     buf[i] = *(p2+i);

    }
    Serial.printf("\n");

    Serial.println("");
    Serial.println("Zeige außerhalb for an");
    Serial.println("");
    Serial.printf("%s", buf);
}

The content of the arry buf[] is only nonsens.

I want to store the pointer like this:

char buf[] = {
0x7C, 0x04, 0x78, 0x04, 0x78
};
char buf[60];
..
..
..
buf[i] = '0x' + *(p2+i);

Explain to us what you think this does.

I do not understand why you are using pointers with an array, why not use the array index?

This may be close to what you are wanting to do:

#include "font5x7.h"

unsigned char buf[60];

char str[] = "Hello World";
//char str[] = "m";

void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.println();

  for (size_t p = 0; p < strlen(str); p++)
  {
    // store the character
    char c = str[p];

    Serial.printf("'%c' = ", c);

    // print 5 bytes
    for (uint8_t i = 0; i < 5; i++)
    {
      Serial.printf("0x%02X, ", font5x7[5 * c + i]);
      buf[5 * p + i] = font5x7[5 * c + i];
    }
    Serial.print('\n');

  }
  
  Serial.println("");
  Serial.println("Zeige außerhalb for an");
  Serial.println("");
  for (size_t i = 0; i < sizeof(buf); i++)
  {
    Serial.printf("0x%02X ", buf[i]);
    if (((i + 1) % 5) == 0) //print 5 bytes per line
    {
      Serial.print('\n');
    }
  }
}

void loop()
{
}

TheMemberFormerlyKnownAsAWOL,
this was my attempt to add "0x" to the byte sequence of a character of the font5x7.

david_2018,
the pointers was the solution of guix to my questions, that's why I follow this approach.

Anyway, your last code was very helpfull for me, now I have it like I wanted! :slight_smile:

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.