don't quite understand function

Discussion in 'Programmer's Corner' started by Bear_2759, Feb 22, 2012.

  1. Bear_2759

    Thread Starter Active Member

    May 23, 2008
    120
    0
    hi guys, so I'm still a noob to C++ and having trouble with some basics. have a rough idea about some pointers but still havent fully grasped the idea yet.
    I have a nokia 6100 LCD and Arduino, it works great, but what I want to do is alter the default font table and instead of it being a 8x16 font I want a 16x32 font. modifying the font table is easy enough. would be helpfull if anyone can tell me a good font to binary converter though so I dont have to do it manually.
    the part I'm having trouble with, is understanding where in the following code it is defined/limited to 8x16.

    Code ( (Unknown Language)):
    1. void setChar(char c, int x, int y, int fColor, int bColor)
    2. {
    3.     //y    =    (COL_HEIGHT - 1) - y; // make display "right" side up
    4.     //x    =    (ROW_LENGTH - 2) - x;
    5.  
    6.     int             i,j; //integer up to -32K -> +32Kish
    7.     unsigned int    nCols; //unsigned 0 -> 65Kish
    8.     unsigned int    nRows;
    9.     unsigned int    nBytes;
    10.     unsigned char   PixelRow;
    11.     unsigned char   Mask;
    12.     unsigned int    Word0;
    13.     unsigned int    Word1;
    14.     unsigned char   *pFont;
    15.     unsigned char   *pChar;
    16.                                    
    17.     // get pointer to the beginning of the selected font table
    18.     pFont = (unsigned char *)FONT8x16;
    19.     // get the nColumns, nRows and nBytes
    20.     nCols = *pFont;
    21.     nRows = *(pFont + 1);
    22.     nBytes = *(pFont + 2);
    23.     // get pointer to the last byte of the desired character
    24.     pChar = pFont + (nBytes * (c - 0x1F)) + nBytes - 1;
    25.     // Row address set (command 0x2B)
    26.     LCDCommand(PASETP);
    27.     LCDData(x);
    28.     LCDData(x + nRows - 1);
    29.     // Column address set (command 0x2A)
    30.     LCDCommand(CASETP);
    31.     LCDData(y);
    32.     LCDData(y + nCols - 1);
    33.     // WRITE MEMORY
    34.     LCDCommand(P_RAMWR);
    35.     // loop on each row, working backwards from the bottom to the top
    36.     for (i = nRows - 1; i >= 0; i--) {
    37.         // copy pixel row from font table and then decrement row
    38.         PixelRow = *pChar++;
    39.         // loop on each pixel in the row (left to right)
    40.         // Note: we do two pixels each loop
    41.         Mask = 0x80;
    42.         for (j = 0; j < nCols; j += 2)
    43.         {
    44.             // if pixel bit set, use foreground color; else use the background color
    45.             // now get the pixel color for two successive pixels
    46.             if ((PixelRow & Mask) == 0)
    47.                 Word0 = bColor;
    48.             else
    49.                 Word0 = fColor;
    50.             Mask = Mask >> 1;
    51.             if ((PixelRow & Mask) == 0)
    52.                 Word1 = bColor;
    53.             else
    54.                 Word1 = fColor;
    55.             Mask = Mask >> 1;
    56.             // use this information to output three data bytes
    57.             LCDData((Word0 >> 4) & 0xFF);
    58.             LCDData(((Word0 & 0xF) << 4) | ((Word1 >> 8) & 0xF));
    59.             LCDData(Word1 & 0xFF);
    60.         }
    61.     }
    62. }
    I assume it may also have something to do with the following
    Code ( (Unknown Language)):
    1. const unsigned char FONT8x16[97][16] = {
    2. 0x0C,0x0C,0x3E,0x63,0x61,0x60,0x3E,0x03,0x03,0x43,0x63,0x3E,0x0C,0x0C,0x00,0x00,
    3. }
    97 is pretty close to the length of the font table (I didnt count, that's an assumption), and I'm assuming 16 is the number of bytes per character. the hex values in the code above are for the character "$". I thought it best to leave out the rest of the font table and just have one as an example:rolleyes:

    I've spent hours looking up code sites for any clues/hints that help me understand this better, and it has helped a bit. but pointers are still a bit confusing. mainly * and it's used allot in this.
     
  2. MrChips

    Moderator

    Oct 2, 2009
    12,432
    3,360
    Can you show me the first line of the font table: FONT8x16[0][0]?
     
  3. Bear_2759

    Thread Starter Active Member

    May 23, 2008
    120
    0
    first 3 lines as follows

    Code ( (Unknown Language)):
    1. 0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    2. 0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    3. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     
  4. K7GUH

    Member

    Jan 28, 2011
    191
    23
    Before you waste a lot of time on this, check to see if the font table is 8 X 16 because of a hardware limitation.
     
  5. Bear_2759

    Thread Starter Active Member

    May 23, 2008
    120
    0
    good point, but it would be hard for me to do this without understanding exactly how the function and font table works.

    there are other binary format images stored in a similar way in some of the example programs that would be much bigger than the font table so with my limited knowledge I doubt it. but can't be sure without fully understanding how it works.
     
  6. MrChips

    Moderator

    Oct 2, 2009
    12,432
    3,360
    Ok, thanks for providing the info. It is just as I thought.

    Those first three lines you show contain no character font. The programmer is using the first three bytes (8, 16, 16) to store the size of the font.

    The * operator serves two separate purposes, somewhat related.
    The first purpose is to identify a variable of type pointer, for example:

    unsigned char *pChar

    What is a pointer? A pointer is a memory location (usually of size equal to the native word length, in this case, maybe 16 bits) that can hold a memory address. Hence pChar holds an address. The part "unsigned char" is only important to the compiler for type checking. All pointers will be one memory location regardless of the variable type.

    So treat pChar as a variable containing an address.

    The second purpose of the * operator is, it is called the indirection operator.

    If ch is a char variable defined as

    unsigned char ch;

    I can do:

    ch = *pChar;

    That is, get the address in pChar and fetch the character at this address.
    Why are pointers important? Here are two examples.

    1) If you have a character string or a large array that you wish to pass to a subroutine, you do not want to pass all the values of the array to the routine. All you need to pass is the address of the start of the string or array.

    2) If your subroutine needs to modify a parameter that has been passed to it, you need to know where that parameter is stored. Hence you pass a pointer, not the value. This is what is know as passing parameters by reference versus passing by value.

    The other related and useful operator to be aware of is the address operator &.
    I can set a pointer by using this operator:

    pChar = &ch;

    This gets the memory address of the variable ch and sets in into the pChar variable.

    So in your program:

    Code ( (Unknown Language)):
    1.  
    2. nCols = *pFont;
    3. nRows = *(pFont + 1 );
    4. nBytes = *(pFont + 2);
    5.  
    is simply extracting information on the size of the font from the first three bytes of the font table. You could just have written:

    Code ( (Unknown Language)):
    1.  
    2. nCols = 8;
    3. nRows = 16;
    4. nBytes = 16;
    5.  
    If you are going to increase the font width to 16, you will have to plan seriously how you will manipulate 16-bit information. Your font table will have to be unsigned int or you can use a pair of bytes.

    Secondly, most LCD graphics displays work with 8-bit data. You will have to transfer the 16 bits as a pair of bytes.
     
  7. Bear_2759

    Thread Starter Active Member

    May 23, 2008
    120
    0
    thanks for all the info, it really helped. I worked it out now... please feel free to criticise, it's the only way I'll learn. but at this point I now have a 16x32 "!" on my screen.
    here's what I did.

    I tested using unsigned int instead of unsigned char like you said but the screen just went blank and I couldnt work out why, probably just because I'm still a noob. so instead of having 16-bit values in the font table, I left it as 8-bit values but had twice as many per character.
    here's how the "!" appears in the font table

    Code ( (Unknown Language)):
    1. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x0F,0xF0,0x1F,0xF8,0x1F,0xF8,0x3F,0xFC,0x3F,0xFC,0x3F,0xFC,0x3F,0xFC,0x3F,0xFC,0x1F,0xF8,0x1F,0xF8,0x1F,0xF8,0x0F,0xF0,0x0F,0xF0,0x0F,0xF0,0x07,0xE0,0x07,0xE0,0x07,0xE0,0x03,0xC0,0x03,0xC0,0x00,0x00,0x01,0x80,0x07,0xE0,0x0F,0xF0,0x0F,0xF0,0x07,0xE0,0x01,0x80,0x00,0x00,
    now dont misinterpret this, every 2nd value corresponds to the 2nd half(right 8 bits) of the character. it alternates (left 8),(right 8),(left 8),(right 8), and so on.

    now there were several things I tried repeatedly but the one that worked, was to add another variable to the function, and run the setchar function twice, once for each half of the character.

    Code ( (Unknown Language)):
    1. void setChar(char c, int x, int y, int fColor, int bColor, int group)
    2. {
    3.     //y    =    (COL_HEIGHT - 1) - y; // make display "right" side up
    4.     //x    =    (ROW_LENGTH - 2) - x;
    5.  
    6.     int             i,j;
    7.     unsigned int    nCols;
    8.     unsigned int    nRows;
    9.     unsigned int    nBytes;
    10.     unsigned char   PixelRow;
    11.     unsigned char   Mask;
    12.     unsigned int    Word0;
    13.     unsigned int    Word1;
    14.     unsigned char   *pFont;
    15.     unsigned char   *pChar;
    16.     unsigned int    First8;
    17.     unsigned int    Seccond8;
    18.     unsigned int    Block;
    19.                                    
    20.     // get pointer to the beginning of the selected font table
    21.     pFont = (unsigned char *)FONT8x16;
    22.     // get the nColumns, nRows and nBytes. first two rows of font table define these.
    23.     nCols = *pFont;
    24.     nRows = *(pFont + 1);
    25.     nBytes = *(pFont + 2);
    26.     // get pointer to the last byte of the desired character
    27.     pChar = pFont + (nBytes * (c - 0x1F)) + nBytes - 1;
    28.     // Row address set (command 0x2B)
    29.     LCDCommand(PASETP);
    30.     LCDData(x);
    31.     LCDData(x + nRows - 1);
    32.     // Column address set (command 0x2A)
    33.     LCDCommand(CASETP);
    34.     LCDData(y);
    35.     LCDData(y + nCols - 1);
    36.     // WRITE MEMORY
    37.     LCDCommand(P_RAMWR);
    38.     // loop on each row, working backwards from the bottom to the top
    39.     for (i = nRows - 1; i >= 0; i--) {
    40.         // copy pixel row from font table and then decrement row
    41.                 Seccond8 = *pChar++;
    42.                 First8 = *pChar++;
    43.                 if (group == 0)
    44.                 {
    45.                   Block = Seccond8;
    46.                 }
    47.                 else if (group == 1)
    48.                 {
    49.                   Block = First8;
    50.                 }
    51.               // loop on each pixel in the row (left to right)
    52.         // Note: we do two pixels each loop
    53.         Mask = 0x80;
    54.         for (j = 0; j < nCols; j += 2)
    55.         {
    56.             // if pixel bit set, use foreground color; else use the background color
    57.             // now get the pixel color for two successive pixels
    58.             if ((Block & Mask) == 0)
    59.                 Word0 = bColor;
    60.             else
    61.                 Word0 = fColor;
    62.             Mask = Mask >> 1;
    63.             if ((Block & Mask) == 0)
    64.                 Word1 = bColor;
    65.             else
    66.                 Word1 = fColor;
    67.             Mask = Mask >> 1;
    68.                         // use this information to output three data bytes
    69.             LCDData((Word0 >> 4) & 0xFF);
    70.             LCDData(((Word0 & 0xF) << 4) | ((Word1 >> 8) & 0xF));
    71.             LCDData(Word1 & 0xFF);
    72.  
    73.         }
    74. }
    75. }
    and now the updated setStr function. runs the setchar function for the left side then the right side. for some reason, the right side was 1 pixel lower than the left side and it's now past midnight so too tired to work out why lol. so I just added the x = x - 1 before the right half of the character is printed and then after x = x + 1 otherwise the next character would be 1 pixel higher overall.

    Code ( (Unknown Language)):
    1. void setStr(char *pString, int x, int y, int fColor, int bColor)
    2. {
    3.   x = x + 16;    //starting X position
    4.   y = y + 8;    //starting Y postion
    5.   // loop until null-terminator is seen
    6.   while (*pString != 0x00) {    //*pString does not equal 0x00
    7.     // draw the character
    8.     char charselect;
    9.     charselect = *pString++;
    10.     setChar(charselect, x, y, fColor, bColor, 1);    //
    11.     y = y + 8;
    12.     x = x - 1;
    13.     setChar(charselect, x, y, fColor, bColor, 0);  
    14.     // advance the y position
    15.     y = y + 8;
    16.     x = x + 1;
    17.     // bail out if y exceeds 131
    18.     if (y > 131) break;
    19.   }
    20. }
    please criticise and remember this is what a noob came up with ;):D
     
  8. Bear_2759

    Thread Starter Active Member

    May 23, 2008
    120
    0
    one last problem that i need assistance with, the length of each character in the font table is now 64 hex values, 32x2 because each one is split in two.
    the first character works fine, but then the 2nd uses the 2nd half of the first and the first half of the 2nd. then the 3rd character uses the hex codes for the 2nd character. so...
    1st character uses 1-32
    2nd character uses 17-48
    3rd character uses 33-64

    where it should be
    1st uses 1-32
    2nd uses 33-64
    3rd uses 65-96
     
  9. MrChips

    Moderator

    Oct 2, 2009
    12,432
    3,360
    Comments:

    You do not have to use variables for nCols, nRows and nBytes.
    You can declare these as constants:

    #define NCOLS 16
    #define NROWS 32
    #define NBYTES 64

    How did you declare the font table?
    I would use

    unsigned char Font16x32[96][32];

    This would be my setStr function. I assume x is along the horizontal axis.

    Code ( (Unknown Language)):
    1.  
    2. void setStr(char *pString, int x, int y, int fColor, int bColor)
    3. {
    4.     char charselect;
    5.   // loop until null-terminator is seen
    6.   while (*pString != 0x00) {    //*pString does not equal 0x00
    7.     // draw the character
    8.     charselect = *pString++;
    9.     setChar(charselect, x, y, fColor, bColor, 1);
    10. // advance the x position
    11.     x = x + NCOLS;
    12.   }
    13. }
    14.  

    setChr( ) to come later.
     
  10. MrChips

    Moderator

    Oct 2, 2009
    12,432
    3,360
    The next question is how do you wish to define each character in the font table?
    Do you want to go left-right 32 times or
    left 32 times follow by right 32 times?
     
  11. Bear_2759

    Thread Starter Active Member

    May 23, 2008
    120
    0
    I'm pretty sure font table is delcared as [97][32]
    I tried setting NBytes as 64 but screen just went blank.
    left-right or left then right doesnt bother me, at the end of the day it wont make much difference.
    I'll have to check half this stuff later when I get home though.
     
  12. Bear_2759

    Thread Starter Active Member

    May 23, 2008
    120
    0
    actually font table was set as [97][16] but if I changed it to 32 nothing on the screen.
    defining nbytes ncols and nrows worked a treat. the 4 characters I've created so far are displaying on the screen like they should.
     
  13. MrChips

    Moderator

    Oct 2, 2009
    12,432
    3,360
    Just changing the values of NCOLS, NROWS, NBYTES would not make it work. You still have to work through the code and change that also.
     
  14. Bear_2759

    Thread Starter Active Member

    May 23, 2008
    120
    0
    sorry I was wrong, doesnt work for the full character table. only works if I comment out most of the character table. forgot about the 0-255 limit for unsigned char. I've changed it to unsigned int
    Code ( (Unknown Language)):
    1. const unsigned int FONT16x32[95][32] = {
    I've remved the first 2 lines where the original author had the values for nbytes, ncols etc. I've replaced most of the contents of the font table with
    Code ( (Unknown Language)):
    1. 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
    there's only 2 characters defined at the moment and that's 1 and !.
     
    Last edited: Feb 26, 2012
  15. Bear_2759

    Thread Starter Active Member

    May 23, 2008
    120
    0
    I've added this to the setchar function to split the 16-bit hex into two 8-bit blocks
    Code ( (Unknown Language)):
    1.  
    2.                 PixelRow = *pChar++;
    3.                 First8 = ((PixelRow & 0xFF00) >> 8);
    4.                 Seccond8 = (PixelRow & 0x00FF);
    5.  
    I'm working through the rest of the setchar function now to see how I can change it to get it to work.

    I added a second font table, the original 8x16 so I can print debug info to the screen and it's helped me get allot further now.
     
  16. MrChips

    Moderator

    Oct 2, 2009
    12,432
    3,360
    If you don't mind my asking, why do you want a 16 x 32 font? Those are large characters.
    How much memory do you have on the processor?
     
  17. MrChips

    Moderator

    Oct 2, 2009
    12,432
    3,360
    You could have broken up the array into pieces.

    unsigned int is ok too.

    That is going to be a lot of typing to do but it is doable. I did it for my 8x12 character set which you will see soon.
     
  18. Bear_2759

    Thread Starter Active Member

    May 23, 2008
    120
    0
    I want a font that large, partially for looks and partially so it can be viewed from a distance easier.

    the typing is ok, I dont mind doing that. it'll take me about 15minutes per character to do but that's why I've only created 2 characters in the font table so far.

    I've been working my way backwards through the setchar function to find where the issue is. I've been manually setting variables with values I know will work to see if it displays on the screen. at this point I've isolated it to the part that either reads the data from the font table, or the part that splits the 16bit string into two 8 bit.
     
  19. Bear_2759

    Thread Starter Active Member

    May 23, 2008
    120
    0
    right, so the issue is with
    Code ( (Unknown Language)):
    1.     pFont = (unsigned int *)FONT16x32;
    2.     pChar = pFont + (nBytes * (c - 0x1F)) + nBytes - 1;
    3.     for (i = nRows - 1; i >= 0; i--) {  
    4.     PixelRow = *pChar++;
    }
    this works fine for a 8x16 font table, but when I changed it to unsigned int I dont know what went wrong. as far as the complier is concerned it's still fine...

    if I specify an element in the array for PixelRow like this
    Code ( (Unknown Language)):
    1. PixelRow = FONT16x32[2][6];
    it works, I get that block printed to the screen. but if I do the following
    Code ( (Unknown Language)):
    1. PixelRow = FONT16x32[2][i];[/i]

    it does not work, as far as I know this SHOULD work, it's in the for loop, where i is constantly decrementing so I should actually be able to use this instead but for some reason my LCD doesnt like it.

    I'm going to keep trying things but if you can suggest anything please do.
     
  20. MrChips

    Moderator

    Oct 2, 2009
    12,432
    3,360
    I will give this a shot sometime later when I have more time.
    For now, this is how I would approach the problem

    Code ( (Unknown Language)):
    1.  
    2. // assuming
    3. const unsigned int FONT16x32[95][32] = {
    4. // first char is SP
    5. // second char is !
    6.  };
    7.  
    8. #define NCOLS   16
    9. #define NROWS   32
    10. #define COFFSET 32  // offset of first character into ASCII table
    11.    :
    12.    :
    13.  
    14. void setChar(char c, int x, int y, int fColor, int bColor)
    15. {
    16.  
    17.     int i, j;
    18.     unsigned int thisrow;
    19.     unsigned char left8, right8;
    20.     unsigned char *pFont;
    21.     unsigned char *pChar;
    22.       :
    23.       :                                
    24.     pFont = &FONT16x32;
    25.     pChar = pFont + (NROWS * (c - COFFSET));
    26.  
    27.     // loop for each row, we can fix up the order later
    28.     i = NROWS;
    29.     do
    30.     {
    31.        thisrow = *pChar++;
    32.        left8 = thisrow >> 8;
    33.        right8 = thisrow & 0x00FF;
    34.          :
    35.          :
    36.     } while (i--);
    37. }
    38.  
    I will check this for correct syntax later.
     
    Last edited: Feb 27, 2012
Loading...