单片机学习笔记---LCD1602功能函数代码

目录

LCD1602.c

模拟写指令的时序

模拟写数据的时序

初始化

显示字符

显示字符串

显示数字

显示有符号的数字

显示16进制数字

显示二进制数

LCD1602.h

main.c


上一篇讲了LCD1602的工作原理,这一节开始代码演示!

新创建工程:LCD1602功能函数代码

新创建main.c,LCD1602.c和LCD1602.h文件

开始代码讲解:

LCD1602.c

先根据原理图声明一下这三个控制引脚和八个数据引脚

#include <REGX52.H>

//引脚定义
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_E=P2^7;
#define LCD_DataPort P0

然后根据上一篇讲的时序逐个定义函数

模拟写指令的时序

首先是写指令

void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;//写指令是低电平
	LCD_RW=0;//写
	LCD_DataPort=Command;//将指令放在数据口Data port上
	LCD_E=1;//使能
	LCD_Delay();//延时1ms
	LCD_E=0;//关闭使能
	LCD_Delay();//延时1ms
}

由于E等于高电平是时间太快了,我们看到手册上的时序参数都是纳秒级的,单片机最低是微秒级的。

我们写指令得需要一定的执行时间,如果E的电平给高立马给低的话,如果太快的话可能读不过来

因此我们需要在E=1之后加一段延时,E=0之后也加一段延时。

我们在STC软件上生成一个1ms的延时函数

放在写指令的函数上方,将函数名改成LCD_Delay()

void LCD_Delay()		//@12.000MHz 1ms
{
	unsigned char i, j;

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

这样我们就可以直接调用这个延时函数了

模拟写数据的时序

void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;//写数据是高电平
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_E=1;
	LCD_Delay();
	LCD_E=0;
	LCD_Delay();
}

接下来我们把这两个函数组合起来根据LCD1602的操作流程完成我们想要的功能!

初始化

void LCD_Init(void)
{
	LCD_WriteCommand(0x38);
	LCD_WriteCommand(0x0C);
	LCD_WriteCommand(0x06);
	LCD_WriteCommand(0x01);
}

显示字符

显示字符之前我们得设置光标位置

void LCD_SetCursor(unsigned char Line,unsigned char Column)//行,列
{
	if(Line==1)//如果是第一行
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else //如果是第二行
	{
		LCD_WriteCommand(0x80|(Column-1)+0x40);
	}
}

如果是第一行,用0x80或上列码-1

如果是第二行,用0x80或上列码-1,再+0x40

(如果不知道0x80是什么请看上一篇博客的解释)

设置好光标位置后开始写显示字符函数 

void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char)
                        //        行,                列,         显示的字符
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

但是显示字符在实际的应用中还是远远不够的,我们可以让它显示别的东西

比如

显示字符串

void LCD_ShowString(unsigned char Line,unsigned char Column,unsigned char *String)
//传过来的unsigned char*型指针代表字符串的首地址

{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)//遍历字符数组
	{
		LCD_WriteData(String[i]);
	}
}

显示数字

由于不能直接显示数字,得先转换成字符然后再显示,

比如传过来的数字是789,那么我们得对789进行转换成字符7,字符8,和字符9再显示

怎么转换呢?

先挨个位取出来数字7,数字8,数字9

789/100=7.89,对7.89取余7.89%10=7(取出来了高位)

789/10%10=8(取出来第二位)

789/1%10=9(取出来最低位)

我们按照这个方法从高位开始取

我们得弄个长度的变量 i,i 和取整时的除数的关系是:

于是我们可以先定义一个次方函数,通过这个函数我们就可以得到返回值等于x的y次方

int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;//如果Y=0,则下面的i<Y直接不成立,直接返回1,符合任何数的0次方等于1的规则
	for(i=0;i<Y;i++)
	{
		Result*=X;
    //如果Y=1,结果等于1*X就等于X的1次方
    //如果Y=2,结果等于1*X*X等于X的2次方
	}
	return Result;//返回值等于x的y次方
}

我们用这个规律Number/LCD_Pow(10,i-1)规律取出来的是数字,想要显示成字符的话,要将数字转换成对应的ASCII码值。怎么转换呢?

我们看着ASCII码表找规律

由此可见,我们想要将一个数字转换成对应的ASCII码值的话可以将它本身的二进制数值加上0x30,也就是字符'0"的ASCII码值就能得到它的ASCII码值了

于是就写成'0'+Number/LCD_Pow(10,i-1)%10

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('0'+Number/LCD_Pow(10,i-1)%10);
        //Number/LCD_Pow(10,i-1) 10=X,i-1=Y
	}
}

显示有符号的数字

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;//变成正数范围是32768,为了保证范围则需要赋给一个无符号的int型
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData('0'+Number1/LCD_Pow(10,i-1)%10);
	}
}

显示16进制数字

如果是16进制了话就不是除以10除以100这样子了,而是除以16再对16取余

所以改成Number/LCD_Pow(16,i-1)%16;

而且16进制从0~F:0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f

而A的ASCII码值不是紧接着9的,所以当数字大于等于10的话要用 if 判断一下

并且这时就不是加0x30了,要改成加上0x41,即 'A' 的ASCII码值

我们将取出来的单个数字(定义成SingleNumber)+‘A’,但是当取出来的SingleNumber大于等于10的话,我们将它+‘A’就会偏移10。

比如说SingleNumber=10,那么它的二进制数是0100 1010,加上‘A’的ASCII码0100 0001, 而我们想要SingleNumber是A的话就得减去10。

如果说SingleNumber=11,那么它的二进制数是0100 1011,加上‘A’的ASCII码0100 0001, 而我们想要SingleNumber是B的话就得减去10。

因此'A'+SingleNumber-10

void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	unsigned char SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;//取出单个数值
		if(SingleNumber<10)//如果单个数值小于10
		{
			LCD_WriteData('0'+SingleNumber);
		}
		else //如果单个数值大于等于10
		{
			LCD_WriteData('A'+SingleNumber-10);
		}
	}
}

显示二进制数

二进制的话就改成除以2和%2,Number/LCD_Pow(2,i-1)%2

取出来之后加上'0'的ASCII码就是对应的字符了

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('0'+Number/LCD_Pow(2,i-1)%2);
	}
}

LCD1602.h

然后声明一下这些函数

#ifndef __LCD1602_H__
#define __LCD1602_H__

void LCD_Init(void);
void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,unsigned 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

main.c

最后在主程序中调用一下这些函数就可以显示了!

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"

void main()
{
	LCD_Init();						//LCD初始化
	LCD_ShowChar(1,1,'A');			//在1行1列显示字符A
	LCD_ShowString(1,3,"Hello");	//在1行3列显示字符串Hello
	LCD_ShowNum(1,9,66,2);			//在1行9列显示数字66,长度为2
	LCD_ShowSignedNum(1,12,-88,2);	//在1行12列显示有符号数字-88,长度为2
	LCD_ShowHexNum(2,1,0xA5,2);		//在2行1列显示十六进制数字0xA5,长度为2
	LCD_ShowBinNum(2,4,0xA5,8);		//在2行4列显示二进制数字0xA5,长度为8
	LCD_ShowChar(2,13,0xDF);		//在2行13列显示编码为0xDF的字符
	LCD_ShowChar(2,14,'C');			//在2行14列显示字符C
	while(1)
	{
	}
}

效果请看视频:

LCD1602液晶显示屏

补充:

如果想要做流动字幕的效果的话,我们可以调用这个指令码0x18

将写指令的函数声明为外部可调用函数

然后在主程序中调用这个函数,传这一个移屏指令过去,放在while循环里面,调用一次,移一次

但是这样太快了,我们可以把我们之前讲过的Delay的模块化程序添加进来,每移一次就Delay 500ms

效果请看视频:

LCD1602液晶屏显示流动字幕

以上就是本节内容,源码会放在评论区,如有问题可评论区留言! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/388924.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux内核-时间子系统(时钟中断)专题汇总

文章目录 概要一、专题汇总1.1、优秀系列博文1.2、时间子系统1.3、高精度定时器hrtimer1.4、RTC硬件芯片驱动 概要 中断机制是计算机系统的重要组成部分&#xff0c;在Linux中也不例外&#xff0c;中断按照来源分为硬中断和软中断&#xff0c;而硬中断根据硬件范围分为外中断和…

MySQL数据库基础(一):数据库概述

文章目录 数据库概述 一、数据库介绍 二、数据库分类 1、关系型数据库 2、非关系型数据库NoSQL 三、常见数据库介绍 1、关系型数据库 2、非关系型数据库 数据库概述 一、数据库介绍 数据库就是存储数据的仓库&#xff0c;其本质是一个文件系统&#xff0c;按照特定的…

AI算法参数个数本身优化空间

一、背景 AI算法的参数数量并非越多越好&#xff0c;也不是越少越好。参数的数量与模型的复杂度密切相关&#xff1a; 1. 参数多&#xff08;高复杂度模型&#xff09;&#xff1a; - 优点&#xff1a;模型具有更强的表达能力和拟合能力&#xff0c;对于复杂的、非线性的数据分…

Backtrader 文档学习- Plotting -Plotting on the same axis

Backtrader 文档学习- Plotting -Plotting on the same axis 1.概述 在同一轴上绘图&#xff0c;绘图是在同一空间上绘制原始数据和稍微(随机)修改的数据&#xff0c;但不是在同一轴上。 核心代码&#xff0c;data数据正负50点。 # The filter which changes the close pri…

PR:视频编辑播放速度技巧

想要视频片段加速或者减速&#xff0c;可以在片段上右击&#xff0c;选择“速度/持续时间...” 速度&#xff1a;可以更改百分比&#xff0c;如改成200%就是加速一倍&#xff0c;改成50%就是减速一倍。 注&#xff1a;如果源视频是正常速度录制的&#xff0c;比如每秒25帧&…

npm使用国内淘宝镜像(最新地址)

目录 前言 一、命令配置 二、使用cnpm安装 三、常见包地址 四、总结 往期回顾 前言 我们前端程序员在使用国外的镜像源速度很慢并且容易下载失败&#xff0c;有时候需要尝试多次才有可能下载成功&#xff0c;很麻烦&#xff0c;但是可以切换为国内镜像源&#xff0c;下…

Docker 在window 2024版笔记 下载 安装 操作 配置

---Docker 前言--- Docker windows版官方版是一款专业开源的应用容器引擎&#xff0c;可以加快用户构建、共享和运行现代应用程序的速度&#xff0c;支持运行Linux和Windows Docker容器。 Docker 在容器的基础上&#xff0c;进行了进一步的封装&#xff0c;从文件系统、网络互…

嵌入式中I2C 相关的硬件问题汇总及死锁解决办法

本文主要介绍如何解决I2C设备硬件设计上的各种问题&#xff0c;希望对大家有所帮助&#xff01; 关于I2C协议详细的讲解&#xff0c;可以参考之前的推文&#xff1a;全面解析 I2C 通信协议 一般情况下&#xff0c; i2c 设备焊接没什么问题&#xff0c;按照设备手册一步步来&a…

初识Qt | 从安装到编写Hello World程序

文章目录 1.前端开发简单分类2.Qt的简单介绍3.Qt的安装和环境配置4.创建简单的Qt项目 1.前端开发简单分类 前端开发&#xff0c;这里是一个广义的概念&#xff0c;不单指网页开发&#xff0c;它的常见分类 网页开发&#xff1a;前端开发的主要领域&#xff0c;使用HTML、CSS …

qt-C++笔记之捕获鼠标滚轮事件并输出滚轮角度增量

qt-C笔记之捕获鼠标滚轮事件并输出滚轮角度增量 code review! 文章目录 qt-C笔记之捕获鼠标滚轮事件并输出滚轮角度增量1.运行2.main.cpp3.main.pro 1.运行 2.main.cpp #include <QApplication> #include <QWidget> #include <QWheelEvent> #include <…

HCIA-HarmonyOS设备开发认证V2.0-轻量系统内核基础-消息队列queue

目录 一、消息队列基本概念二、消息队列运行机制三、消息队列开发流程四、消息队列使用说明五、消息队列接口六、代码分析&#xff08;待续...&#xff09;坚持就有收获 一、消息队列基本概念 队列又称消息队列&#xff0c;是一种常用于任务间通信的数据结构。队列接收来自任务…

Json-序列化字符串时间格式问题

序列化字符串时间格式问题 一、项目场景二、问题描述三、解决方案 一、项目场景 最近C#中需要将实体进行json序列化&#xff0c;使用了Newtonsoft.Json public static void TestJson(){DataTable dt new DataTable();dt.Columns.Add("Age", Type.GetType("Sys…

【数据库】哪些操作会导致索引失效

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;数据库 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 结语 我的其他博客 前言 在数据库管理中&#xff0c;索引的有效性对于查询性能至关重要。然而&#xff0c;索引可能会因为各种操…

插值(一)——多项式插值(C++)

插值 插值的作用是可以将原本比较难计算的函数转换为误差在一定范围内的多项式&#xff0c;比如在单片机中直接计算 x 、 log ⁡ 2 x \sqrt{x}、\log_2x x ​、log2​x之类的函数是比较麻烦的&#xff0c;但是使用插值的方法就可以将其转换为误差可控的只有乘法和加减法的多项…

Codeforces Round 926 (Div. 2)

Codeforces Round 926 (Div. 2) Codeforces Round 926 (Div. 2) A. Sasha and the Beautiful Array 题意&#xff1a;略。 思路&#xff1a;从小到大排序&#xff0c;取前后差和。 AC code&#xff1a; void solve() {int ans 0;cin >> n;for (int i 1; i < n…

iOS AlDente 1.0自动防过充, 拯救电池健康度

经常玩iOS的朋友可能遇到过长时间过充导致的电池鼓包及健康度下降问题。MacOS上同样会出现该问题&#xff0c;笔者用了4年的MBP上周刚拿去修了&#xff0c;就是因为长期不拔电源的充电&#xff0c;开始还是电量一半的时候不接电源会黑屏无法开机&#xff0c;最后连着电源都无法…

模拟算法总结(Java)

目录 模拟算法概述 练习 练习1&#xff1a;替换所有的问号 练习2&#xff1a;提莫攻击 练习3&#xff1a;Z字形变换 模拟算法概述 模拟&#xff1a;根据题目要求的实现过程进行编程模拟&#xff0c;即题目要求什么就实现什么 解决这类题目&#xff0c;需要&#xff1a; 1…

C#,二分法(Bisection Method)求解方程的算法与源代码

1 二分法 二分法是一种分治算法&#xff0c;是一种数学思维。 对于区间[a&#xff0c;b]上连续不断且f&#xff08;a&#xff09;f&#xff08;b&#xff09;<0的函数yf&#xff08;x&#xff09;&#xff0c;通过不断地把函数f&#xff08;x&#xff09;的零点所在的区间…

【STM32 CubeMX】GPIO的工作模式

文章目录 前言一、有哪些工作模式&#xff1f;1.1 GPIO的详细介绍1.2 GPIO的内部框图输入模式输出部分 总结 前言 在嵌入式系统开发中&#xff0c;对于STM32微控制器的GPIO&#xff08;General Purpose Input/Output&#xff09;引脚的配置和使用是至关重要的。GPIO引脚可以通…