单片机学习笔记---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.rhkb.cn/news/257796.html

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

相关文章

假期刷题打卡--Day26

1、MT1212乘法表 请编写一个简单程序&#xff0c;输出九九乘法表。输入n&#xff0c;就输出乘法表到n的地方。 格式 输入格式&#xff1a; 输入整型 输出格式&#xff1a; 输出整型。形式如&#xff1a;1*11 样例 1 输入&#xff1a; 5输出&#xff1a; 1*11 2*12 …

2023全球云计算市场份额排名

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 最近Synergy研究院发布了最新的全球云计算市场份额排名。 亚马逊依旧是以31%的的市场份额排名第一&#xff0c;微软azure24%排名第二&#xff0c;Google云11%排名第三&#xff0c;阿里云4%排名第四。腾讯云和IBM、…

java 宠物在线商城系统Myeclipse开发mysql数据库web结构jsp编程servlet计算机网页项目

一、源码特点 java 宠物在线商城系统是一套完善的java web信息管理系统 servletdaobean mvc模式&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S 模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&…

(13)Hive调优——动态分区导致的小文件问题

前言 动态分区指的是&#xff1a;分区的字段值是基于查询结果自动推断出来的&#xff0c;核心语法就是insertselect。 具体内容指路文章&#xff1a; https://blog.csdn.net/SHWAITME/article/details/136111924?spm1001.2014.3001.5501文章浏览阅读483次&#xff0c;点赞15次…

STM32 SPI

目录 软件SPI读写W25Q64 硬件SPI读写W25Q64 CPHA为时钟相位&#xff0c;决定是第几个边沿采样&#xff0c;并不是规定上升沿采样还是下降沿采样(还要看CPOL极性选择)。 W25Q64框图 软件SPI读写W25Q64 MySPI.c #include "stm32f10x.h" // Device…

.NET Core WebAPI中封装Swagger配置

一、创建相关文件 创建一个Utility/SwaggerExt文件夹&#xff0c;添加一个类 二、在Program中找到Swagger相关配置信息 三、添加方法&#xff0c;在Program中调用 在SwaggerExt类中添加方法&#xff0c;将相关配置添写入 /// <summary> /// swagger配置 /// </sum…

软件架构设计--操作系统

常见I/O类型:缓冲I/O和直接I/O 缓冲I/O是C语言提供的库函数 直接I/O是Linux系统API 应用程序内存:代码中用malloc/free,new/delete 等分配出来的内存 用户缓冲区:C语言的FILE结构体里面的bufer. 内核缓冲区:Linux操作系统的Page Cache. 1Page 一般为4K 缓冲I/O的读操作有3次数…

XMall 开源商城 SQL注入漏洞复现(CVE-2024-24112)

0x01 产品简介 XMall 开源电商商城 是开发者Exrick的一款基于SOA架构的分布式电商购物商城 前后端分离 前台商城:Vue全家桶 后台管理:Dubbo/SSM/Elasticsearch/Redis/MySQL/ActiveMQ/Shiro/Zookeeper等。 0x02 漏洞概述 XMall 开源商城 /item/list、/item/listSearch、/sys/…

GPT-4影响高度创新思维的领域(一)

GPT-4的应用范围不再局限于对现有信息的检索、整理和复述&#xff0c;而是进一步拓展到了诸如文学创作、科学假设生成、教育辅导、商业策略建议等需要高度创新思维的领域。这种独立思考和创新能力赋予了GPT-4作为虚拟助手时更加丰富多元的角色定位&#xff0c;使其成为一种强大…

Git简单了解

文章目录 1、Git概述2、Git下载与安装3、Git代码托管服务3.1、使用码云托管服务 1、Git概述 什么是Git Git是一个分布式版本控制工具&#xff0c;主要用于管理开发过程中的源代码文件&#xff08;Java类、xml文件、html页面等&#xff09;&#xff0c;在软件开发过程中被广泛使…

一、ActiveMQ介绍

ActiveMQ介绍 一、JMS1.jms介绍2.jms消息传递模式3.jms编码总体架构 二、消息中间件三、ActiveMQ介绍1.引入的原因1.1 原因1.2 遇到的问题1.3 解决思路 2.定义3.特点3.1 异步处理3.2 应用系统之间解耦3.3 实际-整体架构 4.作用 一、JMS 1.jms介绍 jms是java消息服务接口规范&…

【微服务】skywalking自定义告警规则使用详解

目录 一、前言 二、SkyWalking告警功能介绍 2.1 SkyWalking告警是什么 2.2 为什么需要SkyWalking告警功能 2.2.1 及时发现系统异常 2.2.2 保障和提升系统稳定性 2.2.3 避免数据丢失 2.2.4 提高故障处理效率 三、 SkyWalking告警规则 3.1 SkyWalking告警规则配置 3.2 …

构建智慧交通平台:架构设计与实现

随着城市交通的不断发展和智能化技术的迅速进步&#xff0c;智慧交通平台作为提升城市交通管理效率和水平的重要手段备受关注。本文将探讨如何设计和实现智慧交通平台的系统架构&#xff0c;以应对日益增长的城市交通需求&#xff0c;并提高交通管理的智能化水平。 ### 1. 智慧…

高级数据结构与算法 | 布谷鸟过滤器(Cuckoo Filter):原理、实现、LSM Tree 优化

文章目录 Cuckoo Filter基本介绍布隆过滤器局限变体 布谷鸟哈希布谷鸟过滤器 实现数据结构优化项Victim Cache备用位置计算半排序桶 插入查找删除 应用场景&#xff1a;LSM 优化 Cuckoo Filter 基本介绍 如果对布隆过滤器不太了解&#xff0c;可以看看往期博客&#xff1a;海量…

Netty应用(一) 之 NIO概念 基本编程

目录 第一章 概念引入 1.分布式概念引入 第二章 Netty基础 - NIO 1.引言 1.1 什么是Netty&#xff1f; 1.2 为什么要学习Netty&#xff1f; 2.NIO编程 2.1 传统网络通信中开发方式及问题&#xff08;BIO&#xff09; 2.1.1 多线程版网络编程 2.1.2 线程池版的网络编程…

操作 Docker 存储卷的常用指令汇总

1. 什么是存储卷&#xff1f; 存储卷就是将宿主机的本地文件系统中存在的某个目录直接与容器内部的文件系统上的某一目录建立绑定关系。使得可以在宿主机和容器内共享数据库内容&#xff0c;让容器直接访问宿主机中的内容&#xff0c;也可以宿主机向容器写入内容&#xff0c;容…

元宇宙专题:元宇宙概念娱乐应用场景案例研究报告 - 体验驱动篇

今天分享的是元宇宙系列深度研究报告&#xff1a;《元宇宙专题&#xff1a;元宇宙概念娱乐应用场景案例研究报告 - 体验驱动篇》。 &#xff08;报告出品方&#xff1a;艾瑞咨询&#xff09; 报告共计&#xff1a;51页 避免刻舟求剑地探索元宇宙概念产品 对于任何一个宏大而…

建筑工程如何找答案? #职场发展#笔记#职场发展

这些软件以其强大的搜索引擎和智能化的算法&#xff0c;为广大大学生提供了便捷、高效的解题方式。下面&#xff0c;让我们一起来了解几款备受大学生欢迎的搜题软件吧&#xff01; 1.易解题 这是一个网站 是我在百度搜题&#xff0c;经常会出现的一个网站&#xff0c;它里面…

Ubuntu Desktop - Disks

Ubuntu Desktop - Disks 1. Search your computer -> DisksReferences 1. Search your computer -> Disks ​ References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

Spring Boot 笔记 021 项目部署

1.1 引入坐标&#xff0c;并双击package打包成jar包 1.2 在服务器上运行jar包 1.3 使用postman测试 2.1 运行配置 2.1.1 命令更改端口 java -jar big-event-1.0-SNAPSHOT.jar --server.port7777 2.1.2 环境变量更新&#xff08;略&#xff09; 2.1.3 外部配置文件&#xff0c…