嵌入式开发学习(STC51-18-LCD液晶显示)

内容

在LCD1602液晶上显示字符信息;

LCD1602介绍

简介

1602液晶也叫1602字符型液晶,它能显示2行字符信息,每行又能显示16个字符;

它是一种专门用来显示字母、数字、符号的点阵型液晶模块;

它是由若干个5x7或者5x10的点阵字符位组成,每个点阵字符位都可以用显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此,所以它不能很好的显示图片;

管脚说明

LCD1602有16个管脚孔,从左至右管脚编号顺序是1-16

其功能定义如下所示:
在这里插入图片描述
部分管脚说明:

  • 3脚:VL,液晶显示偏压信号,用于调整LCD1602的显示对比度,一般会外接电位器用以调整偏压信号,注意此脚电压为0时可以得到最强的对比度;
  • 4脚:RS,数据/命令选择端,当此脚为高电平时,可以对1602进行数据字节的传输操作;而低电平时,则是进行命令字节的传输操作;命令字节,即是用来对LCD1602的一些工作方式作设置的字节;数据字节,即使用以在1602上显示的字节;LCD1602的数据是8位的;
  • 5脚:R/W,读写选择端;当此脚为高电平可对LCD1602进行读数据操作,反之进行写数据操作;
  • 6脚:E,使能信号,其实是LCD1602的数据控制时钟信号,利用该信号的上升沿实现对LCD1602的数据传输;
  • 7~14脚:8位并行数据口,而51单片机一组IO也是8位,使得对LCD1602的数据读写大为方便;

DDRAM说明

在LCD1602内部含有80个字节的DDRAM,它是用来寄存显示字符的;

其地址和屏幕的对应关系如下表:
在这里插入图片描述
在这里插入图片描述
从上图可知,不是所有的地址都可以直接用来显示字符数据,只有第一行中的00-0F,第二行中的40-4F才能显示,其他地址只能用于存储;

要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,而且写入显示地址时要求最高位D7恒定为高电平1,例如第二行第一个字符的地址是40H,所以要写入的数据应该是01000000B(40H)+10000000B(80H)=11000000B(C0H);

在1602中我们只用前16个地址就行了,第二行也一样用前16个地址;

常用指令

在使用LCD1602时,我们需要掌握一些常用的指令,这些指令对于LCD1602初始化是必须的;

清屏指令

在这里插入图片描述

  • 清除液晶显示器,即将DDRAM的内容全部填入"空白"的ASCII码20H;
  • 光标归位,即将光标撤回液晶显示屏的左上方;
  • 将地址计数器(AC)的值设为0;

模式设置指令

在这里插入图片描述

  • 设定每次写入1位数据后光标的移位方向,并且设定每次写入的一个字符是否移动;
  • I/D:0 = 写入新数据后光标左移;1 = 写入新数据后光标右移;
  • S:0 = 写入新数据后显示屏不移动;1 = 写入新数据后显示屏整体右移1个字符;

显示开关控制指令

在这里插入图片描述

  • 控制显示器开/关、光标显示/关闭以及光标是否闪烁;
  • D:0 = 显示功能关;1 = 显示功能开;
  • C:0 = 无光标;1 = 有光标;
  • B:0 = 光标闪烁;1 = 光标不闪烁;

功能设定指令

在这里插入图片描述

  • 设定数据总线位数、显示的行数及字型;
  • DL:0 = 数据总线为4位;1 = 数据总线为8位;
  • N:0 = 显示1行;1 = 显示2行;
  • F:0 = 5×7点阵/每字符;1 = 5×10点阵/每字符;

使用方法

要使用LCD1602,首先需要对其初始化,即通过写入一些特定的指令实现;

然后选择要在LCD1602的哪个位置显示并将所要显示的数据发送到LCD的DDRAM;

使用LCD1602通常都是用于写数据进去,很少使用读功能;

LCD1602操作步骤如下所示:

1 初始化
2 写命令(RS=L),设置显示坐标
3 写数据(RS=H)

工作时序

LCD1602一般不需要读出它的数据的状态或者数据本身;

所以只需要看两个写时序:

  • 当要写指令字,设置LCD1602的工作方式时:把RS置为低电平,RW置为低电平,然后将数据送到数据口D0~D7,最后E引脚一个高脉冲将数据写入;
  • 当要写入数据字,在LCD1602上实现显示时:把RS置为高电平,RW置为低电平,然后将数据送到数据口D0~D7,最后E引脚一个高脉冲将数据写入;
  • 写指令和写数据,差别仅仅在于 RS 的电平不一样而已;

LCD1602时序图:
在这里插入图片描述
在这里插入图片描述
从上图可以看到,以上给的时间参数全部是ns级别的,而51单片机的机器周期是1us,指令周期是2-4个机器周期,所以即便在程序里不加延时程序,也可以很好的配合LCD1602的时序要求;

当要写命令字节的时候,时间由左往右,RS变为低电平,R/W变为低电平,注意看是RS的状态先变化完成;

然后这时,DB0~DB7上数据进入有效阶段,接着E引脚有一个整脉冲的跳变,接着要维持时间最小值为tpw=400ns的E脉冲宽度;

然后E引脚负跳变,RS电平变化,R/W电平变化,这样便是一个完整的LCD1602写命令的时序;

注意:这里介绍的是8位LCD1602,现在某些公司为简化引脚数,使用4位LCD1602;使用4位LCD1602时,应该多看手册,找到不同点,对原有程序加以修改;

原理图

在这里插入图片描述
在这里插入图片描述
从线路图中可知,LCD1602的8位数据口D0-D7与单片机的P0.0-P0.7管脚连接,LCD1602的RS、WR、E脚与单片机的P2.6、P2.5、P2.7管脚连接;

RJ1是一个电位器,用来调节LCD1602对比度即显示亮度;

思路

根据lcd1602的写指令和数据的时序编写相应程序;

根据lcd1602的指令格式,编写必要的初始化、清屏和显示程序;

编码

User

main.c

/*
 * @Description: 使LCD1602上显示字符信息
 */
#include "public.h"
#include "lcd1602.h"

void main()
{
	lcd1602_init();							   // LCD1602初始化
	lcd1602_show_string(0, 0, "Hello World!"); // 第一行显示
	lcd1602_show_string(0, 1, "0123456789");   // 第二行显示
	while (1)
	{
	}
}

Public

public.h

#ifndef _public_H
#define _public_H

#include "reg52.h"

typedef unsigned int u16; // 对系统默认数据类型进行重定义
typedef unsigned char u8;

void delay_10us(u16 ten_us);
void delay_ms(u16 ms);

#endif

public.c

#include "public.h"

/**
 * @description: 延时函数,ten_us=1时,大约延时10us
 * @param {u16} ten_us 延时倍数
 * @return {*}
 */
void delay_10us(u16 ten_us)
{
	while (ten_us--)
		;
}

/**ms延时函数,ms=1时,大约延时1ms***
 * @param {u16} ms 延时倍数
 * @return {*}
 */
void delay_ms(u16 ms)
{
	u16 i, j;
	for (i = ms; i > 0; i--)
		for (j = 110; j > 0; j--)
			;
}

App/lcd1602

lcd1602.h

#ifndef _lcd1602_H
#define _lcd1602_H

#include "public.h"

// LCD1602数据口4位和8位定义,若为1,则为LCD1602四位数据口驱动,反之为8位
#define LCD1602_4OR8_DATA_INTERFACE 0 // 默认使用8位数据口LCD1602

// 管脚定义
sbit LCD1602_RS = P2 ^ 6;	// 数据命令选择
sbit LCD1602_RW = P2 ^ 5;	// 读写选择
sbit LCD1602_E = P2 ^ 7;	// 使能信号
#define LCD1602_DATAPORT P0 // 宏定义LCD1602数据端口

// 函数声明
void lcd1602_init(void);
void lcd1602_clear(void);
void lcd1602_show_string(u8 x, u8 y, u8 *str);

#endif

lcd1602.c

#include "lcd1602.h"

#if (LCD1602_4OR8_DATA_INTERFACE == 0) // 8位LCD
/**
 * @description: LCD1602写命令
 * @param {u8} cmd 指令
 * @return {*}
 */
void lcd1602_write_cmd(u8 cmd)
{
	LCD1602_RS = 0; // 选择命令
	LCD1602_RW = 0; // 选择写
	LCD1602_E = 0;
	LCD1602_DATAPORT = cmd; // 准备命令
	delay_ms(1);
	LCD1602_E = 1; // 使能脚E先上升沿写入
	delay_ms(1);
	LCD1602_E = 0; // 使能脚E后负跳变完成写入
}
#else // 4位LCD
void lcd1602_write_cmd(u8 cmd)
{
	LCD1602_RS = 0; // 选择命令
	LCD1602_RW = 0; // 选择写
	LCD1602_E = 0;
	LCD1602_DATAPORT = cmd; // 准备命令
	delay_ms(1);
	LCD1602_E = 1; // 使能脚E先上升沿写入
	delay_ms(1);
	LCD1602_E = 0; // 使能脚E后负跳变完成写入

	LCD1602_DATAPORT = cmd << 4; // 准备命令
	delay_ms(1);
	LCD1602_E = 1; // 使能脚E先上升沿写入
	delay_ms(1);
	LCD1602_E = 0; // 使能脚E后负跳变完成写入
}
#endif

#if (LCD1602_4OR8_DATA_INTERFACE == 0) // 8位LCD
/**
 * @description: LCD1602写数据
 * @param {u8} dat 数据
 * @return {*}
 */
void lcd1602_write_data(u8 dat)
{
	LCD1602_RS = 1; // 选择数据
	LCD1602_RW = 0; // 选择写
	LCD1602_E = 0;
	LCD1602_DATAPORT = dat; // 准备数据
	delay_ms(1);
	LCD1602_E = 1; // 使能脚E先上升沿写入
	delay_ms(1);
	LCD1602_E = 0; // 使能脚E后负跳变完成写入
}
#else
void lcd1602_write_data(u8 dat)
{
	LCD1602_RS = 1; // 选择数据
	LCD1602_RW = 0; // 选择写
	LCD1602_E = 0;
	LCD1602_DATAPORT = dat; // 准备数据
	delay_ms(1);
	LCD1602_E = 1; // 使能脚E先上升沿写入
	delay_ms(1);
	LCD1602_E = 0; // 使能脚E后负跳变完成写入

	LCD1602_DATAPORT = dat << 4; // 准备数据
	delay_ms(1);
	LCD1602_E = 1; // 使能脚E先上升沿写入
	delay_ms(1);
	LCD1602_E = 0; // 使能脚E后负跳变完成写入
}
#endif

#if (LCD1602_4OR8_DATA_INTERFACE == 0) // 8位LCD
/**
 * @description: LCD1602初始化
 * @return {*}
 */
void lcd1602_init(void)
{
	lcd1602_write_cmd(0x38); // 数据总线8位,显示2行,5*7点阵/字符
	lcd1602_write_cmd(0x0c); // 显示功能开,无光标,光标闪烁
	lcd1602_write_cmd(0x06); // 写入新数据后光标右移,显示屏不移动
	lcd1602_write_cmd(0x01); // 清屏
}
#else
void lcd1602_init(void)
{
	lcd1602_write_cmd(0x28); // 数据总线4位,显示2行,5*7点阵/字符
	lcd1602_write_cmd(0x0c); // 显示功能开,无光标,光标闪烁
	lcd1602_write_cmd(0x06); // 写入新数据后光标右移,显示屏不移动
	lcd1602_write_cmd(0x01); // 清屏
}
#endif

/**
 * @description: LCD1602清屏
 * @return {*}
 */
void lcd1602_clear(void)
{
	lcd1602_write_cmd(0x01);
}

/**
 * @description: LCD1602显示字符
 * @param {u8} x 坐标
 * @param {u8} y 坐标
 * @param {u8} *str 要显示的字符串
 * @return {*}
 */
void lcd1602_show_string(u8 x, u8 y, u8 *str)
{
	u8 i = 0;

	if (y > 1 || x > 15)
		return; // 行列参数不对则强制退出

	if (y < 1) // 第1行显示
	{
		while (*str != '\0') // 字符串是以'\0'结尾,只要前面有内容就显示
		{
			if (i < 16 - x) // 如果字符长度超过第一行显示范围,则在第二行继续显示
			{
				lcd1602_write_cmd(0x80 + i + x); // 第一行显示地址设置
			}
			else
			{
				lcd1602_write_cmd(0x40 + 0x80 + i + x - 16); // 第二行显示地址设置
			}
			lcd1602_write_data(*str); // 显示内容
			str++;					  // 指针递增
			i++;
		}
	}
	else // 第2行显示
	{
		while (*str != '\0')
		{
			if (i < 16 - x) // 如果字符长度超过第二行显示范围,则在第一行继续显示
			{
				lcd1602_write_cmd(0x80 + 0x40 + i + x);
			}
			else
			{
				lcd1602_write_cmd(0x80 + i + x - 16);
			}
			lcd1602_write_data(*str);
			str++;
			i++;
		}
	}
}

编译和结果

按F7编译,无错误,生成.hex文件,使用pz-isp将hex文件下载到单片机

结果:lcd液晶屏上正确显示内容;
在这里插入图片描述

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

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

相关文章

嵌入式学习之震动喇叭项目

震动喇叭项目所用到的元器件有振动传感器模块、继电器模块、高功率喇叭、433M无线发射接收模块&#xff0c;通过这些模块&#xff0c;能够实现做出一个智能报警系统的项目出来&#xff0c;非常的有趣&#xff0c;特别是喇叭声音想起来&#xff0c;那个声音挺大的。 继电器的学…

【Java从0到1学习】06 Java 面向对象

1. 面向对象思想 面向对象是一种符合人类思维习惯的编程思想。现实生活中存在各种形态不同的事物&#xff0c;这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物&#xff0c;使用对象的关系来描述事物之间的联系&#xff0c;这种思想就是面向对象。 提到…

RocketMQ 主备自动切换模式部署

目录 主备自动切换模式部署 Controller 部署​ Controller 嵌入 NameServer 部署​ Controller 独立部署​ Broker 部署​ 兼容性​ 升级注意事项​ 主备自动切换模式部署 该文档主要介绍如何部署支持自动主从切换的 RocketMQ 集群&#xff0c;其架构如上图所示&#xff…

Spring Boot数据访问基础知识与JDBC简单实现

目录 Spring Boot数据访问基础知识 Spring Data ORM JDBC JPA JDBC简单实现 步骤1&#xff1a;新建Maven项目&#xff0c;添加依赖 步骤2&#xff1a;配置数据源—让程序可以访问到 步骤3&#xff1a;配置数据源—让IDEA可以访问到 步骤4&#xff1a;添加数据库和表 …

【网络编程·传输层】UDP和TCP的报头

目录 一、端口号划分 二、部分指令 1、pidof&#xff08;用于查看进程id&#xff09; 2、netstat&#xff08;查看网络状态&#xff09; 三、UDP协议 1、UDP协议格式 2、UDP协议如何进行封装、解包、分用 2.1封装、解包 2.2分用 3、UDP协议的特点 3.1UDP协议的特点 …

CMake 3.13.4 or higher is required. You are running version 3.10.2

ubuntu 安装 cmake&#xff0c;但是apt安装的版本太低&#xff0c;需要其他安装方法。 参考视频 https://www.youtube.com/watch?v_yFPO1ofyF0 以下是对视频内容的提炼&#xff0c;就两点 1、下载需要版本的sh文件&#xff1b;2、安装 一、下载需要版本的sh文件 https://cma…

什么是GCC

GCC&#xff08;GNU Compiler Collection&#xff0c;GNU编译器套件&#xff09;是由 GNU 开发的编程语言译器。GNU 编译器套件包括 C、C、Objective-C、Java、Ada 和 Go 语言前端&#xff0c;也包括了这些语言的库&#xff08;如 libstdc&#xff0c;libgcj等&#xff09; GC…

【gavh39芯片用什么代替-AH8652】

问&#xff1a;gavh39芯片用什么代替&#xff1f; 答&#xff1a;gavh39是一颗用于交流220v转5v输出的芯片&#xff0c;它的拼对拼代替型号为AH8652 AH8652是一款非隔离电源管理芯片&#xff0c;它用于将交流电压转换为直流电压输出。可以将输入的220V交流电转换为输出的5V直流…

MySQL存储过程(二十四)

你相信吗&#xff0c; 相信那一天的夕阳吗? 上一章简单介绍了 MySQL的索引(二十三),如果没有看过,请观看上一章 一. 存储过程 MySQL从5.0版本开始支持存储过程和函数。存储过程和函数能够将复杂的SQL逻辑封装在一起&#xff0c; 应用程序无须关注存储过程和函数内部复杂的S…

积累常见的有针对性的python面试题---python面试题001

1.考点列表的.remove方法的参数是传入的对应的元素的值,而不是下标 然后再看remove这里,注意这个是,删除写的那个值,比如这里写3,就是删除3, 而不是下标. remove不是下标删除,而是内容删除. 2.元组操作,元组不支持修改,某个下标的内容 可以问他如何修改元组的某个元素 3.…

将整数,结构体,结构体数组,链表写到文件

在之前的学习中&#xff0c;忘文件中写的内容都是字符串或字符&#xff0c;本节学习如何写入其他各种类型的数据。 回看write和read函数的形式&#xff1a; ssize_t write(int fd, const void *buf, size_t count); ssize_t read(int fd, void *buf, size_t count); 其中&a…

计算机图形学一:数学基础

数学基础&#xff08;变换矩阵&#xff0c;向量运算等&#xff09; 1.变换矩阵总结 一切物体&#xff08;包括模型&#xff0c;向量等&#xff09;的缩放&#xff0c;旋转&#xff0c;平移&#xff0c;切变等&#xff0c;都可以通过变换矩阵得到。在投影(projection&#xff…

MyCat垂直分库案例以及全局表概念讲解

这里的分片指的就是分库分表 1.垂直拆分 1.1场景介绍 1.2 数据库准备 1.3MyCat配置 schema.xml: <schema name"shopping" checkSQLschema"true" sqlMaxLimit"100"><table name"tb_goods_base" dataNode"dn1" pr…

Git基础知识:常见功能和命令行

文章目录 1.Git介绍2.安装配置2.1 查看配置信息 3.文件管理3.1 创建仓库3.2 版本回退3.3 工作流程3.4 撤销修改3.5 删除文件 4.远程仓库4.1 连接远程库4.2 本地上传至远程4.3 从远程库克隆到本地 5.分支管理5.1 创建分支5.2 删除分支5.3 合并分支解决冲突 参考&#xff1a; Git…

python与深度学习(十五):CNN和宝可梦模型

目录 1. 说明2. 宝可梦模型2.1 导入相关库2.2 建立模型2.3 模型编译2.4 数据生成器2.5 模型训练2.6 模型保存 3. 宝可梦的CNN模型可视化结果图4. 完整代码5. 宝可梦的迁移学习 1. 说明 本篇文章是CNN的另外一个例子&#xff0c;宝可梦模型&#xff0c;是自制数据集的例子。之前…

b站视频标题的获取(xpath、jsonpath的一个简单应用)

目录 1.目的2.代码的演示 注&#xff1a;该篇文章为本人原创&#xff0c;由于本人学习有限&#xff0c;若有错误或者笔误或者有问题&#xff0c;欢迎大家进行批评指正&#xff0c;谢谢。 1.目的 在b站大学上&#xff0c;为了更好的写笔记&#xff0c;本人根据学到的Python(即Py…

element vue2 动态添加 select+tree

难点在 1 添加一组一组的渲染 是往数组里push对象 循环的&#xff1b;但是要注意对象的结构! 因为这涉及到编辑完成后&#xff0c;表单提交时候的 校验&#xff01; 是校验每一个select tree里边 是否勾选 2 是在后期做编辑回显的时候 保证后端返回的值 是渲染到 select中的tr…

C语言案例 按序输出多个整数-03

难度2复杂度3 题目&#xff1a;输入多个整数&#xff0c;按从小到大的顺序输出 步骤一&#xff1a;定义程序的目标 编写一个C程序&#xff0c;随机输入整数&#xff0c;按照从小到大的顺序输出 步骤二&#xff1a;程序设计 整个C程序由三大模块组成&#xff0c;第一个模块使…

实战项目——多功能电子时钟

一&#xff0c;项目要求 二&#xff0c;理论原理 通过按键来控制状态机的状态&#xff0c;在将状态值传送到各个模块进行驱动&#xff0c;在空闲状态下&#xff0c;数码管显示基础时钟&#xff0c;基础时钟是由7个计数器组合而成&#xff0c;当在ADJUST状态下可以调整时间&…

AlexNet卷积神经网络-笔记

AlexNet卷积神经网络-笔记 AlexNet卷积神经网络2012年提出 测试结果为&#xff1a; 通过运行结果可以发现&#xff0c; 在眼疾筛查数据集iChallenge-PM上使用AlexNet&#xff0c;loss能有效下降&#xff0c; 经过5个epoch的训练&#xff0c;在验证集上的准确率可以达到94%左右…