51单片机快速入门之 LCD1602 液晶显示屏2024/10/19

news2024/10/23 12:24:11

51单片机快速入门之 LCD1602 液晶显示屏

Proteus 电路图 :

74HC595 拓展电路可以不用,给 p0-p17 添加上拉电阻也可以!,我这里是方便读取和节省电阻线路

(因为之前不知道 在没有明确循环的情况下,Keil编译器可能会在main()中自动添加类似以下的汇编代码:jump main ; 跳转到main函数的开始处) 所以显示效果就成了 输入   删除   输入  删除

期间各种排查,所以后面的电路图有所更改 

指令集 :

代码实现: 

#include <STC89C5xRC.H>
//定义接口
#define sbp P1
sbit RS=P2^0;
sbit RW=P2^1;
sbit E=P2^2;



void delay(unsigned int t)  ;//声明
void LCD1602(unsigned char RSA,unsigned char RWA,unsigned char date) ;//声明
void LCD1602RED(unsigned char RSB,unsigned char RWB);  //声明


void main()
{

    LCD1602(0,0,0x01);//清屏指令
	
    LCD1602(0,0,0x0e);//打开显示 光标不闪烁

	  LCD1602(0,0,0x30);//设置8位使用
														
    LCD1602(1,0,0x30);//写入0  
	while(1); //防止keil 添加的自动跳回起点导致无限循环执行main函数
		


}





void LCD1602(unsigned char RSA,unsigned char RWA,unsigned char date)    //1602写入操作

{
		
    RS=RSA;        //传递寄存器选择
    RW=RWA;        //传递读写选择
    E=1;          //允许读取    1602
			
    sbp=date;
			delay(200);
    E=0;          //拉低使能控制 下降沿允许写入!      1602
	

}
void LCD1602RED(unsigned char RSB,unsigned char RWB)     //读取操作
{
    unsigned char reddat;//声明一个中间变量
    E=1;//允许读取
    reddat=P0;//获取 P0端口信息


}

void delay(unsigned int t)      //简单延迟函数
{
    while(t--);

}

在Keil等嵌入式开发环境中,如果你没有在main函数中明确地包含一个无限循环(如while(1)),编译器可能会自动在main函数的末尾添加代码,以确保程序不会意外退出。

这种自动添加的代码通常是一个跳转指令,它会跳回到main函数的开始处,从而形成一个隐式的无限循环。这样做是为了确保单片机程序能够持续运行,因为单片机通常不需要像桌面应用程序那样有一个明确的退出过程。相反,它们需要不断地执行其预定的任务,直到被外部事件(如复位按钮)终止。

效果展示:

显示16个字符代码:

#include <STC89C5xRC.H>
//定义接口
#define sbp P1
sbit RS=P2^0;
sbit RW=P2^1;
sbit E=P2^2;



void delay(unsigned int t)  ;//声明
void LCD1602(unsigned char RSA,unsigned char RWA,unsigned char date) ;//声明
void LCD1602RED(unsigned char RSB,unsigned char RWB);  //声明


void main()
{
		unsigned char y;   //声明一个变量
    LCD1602(0,0,0x01);//清屏指令
	
    LCD1602(0,0,0x0e);//打开显示 光标不闪烁

	  LCD1602(0,0,0x30);//设置8位使用
	
		for(y=0;y<16;y++){												
    LCD1602(1,0,0x30);//写入0  
																 }
	while(1);
		


}





void LCD1602(unsigned char RSA,unsigned char RWA,unsigned char date)    //1602写入操作

{
		
    RS=RSA;        //传递寄存器选择
    RW=RWA;        //传递读写选择
    E=1;          //允许读取    1602
			
    sbp=date;
			delay(200);
    E=0;          //拉低使能控制 下降沿允许写入!      1602
	

}
void LCD1602RED(unsigned char RSB,unsigned char RWB)     //读取操作
{
    unsigned char reddat;//声明一个中间变量
    E=1;//允许读取
    reddat=P0;//获取 P0端口信息


}

void delay(unsigned int t)      //简单延迟函数
{
    while(t--);

}

显示效果:

 显示中文:

        因为1602中一般不会储存中文字库,所以我们得自己建立.

首先我们知道其有两种点阵模式 也就是说 2行16列 (16字符) 还可以向下细分为 5x7点阵/字符 或者 5x10 点阵/字符 这意味着每个字符占据5列宽和7行高的空间 

首先我们用操作单个字符 以王字为例(这里要用到1602的CGRAM:自定义字符)

1602液晶模块中的CGRAM(Character Generator RAM)是用户可以自定义的字符图形存储区。它允许用户创建和存储自定义的字符图案,从而在液晶屏幕上显示独特的字符或图形。
CGRAM的基本概念
  1. 存储容量:CGRAM通常有8个字节的存储空间,每个字节可以存储一个自定义字符的点阵图案。
  2. 地址范围:CGRAM的地址范围通常是0x40到0x47,对应于8个自定义字符的存储位置。

 

由上图结合数据手册和下方点位图可知 :

列为 4 3 2 1 0

行为(注意该图只是第一个字符00H 的  | 第二个字符01H 的第一行 0x48 )

 数据手册中明确指出我们可自定义 8 个 字符  00H-07H 或者 08H-0FH (00H==08H)

所以我们想要显示王这个字应该如下

              4  3  2   1 0

0x40 行 1   1  1  1  1

0x41 行 0   0  1 0  0

0x42 行 0   0  1 0  0

0x43 行 1   1  1  1  1

0x44 行 0   0  1 0  0

0x45 行 0   0  1 0  0

0x46 行 1   1  1  1  1

0x47 行  有光标时:   光标会占用这一行!

代码如下 :

可以用循环简化,为了更直观,便于理解这里没有用循环! 

#include <STC89C5xRC.H>
//定义接口
#define sbp P1
sbit RS=P2^0;
sbit RW=P2^1;
sbit E=P2^2;



void delay(unsigned int t)  ;//声明
void LCD1602(unsigned char RSA,unsigned char RWA,unsigned char date) ;//声明
void LCD1602RED(unsigned char RSB,unsigned char RWB);  //声明


void main()
{
		unsigned char y;   //声明一个变量
    LCD1602(0,0,0x01);//清屏指令
    LCD1602(0,0,0x0e);//打开显示 光标不闪烁
	  LCD1602(0,0,0x30);//设置8位使用
	
	  LCD1602(0,0,0x40);//选中 自定义字符 00H 第一行
		LCD1602(1,0,0x1f);//存入第一行数据     0001 1111
	
	  LCD1602(0,0,0x41);//选中 自定义字符 00H 第二行
		LCD1602(1,0,0x04);//存入第二行数据     0000 0100
	
	  LCD1602(0,0,0x42);//选中 自定义字符 00H 第三行
		LCD1602(1,0,0x04);//存入第三行数据     0000 0100
	
	  LCD1602(0,0,0x43);//选中 自定义字符 00H 第四行
		LCD1602(1,0,0x1f);//存入第四行数据     0001 1111
	
    LCD1602(0,0,0x44);//选中 自定义字符 00H 第五行
		LCD1602(1,0,0x04);//存入第五行数据     0000 0100
	
	  LCD1602(0,0,0x45);//选中 自定义字符 00H 第六行
		LCD1602(1,0,0x04);//存入第六行数据     0000 0100
		
	  LCD1602(0,0,0x46);//选中 自定义字符 00H 第七行
		LCD1602(1,0,0x1f);//存入第七行数据     0001 1111
		
		
	  LCD1602(0,0,0x80);  //设置显示在那个字符 DDRAM 一行显示时范围为  00H-4FH
		LCD1602(1,0,0x00);    //显示自定义字符!
		
		
	
	
	while(1);
		


}





void LCD1602(unsigned char RSA,unsigned char RWA,unsigned char date)    //1602写入操作

{
		
    RS=RSA;        //传递寄存器选择
    RW=RWA;        //传递读写选择
    E=1;          //允许读取    1602
			
    sbp=date;
			delay(200);
    E=0;          //拉低使能控制 下降沿允许写入!      1602
	

}
void LCD1602RED(unsigned char RSB,unsigned char RWB)     //读取操作
{
    unsigned char reddat;//声明一个中间变量
    E=1;//允许读取
    reddat=P0;//获取 P0端口信息


}

void delay(unsigned int t)      //简单延迟函数
{
    while(t--);

}

显示效果:

1602的忙碌状态 :

可以称呼其为  锁 

但是需要硬件支持,也就是说 得 8个io 对应单片机 8个引脚 直接链接

其原理为(读取模式下,判断最高位否为0)

首先设置  单片机 所有 io为 高电平 ,初始化!

P1=1;

然后进入读取操作

RS=0;

RW=1; //选择读!

E=0;

delay(100);

E=1; //读取状态

此时 如果 其忙,不能接受数据   p1.7-p1.0顺序  当p1.7 为 还是为高电平 1

  表示1602 很忙 不干其他活  不接受任何外部指令和数据!

当p1.7为 0时 表示其不忙       无论是读还是写都可以!

懒人必备之字符串输出:

原理:

void LCDDD(unsigned char *strr) 是一个函数,它接受一个指向无符号字符的指针 strr 作为参数。这个函数的作用是在LCD1602显示屏上显示一个字符串。

  1. while(*strr) 是一个循环,它会一直执行直到指针 strr 所指向的字符为空字符('\0')通常是C语言字符串的结束标志。

  2. strr++; 将指针 strr 向前移动一个字符,指向下一个字符。可以理解为“往右移动”,因为它意味着指针从当前位置向字符串或数组的尾部方向移动。

这里要说一下 DDRAM 

1602的DDRAM(Display Data RAM)是显示数据随机存储器的简称,常应用于LCD1602等字符设备中。DDRAM是一个80字节的RAM,能够最多存储80个8位字符代码作为显示数据,对应于显示屏上的各个位置。在LCD1602中,第一行的地址为00H到27H,第二行为40H到67H。 

 比方说我们要在00H显示  这里先设置

RS=0 RW=0 E=1   发送设置     延时   E=0

00H 0000 0000 但是这里设置DDRAM最高位固定是一

所以 是 1000 0000  0x80 为第一行第一个字符

同理第二行第一个是 40 0100 0000 因固定位  所以 是1100 0000 0xc0

代码实现:

#include <STC89C5xRC.H>
//定义接口
#define sbp P1
sbit RS=P2^0;
sbit RW=P2^1;
sbit E=P2^2;



void delay(unsigned int t)  ;//声明
void LCD1602(unsigned char RSA,unsigned char RWA,unsigned char date) ;//声明
void LCD1602RED(unsigned char RSB,unsigned char RWB);  //声明
unsigned char y=0;   //声明一个变量

void LCDDD(unsigned char *strr);   //声明
void main()
{

    LCD1602(0,0,0x01);//清屏指令
    LCD1602(0,0,0x0e);//打开显示 光标不闪烁
	LCD1602(0,0,0x38);//设置8位使用   这里要为设置显示为2行
    LCDDD("abcdefghigklmn0123456789");








    while(1);



}

void LCDDD(unsigned char *strr)
{
    while(*strr) {
        LCD1602(1,0,*strr);  //写入当前位置字符
        strr++;                              //往右移动
        y++;                                       //字符检测当字符超出时执行换行
        if(y==16) {
            LCD1602(0,0,0xC0) ;//切换到第二行
        }
    }

}




void LCD1602(unsigned char RSA,unsigned char RWA,unsigned char date)    //1602写入操作

{

    RS=RSA;        //传递寄存器选择
    RW=RWA;        //传递读写选择
    E=1;          //允许读取    1602

    sbp=date;
    delay(200);
    E=0;          //拉低使能控制 下降沿允许写入!      1602


}


void delay(unsigned int t)      //简单延迟函数
{
    while(t--);

}

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

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

相关文章

手机淘宝自动下单退货自动化RPA脚本机器人

使用手机集线器连接多个手机并发运行。 脚本分3个部分&#xff08;读取本地连接下单&#xff0c;退货获取退货地址信息&#xff0c;填写快递单号&#xff09; 脚本部分图结构看下面的图片 部分数据统计展示

ORACLE SELECT INTO 赋值为空,抛出 NO DATA FOUND 异常

例子&#xff1a; DECLARE ORDER_NUM VARCHAR2(20); BEGIN SELECT S.ORDER_NUM INTO ORDER_NUM FROM SALES_ORDER S WHERE S.ID122344; DBMS_OUTPUT.PUT_LINE(单号: || ORDER_NUM); END; 在查询结果为空的情况下&#xff0c;以上代码会报错&#xff1a;未找到任何数据 解决方…

1024程序员节探讨<程序员的人生观和价值观>

程序员的人生观和价值观 程序员的人生观和价值观往往受到其职业特性和工作环境的影响&#xff0c;但也会因个体差异而有所不同。 人生观 持续学习与成长&#xff1a; 程序员通常认识到技术的快速发展&#xff0c;因此他们倾向于保持一种持续学习和自我提升的态度。他们可能将…

全网最详细图文测评!Stability.AI 发布 SD3.5 Large 模型,能否逆风翻盘超越FLUX?

原文链接&#xff1a;全网最详细图文测评&#xff01;Stability.AI 发布 SD3.5 Large 模型&#xff0c;能否逆风翻盘超越FLUX&#xff1f; (chinaz.com) SD3.5 的前世今生 6 月的时候&#xff0c;Stability AI发布了 Stable Diffusion 3 Medium&#xff0c;但是在在 FLUX 发布…

FPGA学习(7)-线性序列机原理与应用,不同类型的LED控制开关

目录 1.实现1 2.实现2 2.1方法1 2.2方法2 3.实现3 3.1实验现象 4.实现4 4.1分析 4.2实现过程 4.2.1 counter的计数 4.2.2 en_counter2的判断 4.2.3 en_counter0的判断 4.2.4 对case语句加判断条件 4.3仿真结果 ​编辑 4.4实验现象 1.实现1 1.实现以下图示功能…

qt QBuffer详解

QBuffer 是 Qt 提供的一个类&#xff0c;用于在内存中操作二进制数据。它是 QIODevice 的一个子类&#xff0c;允许你将数据读入和写出到一个内存缓冲区&#xff0c;而不需要与文件系统交互。 常用方法 构造函数: QBuffer(QObject *parent nullptr): 创建一个空的 QBuffer 对象…

vue项目启动报错:exit status 1

vue项目启动报错&#xff1a;&#xff08;vite构建&#xff09; npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! Exit status 1 如下图所示&#xff1a; 解决 检查node版本&#xff0c;Vite 需要 Node.js 版本 18 或 20 我之前是 14.16.1&#xff0c;更换成 20.0.0 就可…

Flink 06 聚合操作入门学习,真不难

抛砖引玉 让你统计1小时内每种商品的销售额&#xff0c;用Flink 该怎么实现。 还是让你统计1小时内每种商品的销售额&#xff0c;但是要过滤掉退款的订单&#xff0c;用Flink 该怎么实现。 学了本文两个操作&#xff0c;不信你还不会。 AggregateFunction ❝ 通常用于对数据…

【决策树】- 二分法处理连续值

二分法处理连续值 在决策树算法中&#xff0c;处理连续特征通常采用二分法&#xff0c;将其转化为离散特征。此方法通过寻找最佳分割点&#xff0c;将连续特征划分为两个区间。 1. 原理 二分法的核心思想是将连续值特征转换为离散值&#xff0c;以便于决策树的构建。通过选择…

[Linux#67][IP] 报头详解 | 网络划分 | CIDR无类别 | DHCP动态分配 | NAT转发 | 路由器

目录 一. IP协议头格式 学习任何协议前的两个关键问题 IP 报头与有效载荷分离 分离方法 为什么需要16位总长度 如何交付 二. 网络通信 1.IP地址的划分理念 2. 子网管理 3.网络划分 CIDR&#xff08;无类别域间路由&#xff09; 目的IP & 当前路由器的子网掩码 …

R语言机器学习算法实战系列(九)决策树分类算法 (Decision Trees Classifier)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍教程下载数据加载R包导入数据数据预处理数据描述数据切割调节参数构建模型模型的决策树预测测试数据评估模型模型准确性混淆矩阵模型评估指标ROC CurvePRC Curve特征的重要性保存模…

TCP协议四次挥手

1.第一次挥手&#xff1a;客户端发送FIN报文&#xff0c;请求断开连接。这一过程为主动关闭。客户端由ESTABLISHED转换为FIN-WAIT-1。 FIN和ACK置为1&#xff0c;表示这是一个请求结束报文。seqU表示在之前客户端已经发送的字节数。ackV则表示服务端向客户端发送确认消息累计的…

磁盘分区工具 DiskGenius Pro v5.5.0.1488 中文汉化版

DiskGenius 是一款专家级数据恢复软件&#xff0c;集数据恢复、硬盘分区、系统备份还原等多种功能于一身的超级工具软件&#xff0c;功能全面&#xff0c;安全可靠。可以提供磁盘的数据找回、备份、分区、修复、删除、格式化等操作&#xff0c;也能帮助用户修复磁盘坏道、彻底删…

从零构建大模型训练流程及原理(一)

这是一个大模型训练的系列文章&#xff0c;将从零开始手把手带大家构建大模型训练全流程。话不多说&#xff0c;开始发车~什么是大语言模型 1. LLMs是什么&#xff1f; 大型语言模型&#xff08;LLMs&#xff09;是基于Transformer架构的深度学习模型&#xff0c;旨在理解、生…

[枚举坤坤]二进制枚举基础

我们都知道数据是以二进制形式存储在计算机中的。当我们使用十进制数进行编程时&#xff08;如a10&#xff09;实际上计算机要先进行一步转码&#xff0c;将其化为二进制的形式进行计算。如果在编程的过程中我们可以直接越过转码这一步去操纵二进制形式进行运算&#xff0c;程序…

EMNLP 2024 个性化/风格化 文本生成 论文汇总(19篇主会论文)

引言&#xff1a;调研&#xff0c;搬砖… &#x1f60a; &#x1f318;&#x1f317;&#x1f316; &#x1f607; ✅ 笔者简介&#xff1a;Wang Linyong&#xff0c;NPU&#xff0c;2023级&#xff0c;计算机技术 研究方向&#xff1a;文本生成、大语言模型 文章目录 1 Perso…

【C++】STL----map和set

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;C从小白到高手 &#x1f339;往期回顾&#x1f339;&#xff1a;[C]二叉搜索树 &#x1f516; 流水不争&#xff0c;争的是滔滔不息 文章目录 一、set和map的简介setm…

Java设计模式梳理:行为型模式(策略,观察者等)

行为型模式 行为型模式关注的是各个类之间的相互作用&#xff0c;将职责划分清楚&#xff0c;使得我们的代码更加地清晰。 策略模式 策略模式太常用了&#xff0c;所以把它放到最前面进行介绍。它比较简单&#xff0c;我就不废话&#xff0c;直接用代码说事吧。 下面设计的…

某ai gpt的bug

某ai gpt的bug 背景 遇到了一个奇怪的现象&#xff1a; 输入内容 2024-10-21 10:09:31,052 ERROR o.a.j.t.JMeterThread: Test failed! java.lang.IllegalArgumentException:输出结果

Android开发教程二维码扫描功能

Android开发教程二维码扫描功能 二维码扫描大一点的app都有的功能&#xff0c;因为扫一下真的很方便 一、思路&#xff1a; 用zxing库 二、效果图&#xff1a; 看视频更加直观点&#xff1a; Android开发教程实战案例源码分享-二维码扫描功能 三、关键代码&#xff1a; c…