基于51单片机点亮LCD1602+自定义字符

    技术2025-08-01  12

    1602有8位的数据口和4位的数据口,今天我们用到的是8位的数据口。废话不多说,直接上原理图

    8位数据口一定要加上拉电阻,要不然驱动不了。

    写数据和写命令的时序

    清屏指令

    开显示指令

    显示字符的地址 第一行0x80+0x00开始,第二行0x80+0x40开始

    功能配置

    上源代码

    1.main函数

    /************************************************************************************** * LCD1602液晶显示实验 * ***************************************************************************************/ #include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器 #include "lcd.h" typedef unsigned int u16; //对数据类型进行声明定义 typedef unsigned char u8; u8 Disp[]="ROC_CHAO"; //定义数组 为字符串类型 /******************************************************************************* * 函 数 名 : main * 函数功能 : 主函数 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void main(void) { u8 i; LcdInit(); //对屏幕进行初始化 LcdWriteCom(0x80+0x45);//从第二行第五个字符开始显示 for(i=0;i<8;i++) { LcdWriteData(Disp[i]); } while(1); }

    lcd.h

    #ifndef __LCD_H_ #define __LCD_H_ /********************************** 当使用的是4位数据传输的时候定义, 使用8位取消这个定义 **********************************/ //#define LCD1602_4PINS /********************************** 包含头文件 **********************************/ #include<reg52.h> //---重定义关键词---// #ifndef uchar #define uchar unsigned char #endif #ifndef uint #define uint unsigned int #endif /********************************** PIN口定义 **********************************/ #define LCD1602_DATAPINS P0 sbit LCD1602_E=P2^7; sbit LCD1602_RW=P2^5; sbit LCD1602_RS=P2^6; /********************************** 函数声明 **********************************/ /*在51单片机12MHZ时钟下的延时函数*/ void Lcd1602_Delay1ms(uint c); //误差 0us /*LCD1602写入8位命令子函数*/ void LcdWriteCom(uchar com); /*LCD1602写入8位数据子函数*/ void LcdWriteData(uchar dat) ; /*LCD1602初始化子程序*/ void LcdInit(); #endif

    ldc.c

    #include "lcd.h" /******************************************************************************* * 函 数 名 : Lcd1602_Delay1ms * 函数功能 : 延时函数,延时1ms * 输 入 : c * 输 出 : 无 * 说 名 : 该函数是在12MHZ晶振下,12分频单片机的延时。 *******************************************************************************/ void Lcd1602_Delay1ms(uint c) //误差 0us { uchar a,b; for (; c>0; c--) { for (b=199;b>0;b--) { for(a=1;a>0;a--); } } } /******************************************************************************* * 函 数 名 : LcdWriteCom * 函数功能 : 向LCD写入一个字节的命令 * 输 入 : com * 输 出 : 无 *******************************************************************************/ #ifndef LCD1602_4PINS //当没有定义这个LCD1602_4PINS时 void LcdWriteCom(uchar com) //写入命令 { LCD1602_E = 0; //使能 LCD1602_RS = 0; //选择发送命令 LCD1602_RW = 0; //选择写入 LCD1602_DATAPINS = com; //放入命令 Lcd1602_Delay1ms(1); //等待数据稳定 LCD1602_E = 1; //写入时序 Lcd1602_Delay1ms(5); //保持时间 LCD1602_E = 0; } #else void LcdWriteCom(uchar com) //写入命令 { LCD1602_E = 0; //使能清零 LCD1602_RS = 0; //选择写入命令 LCD1602_RW = 0; //选择写入 LCD1602_DATAPINS = com; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改 Lcd1602_Delay1ms(1); LCD1602_E = 1; //写入时序 Lcd1602_Delay1ms(5); LCD1602_E = 0; LCD1602_DATAPINS = com << 4; //发送低四位 Lcd1602_Delay1ms(1); LCD1602_E = 1; //写入时序 Lcd1602_Delay1ms(5); LCD1602_E = 0; } #endif /******************************************************************************* * 函 数 名 : LcdWriteData * 函数功能 : 向LCD写入一个字节的数据 * 输 入 : dat * 输 出 : 无 *******************************************************************************/ #ifndef LCD1602_4PINS void LcdWriteData(uchar dat) //写入数据 { LCD1602_E = 0; //使能清零 LCD1602_RS = 1; //选择输入数据 LCD1602_RW = 0; //选择写入 LCD1602_DATAPINS = dat; //写入数据 Lcd1602_Delay1ms(1); LCD1602_E = 1; //写入时序 Lcd1602_Delay1ms(5); //保持时间 LCD1602_E = 0; } #else void LcdWriteData(uchar dat) //写入数据 { LCD1602_E = 0; //使能清零 LCD1602_RS = 1; //选择写入数据 LCD1602_RW = 0; //选择写入 LCD1602_DATAPINS = dat; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改 Lcd1602_Delay1ms(1); LCD1602_E = 1; //写入时序 Lcd1602_Delay1ms(5); LCD1602_E = 0; LCD1602_DATAPINS = dat << 4; //写入低四位 Lcd1602_Delay1ms(1); LCD1602_E = 1; //写入时序 Lcd1602_Delay1ms(5); LCD1602_E = 0; } #endif /******************************************************************************* * 函 数 名 : LcdInit() * 函数功能 : 初始化LCD屏 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ #ifndef LCD1602_4PINS void LcdInit() //LCD初始化子程序 { LcdWriteCom(0x38); //开显示 功能设定指令 配置数据总线为7位 显示两行 5*7点阵/字符 LcdWriteCom(0x0f); //开显示显示光标 光标闪烁 LcdWriteCom(0x06); //写一个指针加1 写入字符后光标右移动,屏幕不移动 LcdWriteCom(0x01); //清屏 LcdWriteCom(0x80); //设置数据指针起点 第一行第一个字符的地址为80H } #else void LcdInit() //LCD初始化子程序 { LcdWriteCom(0x32); //将8位总线转为4位总线 LcdWriteCom(0x28); //在四位线下的初始化 LcdWriteCom(0x0c); //开显示不显示光标 LcdWriteCom(0x06); //写一个指针加1 LcdWriteCom(0x01); //清屏 LcdWriteCom(0x80); //设置数据指针起点 } #endif

    实验现象

    二,自定义字符

    对于自带字符的显示,只要把ASCLL码填入lcd中显示就可以了

    要显示我们自定义的字符,就要用到LCD中的CGRAM存储器(character generate RAM),而我们之前用的显示自带的字符用到的是DDRAM,两个是不同的。看液晶手册我们知道,CGRAM的容量是64个字节,而一个字符是8个字节,所以一共能显示8个自定义的字符。内部常用字符的显示是从0x20开始的,0x00 ~ 0x0F是专门留给自定义字符显示用的,0x00~0x07和0x80~0x0F显示的内容是一样的,也就是说0x00=0x08,0x01=0x09,以此类推。CGRAM共128个位,地址是0x40~0x7F,128/8=16正好对应的是0x00~0x0F共16个,刚才说了,0x00与0x08对应,0x01与0x09对应,共16个,这并不矛盾!说了这么多,那么怎样显示一个自定义字符呢?   首先我们要清楚LCD1602显示字符的点阵大小,眼力好的可以看出来,LCD1602一个显示字符的位置是5*8的点阵,也就是说它所能显示的点阵图形的大小是5*8的!要显示一个自定义的字符,首先我们要知道所显示自定义字符的点阵数据,也就是在一个5*8的点阵上那个点是黑的(将该点点黑,就是高电平----1),哪个点是白的(该点不显示,为低电平----0),但是我们送入到LCD中的是ASCII码,它是8位的数据,而一个显示字符的点阵大小只是5*8的,显然不够,显示的办法是8*8点阵的前三列不用,也就是不显示,我们只用后面的5列来显示。   然后设定我们是要定义第几个自定义字符,前面已经介绍了,LCD1602最多显示8个自定义字符;然后要规定在液晶的什么位置显示自定义字符,看过数据手册我们知道,第一行第一个位置的地址是0x80,第二行一个位置的地址是0xC0。最后就是要显示我们定义的第几个字符其对应CGRAM地址的关系式是:0x00:第一个(0x40)                       0x01:第二个(0x48)    0x02:第三个(0x50)                       0x03:第四个(0x58) 0x04:第五个(0x60)                       0x05:第六个(0x68)     0x06:第七个(0x70)                       0x07:第八个(0x78)

    自定义有两种方式,1.利用取模软件2.自己画5*8点阵,然后自己算

    现在介绍取模软件的使用方法

    她长这个样子

     

    8*8是因为一个bit8位 每一行都是一个bit 因为1602的是5*8所以前三列不用,不要点亮,这样子只是为了好取数

    下面是生成好的自定义字符代码数组,供参考: uchar code table1[]={0x10,0x06,0x09,0x08,0x08,0x09,0x06,0x00};//字符℃ uchar code table4[]={0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00};//字符一 uchar code table5[]={0x00,0x0E,0x00,0x00,0x00,0x1F,0x00,0x00};//字符二 uchar code table6[]={0x0E,0x00,0x00,0x0E,0x00,0x00,0x1F,0x00};//字符三 uchar code table7[]={0x1F,0x11,0x15,0x15,0x1F,0x11,0x1F,0x00};//字符四 uchar code table8[]={0x1E,0x08,0x08,0x1E,0x0A,0x0A,0x1F,0x00};//字符五 uchar code table9[]={0x08,0x1F,0x12,0x0F,0x0A,0x1F,0x02,0x00};//字符年 uchar code table10[]={0x0F,0x09,0x0F,0x09,0x0F,0x09,0x13,0x00};//字符月 uchar code table11[]={0x1F,0x11,0x11,0x1F,0x11,0x11,0x1F,0x00};//字符日

    上主函数代码,其他文件不用改变

    /************************************************************************************** * LCD1602液晶显示实验 * ***************************************************************************************/ #include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器 #include "lcd.h" #include "intrins.h" typedef unsigned int u16; //对数据类型进行声明定义 typedef unsigned char u8; void delay1s(void); u8 Disp[]="ROC_CHAO "; //定义数组 为字符串类型 unsigned char table[]={0x08,0x1F,0x12,0x0F,0x0A,0x1F,0x02,0x00};//年 unsigned char table1[]={0x0F,0x09,0x0F,0x09,0x0F,0x09,0x13,0x00};//月 unsigned char table2[]={0x1F,0x11,0x11,0x1F,0x11,0x11,0x1F,0x00};//日 /******************************************************************************* * 函 数 名 : main * 函数功能 : 主函数 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void main(void) { u8 i; LcdInit(); //对屏幕进行初始化 LcdWriteCom(0x40);//自定义第一个字符 年 for(i=0;i<8;i++) { LcdWriteData(table[i]); } LcdWriteCom(0x48);//自定义第二个字符 月 for(i=0;i<8;i++) { LcdWriteData(table1[i]); } LcdWriteCom(0x50);//自定义第二个字符 日 for(i=0;i<8;i++) { LcdWriteData(table2[i]); } LcdWriteCom(0x80); LcdWriteData(0x00); //第一个字符显示在 第一排第一个 LcdWriteCom(0x80+0x02); LcdWriteData(0x01); //第二个字符显示在 第一排第三个 LcdWriteCom(0x80+0x04); LcdWriteData(0x02); //第三个字符显示在 第一排第五个 while(1); }

    显示效果如下图:

    非常完美

    Processed: 0.013, SQL: 9