Sunday, August 5, 2018

Storing Data in Non-Standard Ways

While working on another BasicStamp project I found that I needed to store a lot of short sequences of instructions, specifically the addresses of the custom characters needed to to draw big fonts on an alphanumeric display.

Each big font letter is 2 blocks tall and between 2 and 4 blocks wide, each of those blocks can be filled with 1 of 7 custom characters, a blank space or a completely filled block. Its possible to just write a subroutine for each letter, but that would mean a lot of copying and pasting of code and I would have to find a way to convert the string I want to write into a series of subroutine calls.

In the interest of keeping my code short and making things modular I settled on using 2 subroutines to write strings of big font letters to the screen, the first one takes a string of 1-5 characters and looks up their character writing instructions and handles spacing on the screen. The second subroutine takes the character writing instructions and uses them to actually write custom characters to the LCD in the correct place.

The character writing instructions are 5 to 9 digit (base 10) integers, the first 4-8 digits are the custom character codes (0 = top left corner, 1 = top right corner ... 6 = lower bar, etc) in rights to left, top to bottom order, followed by a single digit that indicates the width of the big font letter (e.g. 0124563 where 3 is the big letter's width). To make them easy to look up, each code is stored in an array with an index equal to the value of each letter's ascii code ("A" = 65, "B" = 66...), that way I can take letters from a string, convert them to their ASCII code and use that value to look up the big font instruction.

So now that I had a way to turn a string of characters into a series of instruction codes I needed to be able to dissect the codes, one digit at a time. Had I used HEX values instead of base 10, I could just bitmask 0F to read out the least significant digit and then bitshift to the right by 4 bits to get rid of the current digit and move the rest down one place.

charCode = 1112223
width = charCode AND &H0F = 3
charCode = charCode >> 4 = 111222

But, had I used HEX values the 4 character wide letters' instructions that were larger than could be stored in an integer on the BasicStamp. So I went with base 10 numbers and ended up finding a more universal solution to the problem of taking apart an integer written in any base. To get the value of the least significant digit I use the modulus function, MOD 10 in this case, then I get the quotient (division without the remainder or decimal) of the integer and 10 to shift all the digits to the right while dropping the current "ones" digit.

charCode = 1112223
width = charCode MOD 10 = 3
charCode = charCode / 10 = 111222

By repeatedly using the MOD and quotient functions I could extract each digit and use them to write the correct shape to the correct location. So now my big string writing process looks like this:

Pass a 1 to 5 digit string and location to the bigString sub
bigString looks up the 5 to 9 digit charCodes in the charCode array
bigString passes the charCode and location to the bigLetter sub
bigLetter uses the charCode to write the letter to the LCD in the correct location
bigString calculates the location for the next letter
bigString passes the charCode and location to the bigLetter sub

By using this approach I can create new big font letters by simply adding entries to the charCode array and I have avoided having dozens of subroutines to cover each letter.

No comments:

Post a Comment