51 마이크로 컨트롤러는 1602LCD 디스플레이 화면을 제어하여 맞춤형 문자를 출력합니다. 2

51 마이크로 컨트롤러는 1602LCD 디스플레이 화면을 제어하여 맞춤형 문자를 출력합니다. 2

1. 개요

1602LCD는 내장 문자 외에도 커스텀 문자 기능도 제공하는데, 내장 문자 중 출력하고 싶은 문자가 없을 때 자체 캐릭터를 만들어 표시할 수 있습니다.1602에서 커스텀 문자를 생성하는 방법은 다음과 같습니다.

2.1602LCD 캐릭터 생성 원리

커스텀 캐릭터에는 세 가지 기억이 관련되어 있으며, 기능을 파악한 후 캐릭터를 커스터마이즈할 수 있습니다. 다음은 세 가지 기억이 커스텀 캐릭터에 미치는 영향을 자세히 설명합니다.

맞춤 문자 출력 원리:
프로그램은 CGROM 주소 지정 -> CGROM에서 해당 주소와 연관된 CGRAM 주소 검색 -> CGRAM에서 해당 위치에 해당하는 맞춤 문자 검색 -> 이를 1602LCD 화면에 출력합니다.

CGROM

CGROM은 1602에 내장된 문자 메모리로 흔히 사용되는 문자를 고체화한 것으로, 영숫자를 출력하면 1602 칩은 해당 문자에 해당하는 주소를 CGROM에서 검색한 후 그 주소를 출력하여 LCD에 문자를 표시한다. .
우리가 출력하는 문자가 CGROM에 내장되어 있지 않은 경우, 이때 직접 출력해야 하는 문자를 정의할 수 있습니다. CGROM은 사용자 정의 문자를 출력하기 위해 8개의 CGRAM 위치를 예약합니다. 즉, 최대 8개의 사용자 정의 문자를 저장할 수 있습니다.
여기에 이미지 설명을 삽입하세요.

내장 명령 목록

내장 명령어 테이블을 확인하세요. CGRAM 주소는 6비트입니다. 6비트 D0~D5는 사용자 정의 문자를 저장하는 CGRAM 주소입니다. D6은 1이므로 시작 주소는 0x40 부터 시작됩니다 .
여기에 이미지 설명을 삽입하세요.

CGRAM 주소 테이블

D0~D5에 사용자 정의 문자를 저장하는 방법은 아래 CGRAM 주소 표에 따라 다릅니다. CGRAM 주소는 6비트 주소를 두 가지 범주로 구분하며, 왼쪽(5, 4, 3)은 상위 3자리 해당 문자 저장 주소입니다. 001~111의 3비트를 조합하면 8개의 사용자 정의 문자를 저장할 수 있는 주소가 정확히 8개가 됩니다.

오른쪽(2,1,0)은 사용자 정의 문자에 해당하는 하위 3비트 중 8바이트입니다. 테이블의 CGRAM 데이터는 문자 내용을 구성하는 것입니다. 문자의 각 라인은 바이트당 8비트로 구성됩니다. 8줄로 구성되며 각 문자는 저장하는 데 8바이트가 필요하므로 주소의 하위 3비트를 001부터 111까지 결합하면 문자 하나를 저장하는 데 정확히 8개의 주소가 됩니다.

예를 들어 대문자를 구성하면 해당 배열은 다음과 같습니다.

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

여기에 이미지 설명을 삽입하세요.

CGRAM과 CGROM의 대응

CGRAM의 내장 명령어와 주소 테이블을 이해한 후 사용자 정의 문자를 구성하여 CGRAM에 저장할 수 있습니다. 다음 단계는 CGRAM 주소의 문자를 CGROM 주소와 연결하여 LCD가 CGRAM 주소를 찾을 수 있도록 하는 것입니다. CGROM 주소에서 CGRAM 주소를 전달하여 문자를 찾습니다.

1602LCD에는 CGRAM과 CGROM 주소가 연관되어 있으며, 이들의 관계는 아래와 같습니다.
예를 들어 CGRAM의 첫 번째 문자 위치는 (0x40-0x47)이고 해당 CGROM 주소는 0X00입니다. 프로그램에서 출력 내용의 주소가 0x00이면 CGRAM의 첫 번째 문자를 찾아 다음으로 출력합니다. 1602LCD 화면.

여기에 이미지 설명을 삽입하세요.

3.1602LCD에서 캐릭터 인스턴스를 생성합니다.

다음 예에서는 LCDWriteCGRAM사용자 정의 문자를 생성하는 기능을 구현하는 함수를 생성합니다.

  • 먼저 CGRAM에 사용자 정의 문자가 저장되는 위치를 설정하십시오: LCD1602_WriteCMD(0x40);
  • 사용자 정의 문자 컨텐츠를 CGRAM에 저장합니다: for(i=0;i<8;i++){LCD1602_WriteData(str[i]);}
  • LCD 디스플레이 문자 위치 설정: LCD1602_WriteCMD(0x80| 0x05);
  • 출력 문자의 CGROM 주소를 지정하십시오: 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);
	
}
완전한 코드
#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);
	
}

맞춤형 캐릭터 기능 최적화

위에서 작성한 함수 LCDWriteCGRAM에는 결함이 있어 문자가 저장되는 CGRAM 위치를 변경하거나 LCD 표시 위치를 수정해야 할 때마다 이 함수를 수정해야 하므로 최적화하여 변경된 내용을 매개변수로 추출합니다. 이는 다른 문자를 출력하기 위해 매번 매개변수만 전달하면 되는 도구 함수가 됩니다.

LCDSetChar이 함수는 커스텀 컨텐츠 함수를 캡슐화한 것으로, 함수의 디자인 아이디어는 다음과 같습니다.

  • 먼저 LCD에 표시되는 문자의 위치, CGROM 위치, 문자 내용을 포함한 매개변수를 정의합니다.
    • x: LCD 디스플레이 문자 위치
    • y: LCD에 문자가 표시되는 라인을 설정합니다.
    • pos: CGRAM 위치 설정
    • str: 문자 내용
  • 사용자 정의 캐릭터를 구성하는 것은 두 부분으로 구성됩니다.
    • CGRAM에서 문자 저장 위치 설정
    • 캐릭터 내용 설정
  • 문자 표시 설정
    • LCD에 문자가 표시되는 위치 설정
    • LCD에 표시되는 문자 설정
/*
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);
}
완전한 코드
#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개의 사용자 정의 캐릭터가 사전 설치되어 있습니다.

8개의 문자를 정의하면 한꺼번에 CGRAM에 저장하고 사용 시 바로 호출할 수 있습니다.

  • CgramWrite함수는 한 번에 8자를 읽습니다.
  • print2문자를 출력하는데 사용되는 함수
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);
	}
	
}

추천

출처blog.csdn.net/m0_38039437/article/details/134989234