从零开始带你玩转单片机----------【第五期】LCD1602液晶显示

发布于:2022-12-14 ⋅ 阅读:(965) ⋅ 点赞:(0)

❤️第一话——程序模块化基础知识

🤡1.1什么是模块化?

在这里插入图片描述

上图随便打开了一个工程文件,对于复杂的工程文件我们会调用很多函数,假设都写在一个.c文件下,首先代码读起来很不方便,其次对于后面有相同的函数,也不好直接复制粘贴;但是我们模块化后以后,对于看代码、后期抄代码都有好处,并且实际开发一个项目由一个团队来开发,一个功能可能对应一个模块化,也方便团队合作,简言之,程序模块化就是将程序结构划分,增加程序可读性与可移植性

🤖1.2如何模块化?

将其对应程序用.c和.h文件表示,并且添加在工程文件下,在程序最开始的时候用#include调用一下,.c是程序文件,内含函数实现,变量定义等,.h是头文件,内含宏定义,结构体定义,函数声明,用之前的延时函数Delay()函数举个列子如下所示:

/****************延时函数主函数Delay()的.c文件*****************/
#include <intrins.h>

void Delay(unsigned char xms)
{
	while(xms)
	{
	  
		unsigned char i=2;
		unsigned char j=199;
		_nop_();
	  do
	  {
	   while(--j);
	  }while(--i);
		xms--;
  }
}

/****************延时函数Delay()的.h文件*****************/
#ifndef _DELAY_H__
#define _DELAY_H__

void Delay(unsigned char xms);   //放函数的声明部分

#endif

在这里插入图片描述
最后调用的时候,一定要引用该函数的头文件!!!

👾1.3补充知识点——“” <>两种引用符号的区别

  • 引用头文件不同
    #include< >引用的是编译器的类库路径里面的头文件
    #include“ ”引用的是程序目录的相对路径中的头文件

  • 调用文件顺序不同
    #include< >编译程序会先到标准函数库中调用文件
    #include“ ”编译程序会先从当前目录中调用文件

  • 用法不同
    #include< >用来包含标准头文件
    #include“ ”用来包含非标准头文件

❤️第二话——看懂时序图

😃 2.1什么是时序图?

单片机的时序图,纵轴一般表示对应的IO,横轴代表时间轴,根据芯片写程序时都要对应时序图,尤其写通信方面的程序更需要时序图,读懂时序图是基本的本领,不然程序都不知如何写。

🤣 2.2以LCD1602的时序图分析

在这里插入图片描述
在这里插入图片描述

  • 在上面的直线表示高电平,下面的直线表示低电平
  • 线的交叉处表示电平变化处
  • valid Data表示有效数据
    (这里可能有个疑问,RS和RW根据手册要么是0要么是1,时序图上为什么不是一根直线,其实是因为起始状态有高电平和低电平两种可能;E是一根线的原因是E处于高电平下,DB0~DB7的数据才有效)
    == 结合LCD1602写操作时序图可以看下下面代码==
/********************LCD1602写操作***********************/
void lcd_wcmd(unsigned char cmd)
{
  while(lcd_busy());
  LCD_RS=0;
  LCD_RW=0;    //写命令
  LCD_EN=0nops();
  P0=cmd;
  nops();
  LCD_EN=1;  //产生一个下降沿,把命令写入
  nops();
  LCD_EN=0;
}


void lcd_wcmd(unsigned char dat)
{
  while(lcd_busy());
  LCD_RS=1;     //写数据
  LCD_RW=0;    
  LCD_EN=0;
  P0=dat;
  nops();
  LCD_EN=1;  //产生一个下降沿,把数据写入
  nops();
  LCD_EN=0;
}

❤️第三话——LCD1602液晶显示

🏀 3.1 液晶显示原理

(1)液晶的物理特性:液晶控制光线通过的程度是由加在液晶上的电压强弱来控制的。当通电时导通,排列变的有秩序,使光线容易通过,光的路径不改变;不通电时排列混乱,阻止光线通过,改变光的路径。

(2)LCD屏幕的组成
偏光片:上偏光片,和下偏光片,使背光源的光只能通过下偏光片,不能通过下偏光片

彩色滤光片: 不同强度的光经过红绿蓝三色滤光片之后,会形成各种各样的颜色

液晶层: 通过通电方式来控制液晶的分子排列,从而改变背光源发出的光的路径,如果通电则不改变路径,光不能通过上偏光片,如果不通电则改变光的路径,光可以通过上偏光片,从而进行显示

TFT基板:排列有序的薄膜晶体管,每一个薄膜晶体管都可以调整其电压,从而使单个晶体管范围内液晶进行不同的亮度和颜色显示,也就是我们说的像素点

背光源: 提供均匀的背景光源

(3)显示原理:显示由液晶层的分子排列决定,也就是通过加在液晶上的电压强弱来控制,我们只需要控制每个像素点的电压,就可以达到LCD屏幕显示图形图像字符的效果。

🏐 3.2 LCD1602说明

(1)命名规则:1602代表总共两行显示,每行显示有16个显示点。
在这里插入图片描述
第一行第一个位置显示的话,就在00这个地址给显示的内容即可
(2)引脚说明
在这里插入图片描述
(3)字符关系对照表
在这里插入图片描述

显示的内容对应的数据,假设显示一个A,高位0100 低位0001,输入0100 0001就代表A

(4)开发板原理图
在这里插入图片描述
在这里插入图片描述

LCD4(RS)→P2.6
LCD5(RW)→P2.5
LCD6(E)→P2.7
LCD7(DB0)→P0.0
LCD8(DB1)→P0.1
LCD9(DB2)→P0.2
LCD10(DB3)→P0.3
LCD11(DB4)→P0.4
LCD12(DB5)→P0.5
LCD13(DB6)→P0.6
LCD14(DB7)→P0.7

⚽ 3.2 LCD1602模块化代码实列

这个是网上比较全的关于LCD1602的写好代码,用的时候直接复制好,调用即可,下表是对应函数
在这里插入图片描述

/********************LCD1602.c文件**********************/
#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/*
   LCD1602延时函数,12MHz调用可延时1ms
 
  */
void LCD_Delay()
{
	unsigned char i, j;

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

/* LCD1602写命令
   Command 要写入的命令
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/*
    LCD1602写数据
    Data 要写入的数据

  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/*
   LCD1602设置光标位置
   Line 行位置,范围:1~2
   Column 列位置,范围:1~16
  
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/*
   LCD1602初始化函数

  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/*
    在LCD1602指定位置上显示一个字符
     Line 行位置,范围:1~2
    Column 列位置,范围:1~16
    Char 要显示的字符
 
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/*
   在LCD1602指定位置开始显示所给字符串
   Line 起始行位置,范围:1~2
   Column 起始列位置,范围:1~16
   String 要显示的字符串
  
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

/*  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/*  在LCD1602指定位置开始显示所给数字
    Line 起始行位置,范围:1~2
    Column 起始列位置,范围:1~16
   Number 要显示的数字,范围:0~65535
   Length 要显示数字的长度,范围:1~5
  
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/*
    在LCD1602指定位置开始以有符号十进制显示所给数字
    Line 起始行位置,范围:1~2
    Column 起始列位置,范围:1~16
    Number 要显示的数字,范围:-32768~32767
    Length 要显示数字的长度,范围:1~5

  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/*
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
    Line 起始行位置,范围:1~2
    Column 起始列位置,范围:1~16
   Number 要显示的数字,范围:0~0xFFFF
   Length 要显示数字的长度,范围:1~4
  
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/*
    在LCD1602指定位置开始以二进制显示所给数字
   Line 起始行位置,范围:1~2
   Column 起始列位置,范围:1~16
   Number 要显示的数字,范围:0~1111 1111 1111 1111
   Length 要显示数字的长度,范围:1~16
  
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

/*********************LCD1602.h文件**************************/
#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

🥎 3.3 LCD1602实际调用使用案列

在这里插入图片描述

在第二行,第二个位置显示A
要是需要LCD1602具体资料的私聊我,或者留下邮箱免费分享。

本文含有隐藏内容,请 开通VIP 后查看