单片机学习笔记---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();//延时1msLCD_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列显示字符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列显示字符Cwhile(1){}
}

效果请看视频:

LCD1602液晶显示屏

补充:

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

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

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

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

效果请看视频:

LCD1602液晶屏显示流动字幕

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

黑马程序员——移动Web——day02

目录 空间转换 空间转换简介平移视距旋转左手法则rotate3d-了解立体呈现案例-3d导航缩放动画 动画实现步骤animation复合属性animation拆分写法案例-走马灯精灵动画多组动画综合案例-全名出游 背景云彩位置和动画文字动画 1.空间转换 空间转换简介 空间&#xff1a;是从坐标…

AcWing 112. 雷达设备(区间贪心)

[题目概述] 假设海岸是一条无限长的直线&#xff0c;陆地位于海岸的一侧&#xff0c;海洋位于另外一侧。 每个小岛都位于海洋一侧的某个点上。 雷达装置均位于海岸线上&#xff0c;且雷达的监测范围为 d&#xff0c;当小岛与某雷达的距离不超过 d 时&#xff0c;该小岛可以被雷…

[Angular 基础] - 自定义事件 自定义属性

[Angular 基础] - 自定义事件 & 自定义属性 之前的笔记&#xff1a; [Angular 基础] - Angular 渲染过程 & 组件的创建 [Angular 基础] - 数据绑定(databinding) [Angular 基础] - 指令(directives) 以上是能够实现渲染静态页面的基础 之前的内容主要学习了怎么通过…

第13章 网络 Page727~728 asio定时器例子:后创建的定时器先产生到点事件

代码&#xff1a; 35行&#xff0c;42行&#xff0c;51行&#xff0c;分别构造三个对象&#xff0c; 36行&#xff0c;43行&#xff0c;52行&#xff0c;设置了三个任务peng1、peng2、peng3&#xff0c;并将任务交给io_service对象&#xff08;不需要ios的run()方法启动起来&a…

如何创建和填写 PDF 表单,简化您的文档工作流

阅读本文&#xff0c;了解如何在开源办公套件 ONLYOFFICE 中创建和填写 PDF 表单。 ONLYOFFICE表单发展小史 ONLYOFFICE 表单首个版本发布于2022年1月18日&#xff0c;是 ONLYOFFICE 版本 7.0 更新的一部分。 您可以使用 ONLYOFFICE 表单&#xff0c;创建各种类型的模板文档&a…

Linux多线程[一]

引入知识 进程在线程内部执行是OS的系统调度单位。 内核中针对地址空间&#xff0c;有一种特殊的结构&#xff0c;VM_area_struct。这个用来控制虚拟内存中每个malloc等申请的空间&#xff0c;来区别每个malloc的是对应的堆区哪一段。OS可以做到资源的精细度划分。 对于磁盘…

Android之Android.bp文件格式语法(一百八十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

vue学习106-120

创建项目p106 router&#xff0c;store和app.vue不用删 清一下router里的路由配置 vant组件库p107 目标&#xff1a;认识第三方vue组件库vant-ui&#xff08;cv战士&#xff09; 封装好了的组件整合在一起就是组件库 http://vant-contrib.gitee.io/vant/v2/#/zh-CN/ vue2用va…

2024.02.13作业

21. c 22. b 23. b 5先出栈意味着1234都在栈内&#xff0c;此时1不能比2&#xff0c;3先出栈 24. b, c, d: 10, 12, 120 25. 2, 5 26. 数组越界&#xff0c;可能出现段错误 27. 0, 41 28. 1, 320 29. *a *b; *b *a - *b; *a - *b; 30. 0x801005&#xff1b;0x8…

计算机设计大赛 深度学习YOLOv5车辆颜色识别检测 - python opencv

文章目录 1 前言2 实现效果3 CNN卷积神经网络4 Yolov56 数据集处理及模型训练5 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习YOLOv5车辆颜色识别检测 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0…

Java实现贫困地区人口信息管理系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 人口信息管理模块2.2 精准扶贫管理模块2.3 特殊群体管理模块2.4 案件信息管理模块2.5 物资补助模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 人口表3.2.2 扶贫表3.2.3 特殊群体表3.2.4 案件表3.2.5 物资补助表 四…

NARF关键点检测及SAC-IA粗配准

一、生成对应深度图 C #include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/common/io.h> #include <pcl/range_image/range_image.h> #include <pcl/visualization/range_image_visualizer.h>…

动态内存管理:new和delete的底层探索

之前我们在C语言上是学过malloc和calloc还要realloc等函数来在堆上获取相应的内存&#xff0c;但是这些函数是存在缺陷的&#xff0c;今天引入对new和delete的学习&#xff0c;来了解new和delete的底层实现。 首先就是在C中我们为什么要对内存进行区域的分块&#xff1f; 答案…

ChatGPT高效提问—prompt实践(漏洞风险分析-重构建议-识别内存泄漏)

ChatGPT高效提问—prompt实践&#xff08;漏洞风险分析-重构建议-识别内存泄漏&#xff09; 1.1 漏洞和风险分析 ChatGPT还可以帮助开发人员预测代码的潜在风险&#xff0c;识别其中的安全漏洞&#xff0c;而不必先运行它&#xff0c;这可以让开发人员及早发现错误&#xff0…

【vscode】在vscode中如何导入自定义包

只需要额外添加这两条语句即可&#xff1a; import os,sys sys.path.append("../..") 需要注意的是&#xff0c;ipynb 文件打开的工作目录是文件本身的路径&#xff0c;而 py 文件打开的工作路径是 vscode 打开的路径。 相比较而言 pycharm 中创建好项目之后并不…

FT2232调试记录(2)

FT2232调试记录 &#xff08;1&#xff09;获取当前连接的FTDI设备通道个数:&#xff08;2&#xff09;获取当前连接的设备通道的信息:&#xff08;3&#xff09;配置SPI的通道:&#xff08;4&#xff09;如何设置GPIO:&#xff08;5&#xff09;DEMO测试&#xff1a; FT2232调…

【阅读笔记】空域保边降噪《Side Window Filtering》

1、保边滤波背景 保边滤波器的代表包括双边滤波、引导滤波&#xff0c;但是这类滤波器有一个问题&#xff0c;它们均将待处理的像素点放在了方形滤波窗口的中心。但如果待处理的像素位于图像纹理或者边缘&#xff0c;方形滤波核卷积的处理结果会导致这个边缘变模糊。 基于这个…

揭秘 2024 春晚刘谦魔术——代码还原

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、魔术大概流程 二、代码实现各个步骤 2.1 partition&#xff08;对半撕牌&#xff09; 2.2 bottom&#xff08;将 n 张牌置底…

基于微信小程序的智能社区服务小程序,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

谈谈Lombok的坑

Lombok 是一个 Java 库&#xff0c;通过注解的方式在编译时自动为类生成 getter、setter、equals、hashCode 等方法&#xff0c;以简化代码和提高开发效率。本文主要谈谈代码简化背后的代价。 引入Lombok之前是怎么做的 IDE中添加getter/setter, toString等代码&#xff1a; …