How to create new custom character using LCD HD44780.

Go To Last Post
26 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First of all, sorry for my English.  English is not my native language.

So, I have a problem with custom symbols on LCD.

First  of all I had created my custom character

const char customChar[8] = {
	0b00011,
	0b00011,
	0b11110,
	0b10010,
	0b10000,
	0b10000,
	0b10010,
	0b11110
};

Then I sent the command to LCD for set of  CGRAM adress.

LCD_send_command(0b00100000); //CGRAM adress is zero.

I transfer to specified adress an array of custom character.

for (uint8_t i=0; i!=8; i++)
		LCD_send_data(customChar[i]);

 Nothing works. Where is my error?

Of course, my full code:

#define F_CPU 12000000UL
#define RS PC0
#define EN PC2

#include <avr/io.h>
#include <util/delay.h>



//LCD_FUNCTIONS
void LCD_send_command (char command);
void LCD_send_data (char data);
void LCD_send_string (char *string);
void LCD_initial();
void LCD_hex (char HEX);


// Character buffer of my symbol.
const char customChar[8] = {
	0b00011,
	0b00011,
	0b11110,
	0b10010,
	0b10000,
	0b10000,
	0b10010,
	0b11110
};

// Main function
int main (void){
LCD_initial();
	LCD_send_command(0b00100000); //CGRAM adress is zero.
	for (uint8_t i=0; i!=8; i++)
		LCD_send_data(customChar[i]);
}


// LCD_FUNCTIONS
void LCD_initial (){	
DDRC |= (1 << DDC2)|(1 << DDC0); 
	PORTC = 0x00;
		DDRD = 0xFF; 
			PORTD = 0x00;
				_delay_ms(50); 
					PORTD |= (1 << PD5);
						PORTD &= ~(1 << PD4);
							PORTC |= (1 << EN);
								PORTC &= ~(1 << EN);
									_delay_ms(5);
										LCD_send_command(0x28);
											LCD_send_command(0x08);
												LCD_send_command(0x01);
													_delay_us(100);
														LCD_send_command(0x06);
															_delay_ms(10);
																LCD_send_command(0x0C);
};

void LCD_send_command(char command){
	PORTC &= ~ (1 << RS);
		_delay_us(40);
			PORTC |= (1 << EN);
				_delay_us(100);
					PORTD &= 0x0F;
						PORTD |= (command & 0xF0);
							_delay_us(10);
								PORTC &= ~ (1 << EN);
									_delay_us(40);
										PORTC |= (1 << EN);
											_delay_us(100);
												PORTD &= 0x0F;
													PORTD |= (command << 4);
														_delay_us(10);
															PORTC &= ~ (1 << EN);
																_delay_us(40);
}

void LCD_send_data (char data){
	PORTC |= (1 << RS) | (1 << EN);
		_delay_us(40);
			PORTD &= 0x0F;
				PORTD |= (data & 0xF0);
				_delay_us(10);
					PORTC &= ~ (1 << EN);
						_delay_us(40);
							PORTC |= (1 << EN);
								_delay_us(100);
									PORTD &= 0x0F;
										PORTD |= (data << 4);
											_delay_us(10);
												PORTC &= ~ (1 << EN);
													_delay_us(40);
}

void LCD_send_string(char *string){
	while (*string != '\0')
		LCD_send_data(*string ++);
}


void LCD_hex (char HEX){
	switch(HEX){
		case 0x00: LCD_send_data('0'); break;
		case 0x01: LCD_send_data('1'); break;
		case 0x02: LCD_send_data('2'); break;
		case 0x03: LCD_send_data('3'); break;
		case 0x04: LCD_send_data('4'); break;
		case 0x05: LCD_send_data('5'); break;
		case 0x06: LCD_send_data('6'); break;
		case 0x07: LCD_send_data('7'); break;
		case 0x08: LCD_send_data('8'); break;
		case 0x09: LCD_send_data('9'); break;
		case 0x0A: LCD_send_data('A'); break;
		case 0x0B: LCD_send_data('B'); break;
		case 0x0C: LCD_send_data('C'); break;
		case 0x0D: LCD_send_data('D'); break;
		case 0x0E: LCD_send_data('E'); break;
		case 0x0F: LCD_send_data('F'); break;
	}
}

 

This topic has a solution.
Last Edited: Thu. May 17, 2018 - 03:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Feni wrote:
LCD_send_command(0b00100000); //CGRAM adress is zero.

 

Are you sure that is the correct command byte? 

Looking at some Arduino code, the SETCGRAMADDR = 0x40!  (please don't use binary numbers, all those 1's and 0's make my eyes hurt! )

 

Jim

 

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:

Feni wrote:
LCD_send_command(0b00100000); //CGRAM adress is zero.

 

Are you sure that is the correct command byte? 

 

It's not. The datasheet is quite clear and, as you say, 0x40 is the right command.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OP did a pretty good job in posting.  What made me lose interest is "nothing works".  Are we syupposed to speculate that it only means that the custom character did not appear as desired?  Or that OP's homegrown LCD libray shows nothing but one line of black boxes?  [fails to initialize]  Or shows no pixels at all. [bad contrast setting]  Or all pixels "on". [ditto]

 

A forum search here should uncover custom-character discussions.  I know I've pasted my work based on CodeVision's example.

https://www.avrfreaks.net/commen... and I posted my code.  There are a number of similar threads.

 

Pretty much what you and the other respondents have posted:

void define_char (unsigned char flash * map, unsigned char code)
{
unsigned char command, looper;
command = (code<<3 | 0x40);	// write to CG ram
for (looper = 0; looper < 8; looper++)
	{
	lcd_write_byte (command++, *map++);
	}
return;
}

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Wed. May 16, 2018 - 06:51 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your answer.

No of course. It works very pretty, but I just can't understand how to write to LCD custom characters and nothing more.

In one word, I follow a clear sequence of actions, but there is an error.

Upgraded code:

LCD_initial();

	LCD_send_string ("Your custom");
		LCD_send_command (0xC0); // Line 2, Position 1.
			LCD_send_string("character is ");
					LCD_send_command(0x40); // set CGRAM to zero position.
						for (uint8_t i=0; i!=8; i++)
							LCD_send_data(customChar[i]); // Transfer bytes to LCD.

Proteus cheme:

 

 

As you see, my custum character doesn't exist.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your code snippit only loads the character to CGRAM, you must then print something that uses your new character. 

println(0x00); //arduino example to print custom char 0x00   custome chars are stored in ascii location 0x00 - 0x07

 

Jim

 

 

 

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try

​int main (void){
LCD_initial();
   LCD_send_command(0x40);          //CGRAM adress is zero 
   for (uint8_t i=0; i!=8; i++)
      LCD_send_data(customChar[i]); //save char on adr 0
   
   LCD_send_data(0);                //print char from adr 0
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Feni wrote:

LCD_initial();

	LCD_send_string ("Your custom");
		LCD_send_command (0xC0); // Line 2, Position 1.
			LCD_send_string("character is ");
					LCD_send_command(0x40); // set CGRAM to zero position.
						for (uint8_t i=0; i!=8; i++)
							LCD_send_data(customChar[i]); // Transfer bytes to LCD.

What's with the code wandering off to the right margin like that??

 

surprise

 

The idea of indentation is that it shows "hierarchy" - not just sequence.

 

For example, the above would usually be written as:

LCD_initial();

LCD_send_string ("Your custom");
LCD_send_command (0xC0);          // Line 2, Position 1.
LCD_send_string("character is ");
LCD_send_command(0x40);           // set CGRAM to zero position.

for (uint8_t i=0; i!=8; i++)
    LCD_send_data(customChar[i]); // Transfer bytes to LCD.

so only the last line is indented - as that one is controlled by the 'for'

 

Note that it is also good practice to always put in the braces - '{' and  '}'  - even when not strictly necessary; eg,

for (uint8_t i=0; i!=8; i++)
{
    LCD_send_data(customChar[i]); // Transfer bytes to LCD.
}

this makes the code easier to maintain - you won't get problems if you later add stuff to the loop, but forget the braces...

 

EDIT

 

typo

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Thu. May 17, 2018 - 06:59 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you, but it doesn't work.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried to do this and the resolt is the same :(

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What code did you try?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The layout of the source text  has no effect on the operation of the code.

 

If you want to discuss layout of source code, it would be better to start a separate thread for that ...

 

Probably in Compilers and General Programming

 

You can give a link to this for reference.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So... I understood how to write my character ro CGRAM of LCD. But, I can't get any character from DDROM.

For example: 

I write my custom character to CGRAM to LCD. (doesn't work)

LCD_initial();
		uint8_t adress_one, adress_two;
			adress_one = 0x00; // CGRAM adress = 0x00;
			adress_two = 0x01; // CGRAM adress = 0x01;
				LCD_send_command(0x40 + adress_one); // Set adress for writing of data.
					for (uint8_t i=0; i!=8; i++){
						LCD_send_data(customChar[i]);
					}
						LCD_send_data (0x00); // Display the custom character by adress = 0x00.

But, if I just display any character from DDROM of LCD, it works pretty. It means there is an error in code and I can't find this error.

LCD_initial();
	LCD_send_data (0xFF);

Although, this code doesn't work already.

LCD_initial();
	LCD_send_command (0x40);
		for (uint8_t i=0; i!=8; i++){
			LCD_send_data (customChar[i]);
		} LCD_send_data (0x00); // Display the custum character.
		
		
		LCD_send_data (0xFF); // Display the character located by adress 0xFF;

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This

​int main (void){
LCD_initial();
   LCD_send_command(0x40);          //CGRAM adress is zero 
   for (uint8_t i=0; i!=8; i++)
      LCD_send_data(customChar[i]); //save char on adr 0
   
   LCD_send_data(0);                //print char from adr 0
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Please can you fix the indentation on any subsequent code you post?

It is almost

          impossible

               to

                   read

                       code

                          that

                               has

                                   an

                                       increasing

                                            indent

                                                 on

                                                    every

                                                         line!

 

And in your latest code (#14) you appear to be trying to use 0xFF as a definable character?? That won't work. The HD44780 only supports 8 and they are numbered 0x00 to 0x07.

 

(what's more if you print any of 0x00 to 0x07 on screen and then go back and make a new definition of any one of them all the existing output of that character will immediately change - so you can only have 8 different ones on screen at any time).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmm... If I understood your messgae correct, I use Atmel studio 7.0. 

Thanks anyway.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

BTW I figured someone must have an example somewhere showing this working. Google found this for me:

 

https://hackprojectssol.blogspot...

 

Last Edited: Thu. May 17, 2018 - 08:43 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Please can you fix the indentation on any subsequent code you post?

It is almost

          impossible

               to

                   read

                       code

                          that

                               has

                                   an

                                       increasing

                                            indent

                                                 on

                                                    every

                                                         line!

 

Yes - that was my point in #9

 

Feni wrote:
 I use Atmel studio 7.0. 

Then you should certainly be able to write code without this bizarre ever-increasing indent!

 

No doubt a significant number of people here use Atmel Studio (various versions) - and manage to produce "normal" indentation

 

There are plenty of styles to choose from: https://en.wikipedia.org/wiki/Indentation_style - but this "ever-increasing" indent jut makes no sense at all!

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks you very much! It works perfectly!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lol :) Okey :) Thank you very much, I found my error :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

Feni wrote:
I found my error :)
For the benefit of the next person who searches and finds this thread can you say what the error was? It may be they have the same problem.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Feni wrote:

I found my error :) 

clawson wrote:
For the benefit of the next person who searches and finds this thread can you say what the error was?

+1

 

Also, please mark the solution - see Tip #5 for instructions on how to do that.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Maybe this solution will be helpful for anyone else :)

 

LCD_initial();
unsigned char adress = 0x00; // Local variable of adress CGRAM.
LCD_send_command(0x40 + (adress * 8)); // Adress calculation.
for (uint8_t i=0; i!=8; i++)
LCD_send_data (customChar[i]); // Transver data of the custom character.
LCD_send_command(0x80); // Here was my error. I had to place a cursor to the desired position
LCD_send_data (0x00); // Display the custom character.

Hexadecima type of command + adress.

0x40 - CGRAM cell #0.
0x48 - CGRAM cell #1.
0x50 - CGRAM cell #2.
0x58 - CGRAM cell #3.
0x60 - CGRAM cell #4.
0x68 - CGRAM cell #5.
0x70 - CGRAM cell #6.
0x78 - CGRAM cell #7.

Thank you very much!

Last Edited: Thu. May 17, 2018 - 10:19 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So now please mark the solution!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would point out that there's another probable error, although it may not be causing problems right now; when you strobe the enable pin, you're not delaying long enough to be sure it'll work. My guess is that if you were running with a faster clock, it wouldn't. Most of the spec sheets I've seen suggest a 1us or so minimum strobe time.