大家好,又见面了,我是你们的朋友全栈君。
//********写指令函数************
void LCD_write_command(uchar dat)
{
LCD_DB=dat;
LCD_RS=0;//指令
LCD_RW=0;//写入
LCD_E=1;//允许
LCD_E=0;
delay_n40us(1);//实践证明,我的LCD1602上,用for循环1次就能完成普通写指令。
}
//*******************************
//********写数据函数*************
void LCD_write_data(uchar dat)
{
LCD_DB=dat;
LCD_RS=1;//数据
LCD_RW=0;//写入
LCD_E=1;//允许
LCD_E=0;
delay_n40us(1);
}
//********************************
//*******显示一个字符函数*********
void LCD_disp_char(uchar x,uchar y,uchar dat)
{
uchar address;
if(y==1)
address=0x80+x;
else
address=0xc0+x;
LCD_write_command(address);
LCD_write_data(dat);
}
//********************************
/*******检查忙函数*************
void LCD_check_busy() //实践证明,在我的LCD1602上,检查忙指令通过率极低,以
{ //至于不能正常使用LCD。因此我没有再用检查忙函数。而使
do //用了延时的方法,延时还是非常好用的。我试了一下,用
{ LCD_E=0; //for循环作延时,普通指令只要1次循就可完成。清屏指令
LCD_RS=0; //要用200次循环便能完成。
LCD_RW=1;
LCD_DB=0xff;
LCD_E=1;
}while(LCD_DB^7==1);
}
******************************/
//********延时函数***************
void delay_n40us(uint n)
{ uint i;
uchar j;
for(i=n;i>0;i–)
for(j=0;j<2;j++); //在这个延时循环函数中我只做了2次循环,
} //实践证明我的LCD1602上普通的指令只需1次循环就能可靠完成。
//*******************************
//*********主函数*****************
void main(void)
{
LCD_init();
LCD_disp_char(0,1,’A’);
while(1);
}
//*******************************
具体电路的制作是很简单的,就接了两个电阻,一个是10欧姆的背光限流电阻,另一个是2K的LCD极板电压调节电阻。这两个电阻的阻值怎么定呢?背光比较简单,它就相当于在后面接了几个发光二极管,任何时候你只要在15、16脚串上个100欧的电位器接上电源,调节电位器,觉得亮度合适。此时的阻值便可。LCD液晶极板驱动电压调节电阻的确定就稍微麻烦一点。在各数据线,控制线接好关通上电源的前提下在第3脚(VEE)和地之间接一个10K的电位器。调节电位器。当3脚电压高时为全亮,电压为0时为全暗(液晶全显示为黑块)。你用电位器把屏幕从全暗刚好调到变亮。这时便可调试程序。待屏幕能正确显示后再细调电位器,使对比度合适。这时的阻值便可确定,然后换成等值的固定电阻焊上便可。
组装后:
具体电路图:
接口说明:
我们从CGROM表上可以看到,在表的最左边是一列可以允许用户自定义的CGRAM,从上往下看着是16个,实际只有8个字节可用。它的字符码是00000000-00000111这8个地址,表的下面还有8个字节,但因为这个CGRAM的字符码规定0-2位为地址,3位无效,4-7全为零。因此CGRAM的字符码只有最后三位能用也就是8个字节了。等效为0000X111,X为无效位,最后三位为000-111共8个。
如果我们要想显示这8个用户自定义的字符,操作方法和显示CGROM的一样,先设置DDRAM位置,再向DDRAM写入字符码,例如“A”就是41H。现在我们要显示CGRAM的第一个自定义字符,就向DDRAM写入00000000B(00H),如果要显示第8个就写入00000111(08H),简单吧!
现在我们来看怎么向这八个自定义字符写入字模。有个设置CGRAM地址的指令大家还记得吗?赶快再找出来看看。
从这个指令可以看出指令数据的高2位已固定是01,只有后面的6位是地址数据,而这6位中的高3位就表示这八个自定义字符,最后的3位就是字模数据的八个地址了。例如第一个自定义字符的字模地址为01000000-01000111八个地址。我们向这8个字节写入字模数据,让它能显示出“℃”
地址:01000000 数据:00010000 图示:○○○■○○○○
01000001 00000110 ○○○○○■■○
01000010 00001001 ○○○○■○○■
01000011 00001000 ○○○○■○○○
01000100 00001000 ○○○○■○○○
01000101 00001001 ○○○○■○○■
01000110 00000110 ○○○○○■■○
01000111 00000000 ○○○○○○○○
可以通过手动提取的方法。如下图所示,对应一个字符显示区域。每8个字节,组成一个点阵数组。
“日”的点阵数组即为 {0x1f,0x11,0x11,0x1f,0x11,0x11,0x1f,0x00}
“车”字取模数组为:{0x00,0x0f,0x02,0x04,0x07,0x00,0x0f,0x00,
0x10,0x1e,0x00,0x10,0x1c,0x10,0x1e,0x10}
将生成的点阵数组保存到CGRAM存储器中,生成自定义字符。1602内部CGRAM用于自定义的字符点阵的存储,总共64字节。由上一步点阵提取可知,每一个字符由8个字节数据组成。所以64字节CGRAM存储器,能够存储8组自定义字符的点阵数组。按照CGRAM地址划分为0-7为第一组,8-15为第二组,依次类推56-63为第8组数据。把自定义字符的数组按8个字节一组存储到CGRAM中,程序代码参考如下。
//功能:将自定义字符的编码数组 写入到CGRAM中.
//输入:自定义字符的编码数组
void Write_CGRAM(unsigned char *p)
{
unsigned char i,j,kk;
unsigned char tmp=0x40; //操作CGRAM的命令码
kk=0;
for(j=0;j<8;j++) //64 字节存储空间,可以生成 8 个自定义字符点阵
{
for(i=0;i<8;i++) // 8 个字节生成 1 个字符点阵
{
Write_com(tmp+i); //操作CGRAM的命令码+写入CGRAM地址.
Write_dat(p[kk]); //写入数据
kk++;
}
tmp += 8;
}
}
上一步中,自定义字符存储到CGRAM的任意一组以后,每一个组(8个字节)也有一个显示编码。按顺序依次为00H-07H 。显示时,只要调用每一组的编码,即可以显示相应的字符。
注:内部常用字符显示时,显示编码是从0x20开始的。0x00-0x0f是专门留给自定义字符显示的。0x00-0x07和0x08-0x0f内容是一样的。例如:调用0x01 位置和0x09位置,显示的内容是一样的。
直接按照单个字符的显示方式调用显示函数,就可以显示自定义字符了。代码参考如下:
//在第1行,第7个位置显示自定义汉字 “年”
DisplayOneChar(6,0,0); //显示 “年” //CGRAM 码 00
说明:此时“年”的8个字节点阵数组 ,存储空间为CGRAM的 00-07地址
也就是CGRAM的第1组数据存储区域,编码为0。 如果存储在CGRAM的08-15地址,那么编码就应该是 1了。
很多资料中,都没有详细介绍过CGRAM和CGROM的区别和用法,在1602调试过程中经常会被搞混。这里总结一点小技巧,希望能给需要的人一点帮助。
以下是显示效果:
单个和两个点阵的汉字显示:
图形显示效果:
下面一段程序让这8个自定义字符显示出一个心的图案:
#include unsigned char table1[]={0x03,0x07,0x0f,0x1f,0x1f,0x1f,0x1f,0x1f,
0x18,0x1E,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,
0x07,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,
0x10,0x18,0x1c,0x1E,0x1E,0x1E,0x1E,0x1E,
0x0f,0x07,0x03,0x01,0x00,0x00,0x00,0x00,
0x1f,0x1f,0x1f,0x1f,0x1f,0x0f,0x07,0x01,
0x1f,0x1f,0x1f,0x1f,0x1f,0x1c,0x18,0x00,
0x1c,0x18,0x10,0x00,0x00,0x00,0x00,0x00};//心图案
unsigned char table[]={0x10,0x06,0x09,0x08,0x08,0x09,0x06,0x00};//字符℃
#define CLEARSCREEN LCD_write_command(0x01)
/**************定义接口************************/
#define LCDIO P2
sbit LCD1602_RS=P3^0;
sbit LCD1602_RW=P3^1;
sbit LCD1602_EN=P3^2;
/**************定义函数************************/
void LCD_write_command(unsigned char command);//写入指令函数
void LCD_write_dat(unsigned char dat);//写入数据函数
void LCD_set_xy( unsigned char x, unsigned char y );//设置显示位置函数
void LCD_dsp_char( unsigned x,unsigned char y,unsigned char dat);//显示一个字符函数
void LCD_dsp_string(unsigned char X,unsigned char Y,unsigned char *s);//显示字符串函数
void LCD_init(void);//初始化函数
void delay_nms(unsigned int n);//延时函数
/********************************************/
/************初始化函数****************/
void LCD_init(void)
{
CLEARSCREEN;//clear screen
LCD_write_command(0x38);//set 8 bit data transmission mode
LCD_write_command(0x0c);//open display (enable lcd display)
LCD_write_command(0x80);//set lcd first display address
CLEARSCREEN;//clear screen
}
/****************************************************/
/**************写指令函数********************************/
void LCD_write_command(unsigned char command)
{
LCDIO=command;
LCD1602_RS=0;
LCD1602_RW=0;
LCD1602_EN=0;
LCD1602_EN=1;
delay_nms(10);
}
/***************************************************/
/****************写数据函数************************/
void LCD_write_dat(unsigned char dat)
{
LCDIO=dat;
LCD1602_RS=1;
LCD1602_RW=0;
LCD1602_EN=0;
delay_nms(1);
LCD1602_EN=1;
}
/****************************************************/
/***************设置显示位置**************************/
void LCD_set_xy( unsigned char x, unsigned char y )
{
unsigned char address;
if (y == 1)
address = 0x80 + x;
else
address =0xc0+ x;
LCD_write_command(address);
}
/***************************************************/
/****************显示一个字符**********************/
void LCD_dsp_char( unsigned x,unsigned char y,unsigned char dat)
{
LCD_set_xy( x, y );
LCD_write_dat(dat);
}
/**********************************************/
/***************显示字符串函数***************/
void LCD_dsp_string(unsigned char X,unsigned char Y,unsigned char *s)
{
LCD_set_xy( X, Y );
while (*s)
{
LCD_write_dat(*s);
s ++;
}
}
/***********************************************/
/********** 延时**********************/
void delay_nms(unsigned int n)
{
unsigned int i=0,j=0;
for (i=n;i>0;i–)
for (j=0;j<10;j++);
}
/**************************************/
/***********主函数**************/
void main(void)
{
unsigned char i,j,k,tmp;
LCD_init();
delay_nms(100);
tmp=0x40;//设置CGRAM地址的格式字
k=0;
[1] [2] [3]
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160142.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...