Having trouble sending custom character data

I am fairly new to the electronics world but have done some programming a decade or so ago.
I am trying to learn how to operate an LCD without a library to better understand how everything works on a binary level.
I ran across a video while trying to learn how to create custom characters where he was using two basic functions (command() and data()) to do everything. It works for the most part, but when I display the custom character using this method, it clears the display and then displays the character in the first space no matter where the cursor is.
can someone help me? I have played with this for two days now and cant figure it out.
Note it works in another program ive written with the same basic setup only using functions for all commands ( displayOnOff(), functionSet(), clearScreen(); and so on).

I am using an 8 bit shift register with q0-q7 pins from the shift register connected to the corresponding d0-d7 pins on the LCD. The clear pin from the shift register is connect to positive and the oe pin is set negative.

I am new so take it easy pointing out all the newby mistakes. Also apologies in advanced if code is sloppy.

int rsPin=6;
int ePin=5;
int latchPin=11;
int clockPin=9;
int dataPin=12;
int dt1=5;
int dt2=5;
int dt3=5;
byte zero=0x30;
byte middleFinger[]{
  0x00,
  0x00,
  0x04,
  0x04,
  0x04,
  0x0E,
  0x1F,
  0x0F,
};
byte smileyChar[]{
  0x0A,
  0x0A,
  0x0A,
  0x00,
  0x11,
  0x11,
  0x0E,
  0x00,
};

void setup() {
  // put your setup code here, to run once:
  pinMode(rsPin,OUTPUT);
  pinMode(ePin,OUTPUT);
  pinMode(latchPin,OUTPUT);
  pinMode(clockPin,OUTPUT);
  pinMode(dataPin,OUTPUT);
  delay(dt1);
  command(0x38); //0x38 SETS 8 BIT MODE, 2LINES, 5X8 DOT MATRIX
  command(0x01); //0x01 clears screen
  command(0x0F);//0x0D SETS DISPLAY ON,CURSOR ON, BLINK ON  
} 

void loop() {
  // put your main code here, to run repeatedly:
  for(int x=0;x<8;x++){
   data(zero);
   zero++;
   delay(2500);  
  }  
  //for(int j=0;j<32;j++){//move cursor to line 2
    //command(0x14);  
  //}
  customChar(0x40);
  customChar(0x40);
  delay(10000);
  command(0x01);
  zero=0x30;
}


void command(byte myByte){
  digitalWrite(rsPin,LOW);
  delay(dt1);
  digitalWrite(latchPin,LOW);
  shiftOut(dataPin,clockPin,MSBFIRST,myByte);
  digitalWrite(latchPin,HIGH);
  digitalWrite(ePin,HIGH);
  delay(dt2);
  digitalWrite(ePin,LOW);
  delay(dt3);
}
void data(byte myByte){
  digitalWrite(rsPin,HIGH);
  delay(dt1);
  digitalWrite(latchPin,LOW);
  shiftOut(dataPin,clockPin,MSBFIRST,myByte);
  digitalWrite(latchPin,HIGH);
  digitalWrite(ePin,HIGH);
  delay(dt2);
  digitalWrite(ePin,LOW);
  delay(dt3);
}
void customChar(byte storage){
  command(storage);
  for(int i=0;i<8;i++){
    data(middleFinger[i]);
  }
  command(0x01); // this may be my issue. that is the command to clear code but it will not print without it
  data(0x00);
}

I was wrong about it working on the other program I wrote. It does the same thing.

Have you been able to successfully display a simple 'Hello World' type program before trying to deal with custom characters?

I ask this because your LCD initialization sequence is not correct. You are not doing the several initial 'function set' commands that should be done prior to your 'command(0x38)' step.

Check out LCD Initialization for all the details.

Don

Thanks. I will check that when I get home. Yes I've been able to do a simple hello world. I was able to get the counter from 1-8 to work. I will check that link out when I get off work

I've read that and really not sure what it's saying. Seems like it's Incase you lose power to your microcontroller but not your screen. Running function set again could cause issues depending on what the last instruction you sent to the screen was.

I built this circuit with buttons connected to a shift register and was able to program custom letters by hand so I should be able to fix my code. Thanks for your help.
I'd recommend everyone learn to manually send a character display instructions. You learn a lot

Along those lines you might enjoy reading this: How to use Intelligent L.C.D.s.

Don

1 Like

Solved

int rsPin=6;
int ePin=5;
int latchPin=11;
int clockPin=9;
int dataPin=12;
int dt1=5;
int dt2=5;
int dt3=5;
byte zero=0x30;
byte middleFinger[]{
  0x00,
  0x00,
  0x04,
  0x04,
  0x04,
  0x0E,
  0x1F,
  0x0F,
};
byte smiley[]{
  0x0A,
  0x0A,
  0x0A,
  0x00,
  0x11,
  0x11,
  0x0E,
  0x00,
};
byte horns[]{
  0x00,
  0x00,
  0x00,
  0x11,
  0x11,
  0x11,
  0x1B,
  0x1F
};
byte peace[] = {
  0x00,
  0x00,
  0x05,
  0x05,
  0x05,
  0x1E,
  0x1F,
  0x1F
};
byte crisscross[] = {
  0x0A,
  0x04,
  0x0A,
  0x11,
  0x0A,
  0x04,
  0x0A,
  0x11
};
byte house[] = {
  0x04,
  0x0A,
  0x11,
  0x1F,
  0x11,
  0x15,
  0x15,
  0x1F
};
byte moonMan[] = {
  0x04,
  0x0E,
  0x1B,
  0x11,
  0x1B,
  0x0E,
  0x0A,
  0x11
};
byte moreHeadThanBody[] = {
  0x0E,
  0x0E,
  0x0E,
  0x04,
  0x1F,
  0x15,
  0x15,
  0x15
};

void setup() {
  // put your setup code here, to run once:
  pinMode(rsPin,OUTPUT);
  pinMode(ePin,OUTPUT);
  pinMode(latchPin,OUTPUT);
  pinMode(clockPin,OUTPUT);
  pinMode(dataPin,OUTPUT);
  command(0x38); //0x38 SETS 8 BIT MODE, 2LINES, 5X8 DOT MATRIX
  command(0x01); //0x01 clears screen
  command(0x0F);//0x0D SETS DISPLAY ON,CURSOR ON, BLINK ON
}

void loop() {
  // put your main code here, to run repeatedly:

  // skip 40 spaces to the start of line 2
  command(0x02);
  for(int j=0;j<40;j++){
    command(0x14); // skips 40 lines to get to 2nd line
  }

  //print my custom characters to screen.
  //this can be done before or after character is defined
  //ive chosen to do it now to watch it build.
  data(0x00); //0x00 adress to print first custom character
  data(0x01); // address to print 2nd custom charater 
  data(0x02); // third character location
  data(0x03); // 4th
  data(0x04); // 5th
  data(0x05); // 6th
  data(0x06); // 7th
  data(0x07); // 8th
  command(0x02);
  
  //count 0-7 on top line
  for(int x=0;x<8;x++){
   data(zero);
   zero++;
   delay(2500);
  }
  zero=0x30;// sets back to zero

  //define my custom characters
  command(0x40); //0x40 is the start of first address used to store char data
  //send character data to next 8 adresses 
  sendCharData(smiley);
  
  command(0x48); // start of second adresses
  //send character data to next 8 adresses
  sendCharData(middleFinger);

  //fill the remaing 6 all at once
  command(0x50); // start of 3rd adresses 
  sendCharData(horns);
  //fill next 8
  sendCharData(peace);
  //next 8
  sendCharData(crisscross);
  //next 8
  sendCharData(house);
  //fill next 8
  sendCharData(moonMan);
  //next 8
  sendCharData(moreHeadThanBody);
  //next 8  

  
  delay(5000);
  blankStorage();//use to clear character data again for viewing purposes 
  command(0x01);
}

void command(byte myByte){
  digitalWrite(rsPin,LOW);
  delay(dt1);
  digitalWrite(latchPin,LOW);
  shiftOut(dataPin,clockPin,MSBFIRST,myByte);
  digitalWrite(latchPin,HIGH);
  digitalWrite(ePin,HIGH);
  delay(dt2);
  digitalWrite(ePin,LOW);
  delay(dt3);
}
void data(byte myByte){
  digitalWrite(rsPin,HIGH);
  delay(dt1);
  digitalWrite(latchPin,LOW);
  shiftOut(dataPin,clockPin,MSBFIRST,myByte);
  digitalWrite(latchPin,HIGH);
  digitalWrite(ePin,HIGH);
  delay(dt2);
  digitalWrite(ePin,LOW);
  delay(dt3);
}
void sendCharData(char myByte[]){
  for(int i=0;i<8;i++){
    data(myByte[i]);
    delay(750);    // (not needed) delay to watch it as it builds the character (not needed);
  }
}
void blankStorage(){
  for(int i=0;i<64;i++){
    data(0x00);
  }
}

You are still not initializing your LCD in accordance with the datasheet.

This code may be fine for the particular display you are using today but may not work on a different one tomorrow. Just keep that in mind if you have problems in the future.

Don

1 Like

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