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

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





显示效果如下图:

非常完美

  • 20
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是基于51单片机LCD1602的两行显示的基本代码: ```c #include <reg51.h> // 引入51单片机寄存器定义文件 #define LCD1602_DB P0 // 定义LCD1602数据总线为P0口 sbit LCD1602_RS = P2^0; // 定义LCD1602 RS引脚为P2.0口 sbit LCD1602_RW = P2^1; // 定义LCD1602 RW引脚为P2.1口 sbit LCD1602_E = P2^2; // 定义LCD1602 E引脚为P2.2口 void delay(unsigned int i) { // 延时函数 while(i--); } void LCD1602_WriteCmd(unsigned char cmd) { // 写命令函数 LCD1602_RS = 0; // 选择命令寄存器 LCD1602_RW = 0; // 写操作 LCD1602_E = 1; // 使能 LCD1602_DB = cmd; // 写入命令 delay(50); // 延时 LCD1602_E = 0; // 禁止 } void LCD1602_WriteData(unsigned char dat) { // 写数据函数 LCD1602_RS = 1; // 选择数据寄存器 LCD1602_RW = 0; // 写操作 LCD1602_E = 1; // 使能 LCD1602_DB = dat; // 写入数据 delay(50); // 延时 LCD1602_E = 0; // 禁止 } void LCD1602_Init() { // LCD1602初始化函数 LCD1602_WriteCmd(0x38); // 设置16*2显示,5*7点阵,8位数据接口 LCD1602_WriteCmd(0x0c); // 显示器开,光标不显示,光标闪烁不显示 LCD1602_WriteCmd(0x06); // 光标右移,字符不移动 LCD1602_WriteCmd(0x01); // 清除显示 } void LCD1602_Display(unsigned char x, unsigned char y, unsigned char *p) { // LCD1602显示函数 unsigned char addr; if(x == 0) { // 第1行 addr = 0x80 + y; // 地址为0x80 + 列数 } else { // 第2行 addr = 0xc0 + y; // 地址为0xc0 + 列数 } LCD1602_WriteCmd(addr); // 设置显示地址 while(*p) { // 循环显示字符LCD1602_WriteData(*p++); // 写入数据 } } void main() { LCD1602_Init(); // LCD1602初始化 LCD1602_Display(0, 0, "Hello, World!"); // 在第1行第1列显示字符LCD1602_Display(1, 0, "From AI Chatbot!"); // 在第2行第1列显示字符串 while(1); // 循环等待 } ``` 该代码实现了在LCD1602上显示两行字符串,可以根据需要修改每行字符串的内容和列数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值