[Solved]how to simplify createChar() custom character written to 2X16 lcd?

Here are some of the code. I need to use " lcd.write(byte(0));" and I need to count the location every time. It's very hard work. is there a simpler way? such as using "sprintf ?? if so, how can I do it? thank you

if(mode==1){
  lcd.setCursor(0,0);
  lcd.write(byte(0)); //time icon
  
  lcd.setCursor(9,0);
  lcd.write(byte(0));  //time icon
  
  lcd.setCursor(11,0);
  lcd.print("PigOS");    
  
  lcd.setCursor(1,1);
  lcd.print("Mode  +  -  OK");    
  
  lcd.setCursor(0,1);
  lcd.write(byte(5)); //button icon
  
  lcd.setCursor(6,1);
  lcd.write(byte(5)); //button icon

  lcd.setCursor(9,1);
  lcd.write(byte(5)); //button icon 
  
  lcd.setCursor(12,1);
  lcd.write(byte(5)); //button icon 
  
  char timeStamp[8];
  sprintf(timeStamp, "%02d:%02d:%02d", HR,MIN,SEC);
  lcd.setCursor(1, 0);   
  lcd.print(timeStamp);  
}

if(mode==2){
  lcd.setCursor(0,0);  
  lcd.write(byte(2));  //battery icon
  
  lcd.setCursor(11,0);  
  lcd.write(byte(2));  //battery icon  

  lcd.setCursor(1,0);  
  lcd.print("Discharger"); 
  
  lcd.setCursor(12,0);  
  lcd.print("Test"); 
  
  char shuntRead[14];
  sprintf(shuntRead,"%04dmA %04dMah",shuntMa, shuntMah);
   lcd.setCursor(1, 1); 
  lcd.print(shuntRead);   
}

if(mode==3){
lcd.clear();
}

got many of them already

byte timeIcon[8] = {
    0b11111,
    0b10001,
    0b01010,
    0b00100,
    0b00100,
    0b01010,
    0b10001,
    0b11111};

byte tempIcon[8] = {
        0b00100,
    0b01011,
    0b01010,
    0b01011,
    0b01110,
    0b11111,
    0b11111,
    0b01110};

byte batteryIcon[8] = {
    0b01110,
    0b11011,
    0b10001,
    0b11111,
    0b10001,
    0b11111,
    0b10001,
    0b11111};

byte settingIcon[8] = {
    0b00000,
    0b10101,
    0b01110,
    0b11011,
    0b01010,
    0b11111,
    0b00100,
    0b00000};

byte arrowupIcon[8] = {
    0b00100,
    0b00100,
    0b01110,
    0b11111,
    0b00100,
    0b01110,
    0b01110,
    0b01010};

byte buttonIcon[8] = {
    0b00000,
    0b11111,
    0b10001,
    0b10101,
    0b10101,
    0b10001,
    0b11111,
    0b00000
};

Sorry, but I don’t understand the problem. What is it that you have to count every time ?

I don't understand very well the question too. What you don't like the lcd.setCursor() or the lcd.write(byte(x));?

Are you looking for a tool to help design the characters?

http://omerk.github.io/lcdchargen/

UKHeliBob: Sorry, but I don't understand the problem. What is it that you have to count every time ?

The location of the icons that needed to be printed in certain location. such as lcd.setCursor(0,0); ===lcd.setCursor(9,0); 9 and 0. If there a way to simplify it, so the icon and text goes to one value, and print that value out in a line instead of counting the location of every icon and print it out one by one?

lcd.setCursor(0,0); lcd.write(byte(0)); //time icon

lcd.setCursor(9,0); lcd.write(byte(0)); //time icon

luisilva: I don't understand very well the question too. What you don't like the lcd.setCursor() or the lcd.write(byte(x));?

lcd.setCursor and lcd.write(byte(x)) are great, but I have a lot of icon to write. i want to know if there is a way to combine icon+text to a value, then print in all out at the same time, so I don't need to count the location to which my cursor is set to.

cattledog: Are you looking for a tool to help design the characters?

http://omerk.github.io/lcdchargen/

I already have created few characters using this tool. this is great tool indeed.

You can create a function to do that. Like:

lcdPrintXYIcon(byte X, byte Y, byte icon) {

  lcd.setCursor(X, Y);
  lcd.write(byte(icon));
}

You can do a function like this to print text too:

lcdPrintXYText(byte X, byte Y, char* text) {

  lcd.setCursor(X, Y);
  lcd.print(text);
}

Then you can call it:

if(mode==1){
  lcdPrintXYIcon(0, 0, 0);

  lcdPrintXYIcon(9, 0, 0);
  
  lcdPrintXYText(11, 0, "PigOS");    
  
  lcdPrintXYText(1, 1, "Mode  +  -  OK");    
  
  lcdPrintXYIcon(0, 1, 5); 
  
  lcdPrintXYIcon(6, 1, 5); 

  lcdPrintXYIcon(9, 1, 5); 

  lcdPrintXYIcon(12, 1, 5); 
  
  char timeStamp[8];
  sprintf(timeStamp, "%02d:%02d:%02d", HR,MIN,SEC);
  lcdPrintXYText(1, 0, timeStamp);  
}

if(mode==2){
  lcdPrintXYIcon(0, 0, 2);  //battery icon
  
  lcdPrintXYIcon(11, 0, 2);  //battery icon

  lcdPrintXYText(1, 0, "Discharger"); 
  
  lcdPrintXYText(11, 0, "Test"); 
  
  char shuntRead[14];
  sprintf(shuntRead,"%04dmA %04dMah",shuntMa, shuntMah);
  lcdPrintXYText(1, 1, shuntRead);   
}

if(mode==3){
lcd.clear();
}

You can even do something like:

#define TIME 0
#define BATTERY 2
#define BUTTON 5

And then call they like:

if(mode==1){
  lcdPrintXYIcon(0, 0, TIME);

  lcdPrintXYIcon(9, 0, TIME);
  
  lcdPrintXYText(11, 0, "PigOS");    
  
  lcdPrintXYText(1, 1, "Mode  +  -  OK");    
  
  lcdPrintXYIcon(0, 1, BUTTON); 
  
  lcdPrintXYIcon(6, 1, BUTTON); 

  lcdPrintXYIcon(9, 1, BUTTON); 

  lcdPrintXYIcon(12, 1, BUTTON); 
  
  char timeStamp[8];
  sprintf(timeStamp, "%02d:%02d:%02d", HR,MIN,SEC);
  lcdPrintXYText(1, 0, timeStamp);  
}

if(mode==2){
  lcdPrintXYIcon(0, 0, BATTERY);  //battery icon
  
  lcdPrintXYIcon(11, 0, BATTERY);  //battery icon

  lcdPrintXYText(1, 0, "Discharger"); 
  
  lcdPrintXYText(11, 0, "Test"); 
  
  char shuntRead[14];
  sprintf(shuntRead,"%04dmA %04dMah",shuntMa, shuntMah);
  lcdPrintXYText(1, 1, shuntRead);   
}

if(mode==3){
lcd.clear();
}

I don't know if I answer you question or not. BTW, I don't try the code.

luisilva: You can create a function to do that. Like:

lcdPrintXYIcon(byte X, byte Y, byte icon) {

  lcd.setCursor(X, Y);   lcd.write(byte(icon)); }




You can do a function like this to print text too:
lcdPrintXYText(byte X, byte Y, char* text) {

lcd.setCursor(X, Y);
lcd.print(text);
}

Then you can call it:


if(mode==1){   lcdPrintXYIcon(0, 0, 0);

  lcdPrintXYIcon(9, 0, 0);     lcdPrintXYText(11, 0, "PigOS");        lcdPrintXYText(1, 1, "Mode  +  -  OK");        lcdPrintXYIcon(0, 1, 5);     lcdPrintXYIcon(6, 1, 5);

  lcdPrintXYIcon(9, 1, 5);

  lcdPrintXYIcon(12, 1, 5);     char timeStamp[8];   sprintf(timeStamp, "%02d:%02d:%02d", HR,MIN,SEC);   lcdPrintXYText(1, 0, timeStamp);  }

if(mode==2){   lcdPrintXYIcon(0, 0, 2);  //battery icon     lcdPrintXYIcon(11, 0, 2);  //battery icon

  lcdPrintXYText(1, 0, "Discharger");     lcdPrintXYText(11, 0, "Test");     char shuntRead[14];   sprintf(shuntRead,"%04dmA %04dMah",shuntMa, shuntMah);   lcdPrintXYText(1, 1, shuntRead);    }

if(mode==3){ lcd.clear(); }




You can even do something like:


define TIME 0

define BATTERY 2

define BUTTON 5




And then call they like:


if(mode==1){   lcdPrintXYIcon(0, 0, TIME);

  lcdPrintXYIcon(9, 0, TIME);     lcdPrintXYText(11, 0, "PigOS");        lcdPrintXYText(1, 1, "Mode  +  -  OK");        lcdPrintXYIcon(0, 1, BUTTON);     lcdPrintXYIcon(6, 1, BUTTON);

  lcdPrintXYIcon(9, 1, BUTTON);

  lcdPrintXYIcon(12, 1, BUTTON);     char timeStamp[8];   sprintf(timeStamp, "%02d:%02d:%02d", HR,MIN,SEC);   lcdPrintXYText(1, 0, timeStamp);  }

if(mode==2){   lcdPrintXYIcon(0, 0, BATTERY);  //battery icon     lcdPrintXYIcon(11, 0, BATTERY);  //battery icon

  lcdPrintXYText(1, 0, "Discharger");     lcdPrintXYText(11, 0, "Test");     char shuntRead[14];   sprintf(shuntRead,"%04dmA %04dMah",shuntMa, shuntMah);   lcdPrintXYText(1, 1, shuntRead);    }

if(mode==3){ lcd.clear(); }




I don't know if I answer you question or not.
BTW, I don't try the code.

thank you. that does simplify the code a lot, but still have to count the location to print out those icon and text.

there is no way to do something using "sprintf" to combine Icons+text+ values to "something" and print it out all in a line?

as you can see from my photo. the first line consist of: icon+"time value "+icon+text. Is there a way to combine these together, then print it out? that is my question.

OK. Now I understand the question. I'm sorry about that.

Maybe something like this:

lcdPrintXYSpecialLine(byte X, byte Y, char* text) {

  lcd.setCursor(X, Y);
   while (*text) {
      Serial.write(*text++);
   }
}

To create the string to send to the LCD you need to know 1 thing. You CAN NOT record any "icon" in the first position of the memory (address 0x00). So, you need to change this:

#define TIME 0

Then, you can do:

  char myText[17];
  sprintf(myText, "%c%02d:%02d:%02d %c  PigOS", TIME, HR, MIN, SEC, TIME);
  lcdPrintXYSpecialLine(0, 0, myLine);

  sprintf(myText, "%cMode %c+ %c- %cOK", BUTTON, BUTTON, BUTTON, BUTTON);
  lcdPrintXYSpecialLine(0, 1, myLine);

One more time I didn't try it, so be careful.

luisilva is correct and you can get this working with sprintf. As he says, it is important to not use address 0x00 as the custom characters are numbered 1 through 8. There is also a significant memory cost to using sprintf, and my sketch had about a 1500 byte increase over just calling lcd.print with the formatting.

The following test sketch works for me

#include <Wire.h>
#include <LiquidCrystal_I2C.h> 
LiquidCrystal_I2C lcd(0x27,4,5,6,0,1,2,3,7,NEGATIVE);//mjkdz board

byte timeIcon[8] = {
	0b11111,
	0b10001,
	0b01010,
	0b00100,
	0b00100,
	0b01010,
	0b10001,
	0b11111};

byte  bell[8]  = {
  0x4, 0xe, 0xe, 0xe, 0x1f, 0x0, 0x4};

byte  heart[8] = {0x0, 0xa, 0x1f, 0x1f, 0xe, 0x4, 0x0};

void setup() {
  
  lcd.begin(16, 2);
  lcd.createChar(1,bell);
  lcd.createChar(2,heart);
  lcd.createChar(3,timeIcon);
  lcd.clear();
  
  delay(1000);
  
  char buffer[16];

  sprintf(buffer, "%c %c %c", char(0x02),char(0x01),char(0x03));
  lcd.print(buffer);
  
}
  

void loop() {
}

I do not think you can get a simple wrap to the second line with a larger buffer and more characters. The memory structure of the HD44780 lcd controller is not straight forward. Here’s a good reference:

http://web.alfredstate.edu/weimandn/lcd/lcd_addressing/lcd_addressing_index.html

luisilva: OK. Now I understand the question. I'm sorry about that.

Maybe something like this:

lcdPrintXYSpecialLine(byte X, byte Y, char* text) {

 lcd.setCursor(X, Y);   while (*text) {      Serial.write(*text++);   } }




To create the string to send to the LCD you need to know 1 thing. You CAN NOT record any "icon" in the first position of the memory (address 0x00). So, you need to change this:


define TIME 0




Then, you can do:


 char myText[17];  sprintf(myText, "%c%02d:%02d:%02d %c  PigOS", TIME, HR, MIN, SEC, TIME);  lcdPrintXYSpecialLine(0, 0, myLine);

 sprintf(myText, "%cMode %c+ %c- %cOK", BUTTON, BUTTON, BUTTON, BUTTON);  lcdPrintXYSpecialLine(0, 1, myLine);




One more time I didn't try it, so be careful.

thank you so much.

cattledog:
luisilva is correct and you can get this working with sprintf. As he says, it is important to not use address 0x00 as the custom characters are numbered 1 through 8. There is also a significant memory cost to using sprintf, and my sketch had about a 1500 byte increase over just calling lcd.print with the formatting.

The following test sketch works for me

#include <Wire.h>

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,4,5,6,0,1,2,3,7,NEGATIVE);//mjkdz board

byte timeIcon[8] = {
0b11111,
0b10001,
0b01010,
0b00100,
0b00100,
0b01010,
0b10001,
0b11111};

byte  bell[8]  = {
  0x4, 0xe, 0xe, 0xe, 0x1f, 0x0, 0x4};

byte  heart[8] = {0x0, 0xa, 0x1f, 0x1f, 0xe, 0x4, 0x0};

void setup() {
 
  lcd.begin(16, 2);
  lcd.createChar(1,bell);
  lcd.createChar(2,heart);
  lcd.createChar(3,timeIcon);
  lcd.clear();
 
  delay(1000);
 
  char buffer[16];

sprintf(buffer, “%c %c %c”, char(0x02),char(0x01),char(0x03));
  lcd.print(buffer);
 
}

void loop() {
}




I do not think you can get a simple wrap to the second line with a larger buffer and more characters. The memory structure of the HD44780 lcd controller is not straight forward. Here's a good reference:

http://web.alfredstate.edu/weimandn/lcd/lcd_addressing/lcd_addressing_index.html

this looks great to me, I will try it now. few questions:

1, why #include <Wire.h>?
2, char(0x02) is referring to lcd.createChar(2,heart); ? (is so, is it possible to use words instead of this 0x02?)

is so, is it possible to use words instead of this 0x02?

Yes. Use #defines as suggested in an earlier reply or use an enum data type. Either will allow you to use meaningful names that will be translated into numbers to access the corresponding user defined symbol.

arduinomagbit:
this looks great to me, I will try it now. few questions:

1, why #include <Wire.h>?
(…)

Because the LCD that the poster uses is an I2C LCD. In your case you don’t need it.

I don’t know how you can say that this:

   char buffer[16];

  sprintf(buffer, "%c %c %c", char(0x02),char(0x01),char(0x03));
  lcd.print(buffer);

is better than this:

  char myText[17];
  sprintf(myText, "%c%02d:%02d:%02d %c  PigOS", TIME, HR, MIN, SEC, TIME);
  lcdPrintXYSpecialLine(0, 0, myLine);

It didn’t work? You don’t understand something of what I did?

  sprintf(myText, "%c%02d:%02d:%02d %c  PigOS", TIME, HR, MIN, SEC, TIME);
  lcdPrintXYSpecialLine(0, 0, myLine);

What's the point of using sprintf() to format a buffer (myText) with data then outputting a different buffer (myLine) ?

Yes, good point. Of course that it was a bad copy/paste. (is the problem of write code at 3 AM, and not test it)

luisilva:

arduinomagbit:
this looks great to me, I will try it now. few questions:

1, why #include <Wire.h>?
(…)

Because the LCD that the poster uses is an I2C LCD. In your case you don’t need it.

I don’t know how you can say that this:

   char buffer[16];

sprintf(buffer, “%c %c %c”, char(0x02),char(0x01),char(0x03));
  lcd.print(buffer);




is better than this:


char myText[17];
  sprintf(myText, “%c%02d:%02d:%02d %c  PigOS”, TIME, HR, MIN, SEC, TIME);
  lcdPrintXYSpecialLine(0, 0, myLine);




It didn't work? You don't understand something of what I did?

it works now, everything and all. thank you so much.