51 microcontroller controls 1602LCD display screen to output customized characters 2

51 microcontroller controls 1602LCD display screen to output customized characters 2

1 Overview

In addition to the built-in characters, 1602LCD also provides custom character functions. When there are no characters we want to output among the built-in characters, we can create our own characters for display. Here is how 1602 creates custom characters.

2.1602LCD character creation principle

Custom characters involve three memories. After figuring out their functions, you can customize characters. The following describes in detail the effects of the three memories on custom characters.

Principle of custom character output:
The program specifies the CGROM address -> CGROM searches for the CGRAM address associated with the address -> CGRAM searches for the custom character corresponding to the location -> outputs it to the 1602LCD screen.

CGROM

CGROM is the character memory built into the 1602, in which commonly used characters are solidified. When we output alphanumeric characters, the 1602 chip searches the CGROM for the address corresponding to the character, and then outputs the address to display the character on the LCD.
If the characters we output are not built-in in CGROM, we can define the characters we need to output ourselves at this time. CGROM reserves 8 CGRAM locations for us to output customized characters. This means we can store up to 8 custom characters.
Insert image description here

Built-in command list

Check the built-in instruction table. The CGRAM address has 6 bits. The six bits D0~D5 are the CGRAM addresses for storing custom characters. D6 is 1, so its starting address starts from 0x40 .
Insert image description here

CGRAM address table

How to store custom characters in D0~D5 depends on the CGRAM address table below. CGRAM Address divides the 6-bit address into two categories. The left side (5, 4, 3) is the upper three-digit corresponding character storage address. After combining 3 bits from 001 ~ 111, there are exactly 8 addresses to store 8 custom characters.

The right side (2,1,0) is the 8 bytes of the lower three bits corresponding to the custom character. The CGRAM data in the table is to construct a character content. Each line of the character is 8 bits per byte and consists of 8 lines. Each Characters require 8 bytes to store, so the lower 3 bits of the address are combined from 001 to 111, which is exactly 8 addresses to store one character.

For example, if we construct an uppercase character, its array is

// 数组中每个元素代表字符的一行,一共8行。
//LCD显示的字符是5x8点阵,因此一行只有5位,0x1f:1表示第5位为1,f表示后面4位为1
unsigned char str[] = {
    
    0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,};

Insert image description here

Correspondence between CGRAM and CGROM

After understanding the built-in instructions and address table of CGRAM, you can construct custom characters and store them in CGRAM. The next step is to associate the characters in the CGRAM address with the CGROM address, so that the LCD can find the CGRAM address from the CGROM address, and pass the CGRAM address Find the character.

1602LCD has associated CGRAM and CGROM addresses. Their relationship is as shown below.
For example, the position of the first character of CGRAM is (0x40-0x47) and the corresponding CGROM address is 0X00. When the address of the output content in the program is 0x00, the first character of CGRAM will be found and output to the 1602LCD screen.

Insert image description here

3.1602LCD creates character instance

In the following example LCDWriteCGRAM, a function is created to implement the function of creating custom characters.

  • First set the location where the custom characters are stored in CGRAM: LCD1602_WriteCMD(0x40);
  • Store custom character content into CGRAM: for(i=0;i<8;i++){LCD1602_WriteData(str[i]);}
  • Set the LCD display character position: LCD1602_WriteCMD(0x80| 0x05);
  • Specify the CGROM address of the output characters: LCD1602_WriteData(0x00);
unsigned char code str[] = {
    
    0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00};
void LCDWriteCGRAM(){
    
    
	//构造自定义字符
	unsigned char i;
	//自定义字符存放在CGRAM的第一个位置0x40-0x47
	LCD1602_WriteCMD(0x40);
	//存放自定义字符内容
	for(i=0;i<8;i++){
    
    
		LCD1602_WriteData(str[i]);
	}
	
	//显示字符
	LCD1602_WriteCMD(0x80| 0x05);
	//CGRAM第一个位置对应CGROM的0x00地址
	LCD1602_WriteData(0x00);
	
}
Complete code
#include <STC12C2052AD.H>
typedef unsigned char uint8;
// 定义引脚
#define	LCD1602_DB0_DB7	P1			// 定义LCD1602的数据总线
sbit LCD1602_RS = P3 ^ 2;					// 定义LCD1602的RS控制线
sbit LCD1602_RW = P3 ^ 3;					// 定义LCD1602的RW控制线
sbit LCD1602_E  = P3 ^ 4;					// 定义LCD1602的E控制线
sbit LCD1602_Busy = P1 ^ 7;					// 定义LCD1602的测忙线(与LCD1602_DB0_DB7关联)


// 定义指令集
/*设置显示模式*/
#define LCD_MODE_PIN8 0x38	// 8位数据线,两行显示
#define LCD_MODE_PIN4 0x28	// 4位数据线,两个显示
#define LCD_SCREEN_CLR 0x01	// 清屏
#define LCD_CURSOR_RET 0x02	// 光标复位
#define LCD_CURSOR_RIGHT 0x06	// 光标右移,显示不移动
#define LCD_CURSOR_LEFT 0x04	// 光标左移,显示不移动
#define LCD_DIS_MODE_LEFT 0x07 	// AC自增,画面左移
#define LCD_DIS_MODE_RIGHT 0X05	// AC自增,画面右移


/*光标开关控制*/
#define LCD_DIS_CUR_BLK_ON 0x0f	// 显示开,光标开,光标闪烁
#define LCD_DIS_CUR_ON 0x0e	// 显示开,光标开,光标不闪烁
#define LCD_DIS_ON 0x0c	// 显示开,光标关,光标不闪烁
#define LCD_DIS_OFF 0x08	// 显示关,光标关,光标不闪烁

/*光标、显示移动*/
#define LCD_CUR_MOVE_LEFT 0x10	// 光标左移
#define LCD_CUR_MOVE_RIGHT 0x14	// 光标右移
#define LCD_DIS_MOVE_LEFT 0x18	// 显示左移
#define LCD_DIS_MOVE_RIGHT 0x1c	// 显示右移


/**
LCD1602忙碌状态不会接收新指令,因此在发送新指令前先检测是否忙碌。
判断LCD1602_Busy变量的值为低电平则为不忙。
*/
void LCD1602_TestBusy(void){
    
    
	LCD1602_DB0_DB7 = 0xff;	//将数据引脚置为高电平
	LCD1602_RS = 0; // 指令状态
	LCD1602_RW = 1;	// 读状态
	LCD1602_E = 1;	// 打开LCD显示器读指令
	while(LCD1602_Busy);	//读取LCD1602_Busy(P1.7)为低电平则结束循环
	LCD1602_E = 0;	// 关闭LCD显示器读指令
}


/********************************************************************************************
// 写指令程序 //
// 向LCD1602写命令 本函数需要1个指令集的入口参数 //
/********************************************************************************************/
void LCD1602_WriteCMD(uint8 LCD1602_command) {
    
     
	LCD1602_TestBusy();
	//输入的命令赋值给LCD1602_DB0_DB7
	LCD1602_DB0_DB7 = LCD1602_command;
	LCD1602_RS = 0;
	LCD1602_RW = 0;
	LCD1602_E = 1;
	LCD1602_E = 0;
}
/********************************************************************************************
// 写数据程序 //
// 向LCD1602写数据 //
/********************************************************************************************/
void LCD1602_WriteData(uint8 LCD1602_data){
    
     
	LCD1602_TestBusy();
	LCD1602_DB0_DB7 = LCD1602_data;
	LCD1602_RS = 1;
	LCD1602_RW = 0;
	LCD1602_E = 1;
	LCD1602_E = 0;
}


// LCD1602初始化
void LCD1602_Init(void){
    
    
	LCD1602_WriteCMD(LCD_MODE_PIN8);	// 显示模式设置:显示2行,每个字符为5*7个像素
	LCD1602_WriteCMD(LCD_DIS_ON); 	// 显示开及光标设置:显示开,光标关
	LCD1602_WriteCMD(LCD_CURSOR_RIGHT);		//显示光标移动设置:文字不动,光标右移
	LCD1602_WriteCMD(LCD_SCREEN_CLR);	// 显示清屏
}


/*
输出字符串
x:数据地址
y:输出的行位置,第一行和第二行
str:输入字符串
*/
void print(uint8 x, uint8 y, uint8 *str){
    
    
	if(0 == y){
    
    
		LCD1602_WriteCMD(0x80 | x);
	}
	else{
    
    
		// 第二行起始位置是0x40
		LCD1602_WriteCMD(0x80 | (0x40+x));
	}
	while(*str != '\0'){
    
    
		LCD1602_WriteData(*str++);
	}

}


unsigned char code str[] = {
    
    0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00};
void LCDWriteCGRAM(){
    
    
	//构造自定义字符
	unsigned char i;
	//自定义字符存放在CGRAM的第一个位置0x40-0x47
	LCD1602_WriteCMD(0x40);
	//存放自定义字符内容
	for(i=0;i<8;i++){
    
    
		LCD1602_WriteData(str[i]);
	}
	
	//显示字符
	LCD1602_WriteCMD(0x80| 0x05);
	//CGRAM第一个位置对应CGROM的0x00地址
	LCD1602_WriteData(0x00);
	
}

void main(){
    
    
	unsigned char str1[] = "Beyound Self";
	LCD1602_Init();
	// 显示自定义内容
	LCDWriteCGRAM();
	print(0x00,1,str1);
	while(1);
	
}

Optimize custom character functions

The function created above LCDWriteCGRAMis flawed. Whenever you need to change the CGRAM location where characters are stored or modify the LCD display position, you need to modify this function. Therefore, it is optimized and the changed content is extracted as parameters. It becomes a tool function that only needs to pass in parameters each time to output different characters.

LCDSetCharThe function encapsulates the custom content function. The design idea of ​​the function is as follows

  • First define the parameters including the position of the character displayed on the LCD, the CGROM position, and the character content.
    • x: LCD display character position
    • y: Set the line where characters are displayed on the LCD
    • pos: set CGRAM location
    • str: character content
  • Constructing a custom character consists of two parts
    • Set the character storage location in CGRAM
    • Set character content
  • Set character display
    • Set where characters are displayed on the LCD
    • Set which character the LCD displays
/*
x:LCD显示字符位置
y:设置字符在LCD显示的行
pos:设置CGRAM位置
str:字符内容
*/
void LCDSetChar(unsigned char x, unsigned char y, unsigned char pos, unsigned char *str){
    
    
	unsigned char i;
	// 1.构造自定义字符,确定CGRAM位置
	for(i=0;i<8;i++){
    
    
		/*
		确定CGRAM位置
		0x40是CGRAM第一个起始位置,pos是设置第几个位置,一共8个。
		
		*/
		LCD1602_WriteCMD(0x40+pos*8+i );
		// 构造自定义字符
		LCD1602_WriteData(*(str+i));
	}
	
	// 2.显示字符
	// 设置字符在LCD显示的位置
	if(0 == y){
    
    
		LCD1602_WriteCMD(0x80 | x);
	}
	else{
    
    
		// 第二行起始位置是0x40
		LCD1602_WriteCMD(0x80 | (0x40+x));
	}
	
	// LCD显示字符内容,该地址是CGROM
	LCD1602_WriteData(0x00+pos);
}
Complete code
#include <STC12C2052AD.H>
typedef unsigned char uint8;
// 定义引脚
#define	LCD1602_DB0_DB7	P1			// 定义LCD1602的数据总线
sbit LCD1602_RS = P3 ^ 2;					// 定义LCD1602的RS控制线
sbit LCD1602_RW = P3 ^ 3;					// 定义LCD1602的RW控制线
sbit LCD1602_E  = P3 ^ 4;					// 定义LCD1602的E控制线
sbit LCD1602_Busy = P1 ^ 7;					// 定义LCD1602的测忙线(与LCD1602_DB0_DB7关联)


// 定义指令集
/*设置显示模式*/
#define LCD_MODE_PIN8 0x38	// 8位数据线,两行显示
#define LCD_MODE_PIN4 0x28	// 4位数据线,两个显示
#define LCD_SCREEN_CLR 0x01	// 清屏
#define LCD_CURSOR_RET 0x02	// 光标复位
#define LCD_CURSOR_RIGHT 0x06	// 光标右移,显示不移动
#define LCD_CURSOR_LEFT 0x04	// 光标左移,显示不移动
#define LCD_DIS_MODE_LEFT 0x07 	// AC自增,画面左移
#define LCD_DIS_MODE_RIGHT 0X05	// AC自增,画面右移


/*光标开关控制*/
#define LCD_DIS_CUR_BLK_ON 0x0f	// 显示开,光标开,光标闪烁
#define LCD_DIS_CUR_ON 0x0e	// 显示开,光标开,光标不闪烁
#define LCD_DIS_ON 0x0c	// 显示开,光标关,光标不闪烁
#define LCD_DIS_OFF 0x08	// 显示关,光标关,光标不闪烁

/*光标、显示移动*/
#define LCD_CUR_MOVE_LEFT 0x10	// 光标左移
#define LCD_CUR_MOVE_RIGHT 0x14	// 光标右移
#define LCD_DIS_MOVE_LEFT 0x18	// 显示左移
#define LCD_DIS_MOVE_RIGHT 0x1c	// 显示右移


/**
LCD1602忙碌状态不会接收新指令,因此在发送新指令前先检测是否忙碌。
判断LCD1602_Busy变量的值为低电平则为不忙。
*/
void LCD1602_TestBusy(void){
    
    
	LCD1602_DB0_DB7 = 0xff;	//将数据引脚置为高电平
	LCD1602_RS = 0; // 指令状态
	LCD1602_RW = 1;	// 读状态
	LCD1602_E = 1;	// 打开LCD显示器读指令
	while(LCD1602_Busy);	//读取LCD1602_Busy(P1.7)为低电平则结束循环
	LCD1602_E = 0;	// 关闭LCD显示器读指令
}


/********************************************************************************************
// 写指令程序 //
// 向LCD1602写命令 本函数需要1个指令集的入口参数 //
/********************************************************************************************/
void LCD1602_WriteCMD(uint8 LCD1602_command) {
    
     
	LCD1602_TestBusy();
	//输入的命令赋值给LCD1602_DB0_DB7
	LCD1602_DB0_DB7 = LCD1602_command;
	LCD1602_RS = 0;
	LCD1602_RW = 0;
	LCD1602_E = 1;
	LCD1602_E = 0;
}
/********************************************************************************************
// 写数据程序 //
// 向LCD1602写数据 //
/********************************************************************************************/
void LCD1602_WriteData(uint8 LCD1602_data){
    
     
	LCD1602_TestBusy();
	LCD1602_DB0_DB7 = LCD1602_data;
	LCD1602_RS = 1;
	LCD1602_RW = 0;
	LCD1602_E = 1;
	LCD1602_E = 0;
}


// LCD1602初始化
void LCD1602_Init(void){
    
    
	LCD1602_WriteCMD(LCD_MODE_PIN8);	// 显示模式设置:显示2行,每个字符为5*7个像素
	LCD1602_WriteCMD(LCD_DIS_ON); 	// 显示开及光标设置:显示开,光标关
	LCD1602_WriteCMD(LCD_CURSOR_RIGHT);		//显示光标移动设置:文字不动,光标右移
	LCD1602_WriteCMD(LCD_SCREEN_CLR);	// 显示清屏
}


/*
输出字符串
x:数据地址
y:输出的行位置,第一行和第二行
str:输入字符串
*/
void print(uint8 x, uint8 y, uint8 *str){
    
    
	if(0 == y){
    
    
		LCD1602_WriteCMD(0x80 | x);
	}
	else{
    
    
		// 第二行起始位置是0x40
		LCD1602_WriteCMD(0x80 | (0x40+x));
	}
	while(*str != '\0'){
    
    
		LCD1602_WriteData(*str++);
	}

}

/*
x:LCD显示字符位置
y:设置字符在LCD显示的行
pos:设置CGRAM位置
str:字符内容
*/
void LCDSetChar(unsigned char x, unsigned char y, unsigned char pos, unsigned char *str){
    
    
	unsigned char i;
	// 1.构造自定义字符,确定CGRAM位置
	for(i=0;i<8;i++){
    
    
		/*
		确定CGRAM位置
		0x40是CGRAM第一个起始位置,pos是设置第几个位置,一共8个。
		
		*/
		LCD1602_WriteCMD(0x40+pos*8+i );
		// 构造自定义字符
		LCD1602_WriteData(*(str+i));
	}
	
	// 2.显示字符
	// 设置字符在LCD显示的位置
	if(0 == y){
    
    
		LCD1602_WriteCMD(0x80 | x);
	}
	else{
    
    
		// 第二行起始位置是0x40
		LCD1602_WriteCMD(0x80 | (0x40+x));
	}
	
	// LCD显示字符内容,该地址是CGROM
	LCD1602_WriteData(0x00+pos);
}

void main(){
    
    
	unsigned char str1[] = "Beyound Self";
	unsigned char code c1[] = {
    
    0x00,0x00,0x00,0x00,0x1f,0x00,0x00,0x00};
	LCD1602_Init();
	// 显示自定义内容
	LCDSetChar(3,0,0,c1);
	print(0x00,1,str1);
	while(1);
	
}

8 custom characters pre-installed

If 8 characters have been defined, they can all be stored in CGRAM at once and called directly when used.

  • CgramWriteFunction reads 8 characters at a time
  • print2Function used to output characters
uint8 code Xword[]={
    
    
    0x18,0x18,0x07,0x08,0x08,0x08,0x07,0x00,        //℃,代码 0x00
    0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,        //一,代码 0x01
    0x00,0x00,0x00,0x0e,0x00,0xff,0x00,0x00,        //二,代码 0x02
    0x00,0x00,0xff,0x00,0x0e,0x00,0xff,0x00,        //三,代码 0x03
    0x00,0x00,0xff,0xf5,0xfb,0xf1,0xff,0x00,        //四,代码 0x04
    0x00,0xfe,0x08,0xfe,0x0a,0x0a,0xff,0x00,        //五,代码 0x05
    0x00,0x04,0x00,0xff,0x00,0x0a,0x11,0x00,        //六,代码 0x06
    0x00,0x1f,0x11,0x1f,0x11,0x11,0x1f,0x00,        //日,代码 0x07
};
void CgramWrite(void) {
    
    	// 装入CGRAM //
	unsigned char i;
	LCD1602_WriteCMD(0x06);			// CGRAM地址自动加1
	LCD1602_WriteCMD(0x40);			// CGRAM地址设为从第一个位置开始
		
    for(i=0;i<64;i++) {
    
    
    	LCD1602_WriteData(Xword[i]);// 按数组写入数据
    }
}

// a:LCD显示位置  b:显示哪个字符
void print2(unsigned char a,unsigned char t){
    
    
		LCD1602_WriteCMD(a | 0x80);
		LCD1602_WriteData(t);
}

void main(){
    
    
	LCD1602_Init();
	CgramWrite();
	while(1){
    
    
		print2(0x01,0x00);
		print2(0x03,0x01);
		print2(0x05,0x02);
		print2(0x07,0x03);
		print2(0x09,0x04);
		print2(0x0b,0x05);
		print2(0x0d,0x06);
		print2(0x0f,0x07);
	}
	
}

Guess you like

Origin blog.csdn.net/m0_38039437/article/details/134989234
Recommended