笔记——C51的LCD1602屏幕显示

LCD1602显示屏三个操作的引脚其它的都是不需要操作的,在手册里面可以看到

分别是RS数据命令端,就是用来操作屏幕的命令的。R/W端就是用来读写操作的,E就是使能端,当需要进行那个状态的时候就是用于使能变换的。

屏幕的命令操作地址也就是指令集,标红的就是常用的。等下代码讲到

还有就是屏幕内置已经是集成可以显示什么字符,还有几个字符是可以自己自定义显示的,因为这个每一个操作位已经是做好选择的,还有就是留了几个空位用于自己自定义的。可以看到一些字符指令集是对应着地址位的。

 

还有可以看到屏幕是每个格子显示的,而且格子之间是有地址的,第一行的地址是00开始

而第二行的地址就是40,所以等下代码就是如果需要在第二行显示字符加上40就可以寻址到第二行去了,而且屏幕是可以显示到28个地址位这么长,但是呢碍于屏幕的大小,只能看到16个字符

可以看到c51的原理图上三个操作引脚是接到P25是读写端、P26是命令端、P27是使能端

 剩下的很多引脚就是数据引脚,用来把数据写到这个引脚然后显示,可以看到整个P0的引脚都是数据引脚

 

接下来就是边写代码边解释为什么这样写。

首先写之前说明一个引脚的操作RS写1为写数据、写0为写指令。RW写1为读,写0为写。E使能1为有效,下降沿执行命令。P0的引脚为数据输入/输出

首先把引脚初始化,这些引脚就是刚才说到的引脚。

#include <regx52.h>
#include "LCD1602.h"

sbit LCD1602_WR=P2^5;	    //读写端	1读0写
sbit LCD1602_RS=P2^6;		//数据/命令	1写数据0写命令
sbit LCD1602_EN=P2^7;		//时序端
#define LCD1602_DAtaport P0   //数据位

初始化完了就要开始看时序图了

 

写指令代码,这里有一个延时函数,是用软件生成的,需要根据每个时钟晶振来确定延迟函数,这里需要延时是因为这个在时序图里面有符号对应着延迟的值,因为每次使能都需要一定的时间来确定虽然这里写着ns级别,按道理来说是可以执行的,但是实际上面的指令集的图却是ms级别,所以要一定的延时写入数据才行。

 

/**
  * @brief  LCD1602专属延迟函数1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay1ms()		//@11.0592MHz需要根据不同的晶振生成不同的延迟
{
	unsigned char i, j;

	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}


void LCD1602_Wirecomd(unsigned char comd)	    //写命令
{
	 LCD1602_RS=0;			  //写命令
	 LCD1602_WR=0;			  //写操作
	 LCD1602_DAtaport=comd;      把命令传输到P0,然后识别到指令操作
	 LCD1602_EN=1;				    //由于没有延迟 反应太快,读不过来
	 LCD_Delay1ms();
	 LCD1602_EN=0;
	 LCD_Delay1ms();
}

写完命令,开始写数据了,只需要把Rs为该为1就是写数据了,使能端的操作还是一样的。由高到低才会有数据为产生,否是是无效的,也就是红色圈起来那个就是数据命令操作,然后RS、RW就要看写1还是0就是读写命令数据了。当这些做完E这个端是由高到低的,这样才完成一个操作

 

/**
  * @brief  LCD1602写数据函数
  * @param  Data:LCD1602要写入的数据
  * @retval 无
  */
void LCD1602_Wiredata(unsigned char Data)		//写数据
{
	 LCD1602_RS=1;			  //写数据
	 LCD1602_WR=0;			  //写操作
	 LCD1602_DAtaport=Data;
	 LCD1602_EN=1;				    //由于没有延迟 反应太快,读不过来
	 LCD_Delay1ms();
	 LCD1602_EN=0;
	 LCD_Delay1ms();
}

 数据命令都写好了就到了屏幕的指令集了,就是屏的初始化,这里调用的就是写命令的函数

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  *声明:里面的初始化函数写的命令集可更改,根据需要的效果更改指令集里面的指令
  */
void LCD1602_Init()	 //初始化指令
{	  //LCD1602_Wirecomd(0x18);  流动字幕
	  LCD1602_Wirecomd(0x38); //模式  8位数据位接口 两行显示 5*7点阵
	  LCD1602_Wirecomd(0x0c); //显示开  光标关  闪烁关1
	  LCD1602_Wirecomd(0x06); //数据读写操作后,光标自动加一,画面不动
	  LCD1602_Wirecomd(0x01); //清屏
}

可以看到0x38红色的线8421-8421码来分就是0x38也就是0011-1000功能指令集这里也写得很清楚而且可以看到无论哪一行RS和RW都是00,除了后面那一行是有1,但是那个基本用不到,为什么光标位移那里不写呢,就是要静止显示。所以就没有写,也可以把注释去掉就可以看到屏幕流动了。

 

写完这些初始化下面开始选行列了,这里除了第一行以外,就是第二行了,所以参数Line除了1就是第二行了,所以写else要加上0x40,为什么写的列要或上0x80就是因为高位从屏幕的左边往右显示减1是因为屏幕的坐标是从0开始。

/**
  * @brief  LCD1602写控制行 列函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @retval 无
  */
void LCD1602_SetCour(unsigned char Line,unsigned char Colum)
{
	if(Line==1)
    {  
	   LCD1602_Wirecomd(0x80|(Colum-1));   	//显示 发送指令0x80|AC  //设置光标位置
	}
	else 
	{
	   LCD1602_Wirecomd(0x80|(Colum-1)+0x40);  //第二行
	}

}

既然初始化命令以及坐标都写好了,里面也集成好了字符,那么就可以直接写显示了。就是这么简单,直接写位置,然后写数据。就行了


/**
  * @brief  LCD1602写单个字符函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @param   Char:‘要写入的字符’	或者ASiic标的十六进制数
  * @retval 无
  */
void LCD1602_ShowChar(unsigned char Line,unsigned char Colum, char Char )
{
   	LCD1602_SetCour(Line,Colum);
	LCD1602_Wiredata(Char);
}

那既然能显示一个字符了,是不是就可以按照这个显示一串字符啦,用指针操作,指向第一个地址,只要我没有遇到结束标志符\0那么就一直执行地址加的操作。

/**
  * @brief  LCD1602写字符串函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @param   *String:“要写入的字符串”
  * @retval 无
  */																//指向字符串首地址
void LCD1602_ShowString(unsigned char Line,unsigned char Colum, char *String )
{ 
    unsigned char i;
   LCD1602_SetCour(Line,Colum);		//设置位置
   for(i=0;String[i]!='\0';i++)	   //识别字符结束标志
	 LCD1602_Wiredata(String[i]);  //写入数据
}

那既然显示字符了,就要显示数字啦,这里数字就要看着asiic表操作了,因为这个集成内置字符就是按照这个表来显示的,其实也很简单。

首先是显示无符号数字,为了显示方便我们数字显示可没有像字符串那样的结束标志,所以要确定长度,而且要把字符数字转换位asiic码里面的字符数字,所以我们的数据要从‘0’的位置开始显示,所以要加上字符‘0’的位置。那么下面有一个操作为什么要这样呢,首先解释x的y次方。可以看到LCD1602_POW(10,i-1)传的参数是10和i-1,首先假装我们的i是3,所以第一次我们的数据就是10的3-1次方那么就是等于10的2次方等于100然后number这个数除100是不是就等于高位的数的第一个数了,然后对10取余也就是这一个数。,然后i等于2的时候就是10的1次方等于10,然后number除10等于后两个数,然后对10取余那么就是剩余个位数了。最后i等于0的时候,就是number除1还是本身,然后求余10也是剩余个位数,所以着3位数就一一显示出来了。

/**
  * @brief  x的y次方
  * 声明:为了方便下面数字显示哪个位置的数字而建立的函数
  */
int LCD1602_POW(int x,int y)  //x的y次方
{
   unsigned char i;
   int Result=1;
   for(i=0;i<y;i++)
      Result*=x;
   
   return Result;
}

/**
  * @brief  LCD1602写无字符数字函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @param   Number:写入的数字   0~65536
  * @param   Length:数字长度
  * @retval 无
  */
void LCD1602_ShowNum(unsigned char Line,unsigned char Colum, unsigned int Number,unsigned char Length )
{														//Number	   		i	 
														//789 /100%10   7	3	10^i-1=100
   unsigned char i;										//789 /10%10	8	2	10^i-1=10
   LCD1602_SetCour(Line,Colum);		//设置位置		    //789 /1%10	    9	1	10^i-1=1
   for(i=Length;i>0;i--)
   {
   	LCD1602_Wiredata('0'+Number/LCD1602_POW(10,i-1)%10);  //从数字转Asiic表  0x30或'0'就是标的字符0开始这样加上多少就是显示多少数字       
   }

}

接下来显示有符号字符了,直接判断这个数大于0还是小于0,然后在数据面前写多一个字符就好了

/**
  * @brief  LCD1602写有符号数字函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @param   Number:写入的数字   -32768~32767
  * @param   Length:数字长度
  * @retval 无
  */

void LCD1602_SingShowNum(unsigned char Line,unsigned char Colum,  int Number,unsigned char Length )
{
   unsigned char i;
   unsigned int Number1=0;	 //65535   为了更好的发输出数字需要变成多位显示,所以多一个变量来存numbwer的值								
   LCD1602_SetCour(Line,Colum); 
  
   if(Number>=0)
   {
   	  LCD1602_Wiredata('+');
	  Number1=Number;
   }
   else
   {
   	 LCD1602_Wiredata('-');
	  Number1=-Number;
   }
   for(i=Length;i>0;i--)
   {
   	LCD1602_Wiredata('0'+Number1/LCD1602_POW(10,i-1)%10);  //从数字转Asiic表  0x30或'0'就是标的字符0开始这样加上多少就是显示多少数字       
   }

}

显示十六进制,同样设置长度,然后按照刚才的次方函数把10该为16就是16进制的啦,但是刚才的数字显示是在0开始,现在的十六进制就要在字符‘A’的位置开始了。因为大于10的时候我们要用a,b,c,d,e,f显示,所以大于等于10的时候就要在a的位置开始,不然还是从0开始

/**
  * @brief  LCD1602写十六进制函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @param   Number:写入的十六进制数  0x00~0xff
  * @param   Length:数字长度  2 
  * @retval 无
  */
void LCD1602_ShowHexNum(unsigned char Line,unsigned char Colum, unsigned int Number,unsigned char Length )
{
   unsigned char i,SingleNumber;
   SingleNumber=Number;										
   LCD1602_SetCour(Line,Colum);		//设置位置		   
   for(i=Length;i>0;i--)
   {
     SingleNumber=Number/LCD1602_POW(16,i-1)%16;
	if(SingleNumber>=10)
	{
		LCD1602_Wiredata('A'+SingleNumber-10);   //因为16进制大于10的话开始的字符偏移用重新设置	,但是如果大于10我们要从a开始计所以要再减去10
	}
	else
	{
   		LCD1602_Wiredata('0'+SingleNumber);  //从数字转Ascii表  0x30或'0'就是标的字符0开始这样加上多少就是显示多少数字       
    }
   }
   

}

二进制显示一个到了只有1和0,那么就是2的次方,数字只有0和1不能超过2,所以要对2求余。都是一个道理。

/**
  * @brief  LCD1602写二进制函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @param   Number:写入的十六进制数  0x00~0xff
  * @param   Length:数字长度  8
  * @retval 无
  */
void LCD1602_ShowBinNum(unsigned char Line,unsigned char Colum, unsigned int Number,unsigned char Length )
{
   unsigned char i;									
   LCD1602_SetCour(Line,Colum);		//设置位置		    
   for(i=Length;i>0;i--)
   {
   	LCD1602_Wiredata('0'+Number/LCD1602_POW(2,i-1)%2);  //显示二进制数 对2求余只显示0或1
   }						//因为输入的是十六进制数,所以对应的是Ascii表的 二进制数
   

}

 代码解释到这里差不多了,剩下的也可以自己拓展类似于8进制,还有一些其他的都要可以慢慢试试。还有就是指令集也是每一个写一遍看看效果怎么样,这样自己印象更深刻。

接下来完整代码.c文件

#include <regx52.h>
#include "LCD1602zijida.h"

sbit LCD1602_WR=P2^5;	    //读写端	1读0写
sbit LCD1602_RS=P2^6;		//数据/命令	1写数据0写命令
sbit LCD1602_EN=P2^7;		//时序端
#define LCD1602_DAtaport P0   //数据位

/**
  * @brief  LCD1602专属延迟函数
  * @param  无
  * @retval 无
  */
void LCD_Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令函数
  * @param  comd:LCD162要写入的命令,就是指令集里面的命令
  * @retval 无
  */
void LCD1602_Wirecomd(unsigned char comd)	    //写命令
{
	 LCD1602_RS=0;			  //写命令
	 LCD1602_WR=0;			  //写操作
	 LCD1602_DAtaport=comd;
	 LCD1602_EN=1;				    //由于没有延迟 反应太快,读不过来
	 LCD_Delay1ms();
	 LCD1602_EN=0;
	 LCD_Delay1ms();
}

/**
  * @brief  LCD1602写数据函数
  * @param  Data:LCD1602要写入的数据
  * @retval 无
  */
void LCD1602_Wiredata(unsigned char Data)		//写数据
{
	 LCD1602_RS=1;			  //写数据
	 LCD1602_WR=0;			  //写操作
	 LCD1602_DAtaport=Data;
	 LCD1602_EN=1;				    //由于没有延迟 反应太快,读不过来
	 LCD_Delay1ms();
	 LCD1602_EN=0;
	 LCD_Delay1ms();
}


/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  *声明:里面的初始化函数写的命令集可更改,根据需要的效果更改指令集里面的指令
  */
void LCD1602_Init()	 //初始化指令
{	  //LCD1602_Wirecomd(0x18);  流动字幕
	  LCD1602_Wirecomd(0x38); //模式  8位数据位接口 两行显示 5*7点阵
	  LCD1602_Wirecomd(0x0c); //显示开  光标关  闪烁关1
	  LCD1602_Wirecomd(0x06); //数据读写操作后,光标自动加一,画面不动
	  LCD1602_Wirecomd(0x01); //清屏
}


/**
  * @brief  LCD1602写控制行 列函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @retval 无
  */
void LCD1602_SetCour(unsigned char Line,unsigned char Colum)
{
	if(Line==1)
    {  
	   LCD1602_Wirecomd(0x80|(Colum-1));   	//显示 发送指令0x80|AC  //设置光标位置
	}
	else 
	{
	   LCD1602_Wirecomd(0x80|(Colum-1)+0x40);  //第二行
	}

}

/**
  * @brief  LCD1602写单个字符函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @param   Char:‘要写入的字符’	或者ASiic标的十六进制数
  * @retval 无
  */
void LCD1602_ShowChar(unsigned char Line,unsigned char Colum, char Char )
{
   	LCD1602_SetCour(Line,Colum);
	LCD1602_Wiredata(Char);
}

/**
  * @brief  LCD1602写字符串函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @param   *String:“要写入的字符串”
  * @retval 无
  */																//指向字符串首地址
void LCD1602_ShowString(unsigned char Line,unsigned char Colum, char *String )
{ 
    unsigned char i;
   LCD1602_SetCour(Line,Colum);		//设置位置
   for(i=0;String[i]!='\0';i++)	   //识别字符结束标志
	 LCD1602_Wiredata(String[i]);  //写入数据
}

/**
  * @brief  x的y次方
  * 声明:为了方便下面数字显示哪个位置的数字而建立的函数
  */
int LCD1602_POW(int x,int y)  //x的y次方
{
   unsigned char i;
   int Result=1;
   for(i=0;i<y;i++)
      Result*=x;
   
   return Result;
}

/**
  * @brief  LCD1602写无字符数字函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @param   Number:写入的数字   0~65536
  * @param   Length:数字长度
  * @retval 无
  */
void LCD1602_ShowNum(unsigned char Line,unsigned char Colum, unsigned int Number,unsigned char Length )
{														//Number	   		i	 
														//789 /100%10   7	3	10^i-1=100
   unsigned char i;										//789 /10%10	8	2	10^i-1=10
   LCD1602_SetCour(Line,Colum);		//设置位置		    //789 /1%10	    9	1	10^i-1=1
   for(i=Length;i>0;i--)
   {
   	LCD1602_Wiredata('0'+Number/LCD1602_POW(10,i-1)%10);  //从数字转Asiic表  0x30或'0'就是标的字符0开始这样加上多少就是显示多少数字       
   }

}


/**
  * @brief  LCD1602写有符号数字函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @param   Number:写入的数字   0~65536
  * @param   Length:数字长度
  * @retval 无
  */

void LCD1602_SingShowNum(unsigned char Line,unsigned char Colum,  int Number,unsigned char Length )
{
   unsigned char i;
   unsigned int Number1=0;	 //65535   为了更好的发输出数字需要变成多位显示								
   LCD1602_SetCour(Line,Colum); 
  
   if(Number>=0)
   {
   	  LCD1602_Wiredata('+');
	  Number1=Number;
   }
   else
   {
   	 LCD1602_Wiredata('-');
	  Number1=-Number;
   }
   for(i=Length;i>0;i--)
   {
   	LCD1602_Wiredata('0'+Number1/LCD1602_POW(10,i-1)%10);  //从数字转Asiic表  0x30或'0'就是标的字符0开始这样加上多少就是显示多少数字       
   }

}

/**
  * @brief  LCD1602写十六进制函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @param   Number:写入的十六进制数  0x00~0xff
  * @param   Length:数字长度  2 
  * @retval 无
  */
void LCD1602_ShowHexNum(unsigned char Line,unsigned char Colum, unsigned int Number,unsigned char Length )
{
   unsigned char i,SingleNumber;
   SingleNumber=Number;										//789 /10%10	8	2	10^i-1=10
   LCD1602_SetCour(Line,Colum);		//设置位置		    //789 /1%10	    9	1	10^i-1=1
   for(i=Length;i>0;i--)
   {
     SingleNumber=Number/LCD1602_POW(16,i-1)%16;
	if(SingleNumber>=10)
	{
		LCD1602_Wiredata('A'+SingleNumber-10);   //因为16进制大于10的话开始的字符偏移用重新设置	,但是如果大于10我们要从a开始计所以要再减去10
	}
	else
	{
   		LCD1602_Wiredata('0'+SingleNumber);  //从数字转Ascii表  0x30或'0'就是标的字符0开始这样加上多少就是显示多少数字       
    }
   }
   

}

/**
  * @brief  LCD1602写二进制函数
  * @param   Line:1或2
  * @param   Colum:1~16
  * @param   Number:写入的十六进制数  0x00~0xff
  * @param   Length:数字长度  8
  * @retval 无
  */
void LCD1602_ShowBinNum(unsigned char Line,unsigned char Colum, unsigned int Number,unsigned char Length )
{
   unsigned char i;									
   LCD1602_SetCour(Line,Colum);		//设置位置		    
   for(i=Length;i>0;i--)
   {
   	LCD1602_Wiredata('0'+Number/LCD1602_POW(2,i-1)%2);  //显示二进制数 对2求余只显示0或1
   }						//因为输入的是十六进制数,所以对应的是Ascii表的 二进制数
   

}

.h文件

#ifndef _LCD1602ZIJIDA_H_
#define _LCD1602ZIJIDA_H_
void LCD1602_Init();	 //初始化指令
void LCD_Delay1ms();
void LCD1602_Wirecomd(unsigned char comd);	    //写命令
void LCD1602_Wiredata(unsigned char Data);		//写数据
void LCD1602_SetCour(unsigned char Line,unsigned char Colum);
void LCD1602_ShowChar(unsigned char Line,unsigned char Colum,char Char );
void LCD1602_ShowString(unsigned char Line,unsigned char Colum, char *String );
void LCD1602_ShowNum(unsigned char Line,unsigned char Colum, unsigned int Number,unsigned char Length );
void LCD1602_SingShowNum(unsigned char Line,unsigned char Colum,  int Number,unsigned char Length );
void LCD1602_ShowHexNum(unsigned char Line,unsigned char Colum, unsigned int Number,unsigned char Length );
void LCD1602_ShowBinNum(unsigned char Line,unsigned char Colum, unsigned int Number,unsigned char Length );

#endif

  • 7
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
基于单片机的的LCD1602显示,C语言编程。#include "lcd.h" void Lcd1602_Delay1ms(uint c) { uchar a,b; for (; c>0; c--) { for (b=199;b>0;b--) { for(a=1;a>0;a--); } } } /******************************************************************************* * 函 数 名 : LcdWriteCom * 函数功能 : 写命令 * 输 入 : com * 输 出 : 无 *******************************************************************************/ 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; } /******************************************************************************* * 函 数 名 : LcdWriteData * 函数功能 : 写数据 * 输 入 : dat * 输 出 : 无 *******************************************************************************/ 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; } /******************************************************************************* * 函 数 名 : LcdInit() * 函数功能 : 初始化LCD屏 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void LcdInit() { LcdWriteCom(0x38); //开显示 LcdWriteCom(0x0c); //开显示不显示光标 LcdWriteCom(0x06); //写一个指针加1 LcdWriteCom(0x01); //清屏 LcdWriteCom(0x80); //设置数据指针起点 } /******************************************************************************* * 函 数 名 : LcdIdiszhu() * 函数功能 : 主屏显示 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void lcddiszhu() { uchar i; uchar lcd1[]="Model i ii iii"; uchar lcd2[]="Choose 1 2 3 "; LcdWriteCom(0x80); for(i=0;i<15;i++) { LcdWriteData(lcd1[i]); } LcdWriteCom(0x80+0x40); fo

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

c-tion

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值