当前位置: 首页 > news >正文

(51单片机)LCD展示动画(延时函数)(LLCD1602教程)

前言:

前面我们说过,之前LCD1602模块有点难,但是现在,我们通过几遍博客的学习,今天来讲一下LCD1602的原理

演示视频:

LCD1602流动

源代码:

main.c

#include <STC89C5xRC.H>
#include "LCD1602.h"
#include "Delay.h"void main()
{LCD_Init();						//LCD初始化LCD_ShowChar(1,1,'A');			//在1行1列显示字符ALCD_ShowString(1,3,"Hello");	//在1行3列显示字符串HelloLCD_ShowNum(1,9,66,2);			//在1行9列显示数字66,长度为2LCD_ShowSignedNum(1,12,-88,2);	//在1行12列显示有符号数字-88,长度为2LCD_ShowHexNum(2,1,0xA5,2);		//在2行1列显示十六进制数字0xA5,长度为2LCD_ShowBinNum(2,4,0xA5,8);		//在2行4列显示二进制数字0xA5,长度为8LCD_ShowChar(2,13,0xDF);		//在2行13列显示编码为0xDF的字符LCD_ShowChar(2,14,'C');			//在2行14列显示字符CLCD_ShowString(1,16,"I Love You");while(1){LCD_WriteCommand(0x18);Delay(500);}
}

 LCD1602.c

#include <STC89C5xRC.H>//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0//函数定义:
/*** @brief  LCD1602延时函数,12MHz调用可延时1ms* @param  无* @retval 无*/
void LCD_Delay()		//@11.0592MHz
{unsigned char i, j;i = 11;j = 190;do{while (--j);} while (--i);
}/*** @brief  LCD1602写命令* @param  Command 要写入的命令* @retval 无*/
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();
}/*** @brief  LCD1602写数据* @param  Data 要写入的数据* @retval 无*/
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();
}/*** @brief  LCD1602设置光标位置* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @retval 无*/
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));}
}/*** @brief  LCD1602初始化函数* @param  无* @retval 无*/
void LCD_Init()
{LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动LCD_WriteCommand(0x01);//光标复位,清屏
}/*** @brief  在LCD1602指定位置上显示一个字符* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @param  Char 要显示的字符* @retval 无*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{LCD_SetCursor(Line,Column);LCD_WriteData(Char);
}/*** @brief  在LCD1602指定位置开始显示所给字符串* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  String 要显示的字符串* @retval 无*/
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]);}
}/*** @brief  返回值=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;
}/*** @brief  在LCD1602指定位置开始显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~65535* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
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');}
}/*** @brief  在LCD1602指定位置开始以有符号十进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:-32768~32767* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
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指定位置开始以十六进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~0xFFFF* @param  Length 要显示数字的长度,范围:1~4* @retval 无*/
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');}}
}/*** @brief  在LCD1602指定位置开始以二进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~1111 1111 1111 1111* @param  Length 要显示数字的长度,范围:1~16* @retval 无*/
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_WriteCommand(unsigned char Command);
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

 Delay.c


void Delay(unsigned int xms)
{unsigned char i, j;while(xms--){i = 2;j = 239;do{while (--j);} while (--i);}
}

 Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__void Delay(unsigned int xms);#endif

 代码解析与教程:

 Dealy模块

  • 包含源代码与头文件,不需要知道怎么实现的会用即可,后续使用,直接将头文件和源代码拿过来用即可;

xms是定义的毫秒,1000毫秒就是1秒;模版生成的是1毫秒的,因此xms等于1000

 LCD1602模块

  • LCD1602相关重要知识:
    • LCD1602有两上下两行显示屏,每行各有16个小显示屏,如上图中的LCD_ShowString(1,3,"Hello"),第一个参数是第一行还是第二行,第2个参数是对应第几行的第几个小显示屏,最后一个是输出的东西,同理,到LCD_ShowNum(1,9,123,3)里,前三个和前面一样,最后一个参数是显示的位数,不够就在前面补0,例如输入1,参数为4,显示就是0001,输入23,参数为3,显示就是023
  • 先看原理图

VO是调节显示亮度的,让你的显示屏显示更清楚。

RS,WR,EN(E)是引脚定义,看单片机核心,对应着P25,P26,P27:(下述所有代码WR都写成了RW,不过不影响,引脚对就行)

再看D0-D7,也就是数据,看单片机核心可知,对应着P00-P07,也就是P0,因此宏定义LCD_DataPort=P0;

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

LCD1602,屏幕是16*2的,每一个小格格就是CGRAM+CGROM(字模库)组成,这个东西就是显示数据的,这些数据是DDPAN(数据显示区)来存储的,然后映射到屏幕上,一一对应;但是DDRAM有40*2个小格格,因此,LCD1602,其实可以滚动显示;然后DDRAM是由控制器来决定的,AC就是小格格的地址;

  • DDRAM部分

看第8个DDRAM部分:前两个是00

上图就是DDRAM的地址,也就是小格格的,如果是第一行显示,A6前面那个等于0就行了,A6前面等于1就是第二行显示,剩下的A6-A0就是小格格的地址,比如第一个,0000 0000,因此简写成00H,第二行第一个,0100 0000,0x40,简写40H,以此类推;

  • CGRAM+CGROM部分

这部分可以理解成二维数组,比如你想显示A,在图中找到A,A的列是0100,行是0001,把列放到行的前面组成二进制就是他的地址,0100 0001,就是0x41;

来看编码表,A确实是0x41;

  • 掌握上述知识,就可以写显示数据了,这里只讲写数据/指令:

  • 写指令/数据部分

可以看到,写入一个数据要将RS变化(默认为1),R/W变化(默认为1),EN(E)也要变化,因此有:

/*** @brief  LCD1602延时函数,12MHz调用可延时1ms* @param  无* @retval 无*/
void LCD_Delay()		//@11.0592MHz
{unsigned char i, j;i = 11;j = 190;do{while (--j);} while (--i);
}/*** @brief  LCD1602写命令* @param  Command 要写入的命令* @retval 无*/
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();
}/*** @brief  LCD1602写数据* @param  Data 要写入的数据* @retval 无*/
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();
}

注意:EN(E)操作的时候需要时间,数据读取需要时间,因此延时1ms;RS在写数据和指令的时候不一样,前者1,后者0;

  • 屏幕显示部分

由上控制指令,完成操作,就可以初始化屏幕:

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

然后是显示字符的操作,先用指令确定AC地址:

/*** @brief  LCD1602设置光标位置* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @retval 无*/
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));}
}

然后发送数据:

字符:

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

确定AC地址,然后用函数直接写数据;

字符串:

/*** @brief  在LCD1602指定位置开始显示所给字符串* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  String 要显示的字符串* @retval 无*/
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]);}
}

这部分就是C语言程序部分,看看代码很好理解

数字:

/*** @brief  返回值=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;
}/*** @brief  在LCD1602指定位置开始显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~65535* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
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');}
}

这部分也是C语言代码部分,将数字各位分开,例如:

这样操作。

其他部分:

/*** @brief  在LCD1602指定位置开始以有符号十进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:-32768~32767* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
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指定位置开始以十六进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~0xFFFF* @param  Length 要显示数字的长度,范围:1~4* @retval 无*/
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');}}
}/*** @brief  在LCD1602指定位置开始以二进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~1111 1111 1111 1111* @param  Length 要显示数字的长度,范围:1~16* @retval 无*/
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');}
}

和数字部分差不多,也是C语言程序,认真看代码即可;

 main模块
  • 注释写的很清楚,这里不做解释了
#include <STC89C5xRC.H>
#include "LCD1602.h"
#include "Delay.h"void main()
{LCD_Init();						//LCD初始化LCD_ShowChar(1,1,'A');			//在1行1列显示字符ALCD_ShowString(1,3,"Hello");	//在1行3列显示字符串HelloLCD_ShowNum(1,9,66,2);			//在1行9列显示数字66,长度为2LCD_ShowSignedNum(1,12,-88,2);	//在1行12列显示有符号数字-88,长度为2LCD_ShowHexNum(2,1,0xA5,2);		//在2行1列显示十六进制数字0xA5,长度为2LCD_ShowBinNum(2,4,0xA5,8);		//在2行4列显示二进制数字0xA5,长度为8LCD_ShowChar(2,13,0xDF);		//在2行13列显示编码为0xDF的字符LCD_ShowChar(2,14,'C');			//在2行14列显示字符CLCD_ShowString(1,16,"I Love You");while(1){LCD_WriteCommand(0x18);Delay(500);}
}

 注:该代码是本人自己所写,可能不够好,不够简便,欢迎大家指出我的不足之处。如果遇见看不懂的地方,可以在评论区打出来,进行讨论,或者联系我。上述内容全是我自己理解的,如果你有别的想法,或者认为我的理解不对,欢迎指出!!!如果可以,可以点一个免费的赞支持一下吗?谢谢各位彦祖亦菲!!!!!

相关文章:

  • JVM(Java虚拟机)详解
  • JVM-类加载机制
  • 总结-SQL注入分类手法注入漏洞总结性分化说明
  • FreeRTOS【3】任务调度算法
  • 【缓存与数据库结合最终方案】伪从技术
  • 膳食营养诊断活动:科技赋能,共筑全民健康新基石
  • 使用Django REST Framework快速开发API接口
  • 118. 杨辉三角
  • 开源项目实战学习之YOLO11:ultralytics-cfg-datasets-lvis.yaml文件(五)
  • 接口测试教程详解
  • 使用 Docker 安装 SQL Server 2022 并解决 Navicat 连接问题
  • 商显行业革新者:RK3588的8K显示技术如何打造沉浸式商业体验
  • CSS element-ui Icon Unicode 编码引用
  • 蓝桥杯嵌入式系统设计:高效编程与调试方法全解析
  • arm64适配系列文章-第九章-arm64环境上sentinel的部署
  • 人工智能---当机器人遇到大模型会产生火花吗?
  • 与智者同行:京东零售技术人的成长书单
  • 数学基础 -- 欧拉公式的推导过程学习
  • 零基础上手Python数据分析 (22)案例实战]之利用 Matplotlib Seaborn 进行电商销售数据可视化分析
  • 《Pinia 从入门到精通》Vue 3 官方状态管理 -- 插件扩展篇
  • 传染病防治法修订草案:拟加强医疗机构疾病预防控制能力建设
  • AI翻译技术已走向大规模商用,应用场景覆盖多个关键领域
  • 马上评丨从东方红一号到神二十,中国航天步履不停
  • 吉林建筑大学党委原书记崔征接受纪律审查和监察调查
  • 养胃不是顿顿喝粥,这份“胃的使用说明书”请收好
  • 刺激视网膜可让人“看”到全新颜色