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);
}
}