51单片机-LCD1602(液晶显示屏)- 写驱动

news2024/9/20 22:41:35

时间永远是检验真理唯一标准!Whappy!

主要简单写出几个驱动

初始化、显示字符、显示字符串、显示整形数据、有符号数据、十六进制、二进制!

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

介绍
 

LCD1602驱动程序编写

根据时序写出发送指令和发送数据的操作,

首先设置指令(查看指令格式)集存取RS,RS=0,输入指令,1输入数据。再RS=1期间,将R/W设置位写,并打开使能从1 -0,然后数据就会被写入进去。

下面两个函数实现写数据和写指令的操作,接下来我们就要根据相关寄存器发送,对应的指令和数据即可,可参考数据手册。



//RS写指令的驱动
void LCD1602_WriteCommand(unsigned char Command)
{
	LCD_RS = 0; //写入指令
	LCD_WR = 0; //写入数据
	LCD_DataPort = Command; //将指令放到数据总线上,并行端口,Commmand的8位可以直接放上去
	LCD_EN = 1;  //使能1-0,写入数据
	Delay1ms();
	LCD_EN = 0;	
	Delay1ms();
		
}


//RW写数据的驱动
void LCD1602_WriteData(unsigned char Data)
{
	LCD_RS = 1; //写入指令
	LCD_WR = 0; //写入数据
	LCD_DataPort = Data; //将指令放到数据总线上,并行端口,Commmand的8位可以直接放上去
	LCD_EN = 1;  //使能1-0,写入数据
	Delay1ms();
	LCD_EN = 0;	
	Delay1ms();
}

代码写数据写指令已经完成,接下我们就要根据LCD1602的相关寄存器配置进行我们需要的操作,下图表位LCD1602的相关操作配置指令(也是寄存器配置)

具体操作流程如下,对照指令集写的初始化函数和显示字符函数等(通过发送指令和数据函数完成)

(1)对功能指令的寄存器配置为0X38,  发送指令0x38    //八位数据接口,两行显示,5*7点阵

给出功能指令配置,其余指令配置请参考指令集,自行研究,也很容易!

初始化函数编写

//初始化
void LCD1602_Init(void)
{
	LCD1602_WriteCommand(0X38);//八位数据接口,两行显示,5*7点阵
	LCD1602_WriteCommand(0X0C);//显示开,光标关,闪烁关
	LCD1602_WriteCommand(0X06);//数据读写操作后,光标自动加一,画面不动
	LCD1602_WriteCommand(0X01);//光标复位,清屏
	
}


//光标位置
void LCD1602_SetCursor(unsigned char Line, unsigned char Column)
{
	if(Line == 1)
	{
		LCD1602_WriteCommand(0X80 | (Column-1));
		
	}
	else
	{
		LCD1602_WriteCommand(0X80 | (Column-1)+0X40);
	}
}

整体函数

LCD1602.c

#include <REGX52.H>

#include "LCD1602_W.h"


unsigned int LCD_Pow(unsigned char base, unsigned char exponent)
{
    unsigned int result = 1;
    while (exponent--)
    {
        result *= base;
    }
    return result;
}

//初始化
void LCD1602_Init(void)
{
	LCD1602_WriteCommand(0X38);//八位数据接口,两行显示,5*7点阵
	LCD1602_WriteCommand(0X0C);//显示开,光标关,闪烁关
	LCD1602_WriteCommand(0X06);//数据读写操作后,光标自动加一,画面不动
	LCD1602_WriteCommand(0X01);//光标复位,清屏
	
}

/*
行与地址映射
第一行地址起点:通常,LCD 屏幕的第一行的 DDRAM 地址从 0x00 开始。
第二行地址起点:第二行的 DDRAM 地址通常从 0x40 开始。
所以,如果我们想移动光标到显示屏的第一行的第 1 列,就需要发送的命令是 0x80 加上该列的偏移量(即 Column-1)。

解释 0x80 | (Column - 1)
0x80:

0x80 是一个命令位,表示将要设置光标的 DDRAM 地址。LCD 控制器的命令格式中,高位 1 用来表明我们要设置光标。
它是“设置地址”指令的标识符,告诉 LCD 控制器接下来传递的值是 DDRAM 的地址。
Column - 1:

Column 是用户输入的列数,它通常是从 1 开始的。然而,LCD 的内存地址是从 0 开始的(即第 1 列对应地址 0,第 2 列对应地址 1,以此类推)。
所以我们需要将 Column 减去 1,将它转换为从 0 开始的索引值,匹配 DDRAM 地址。
*/
//光标位置
void LCD1602_SetCursor(unsigned char Line, unsigned char Column)
{
	if(Line == 1)
	{
		LCD1602_WriteCommand(0X80 | (Column-1));
		
	}
	else
	{
		LCD1602_WriteCommand(0X80 | (Column-1)+0X40);
	}
}

//显示字符
void LCD1602_ShowChar(unsigned char Line, unsigned char Column,unsigned char Char)
{
	LCD1602_SetCursor(Line,Column); //光标位置
	LCD1602_WriteData(Char); //要显示的字符
}


//显示字符串
void LCD_DisplayString(unsigned char Line, unsigned char Column, char *str)
{
    // 将光标移动到指定的行和列
    LCD1602_SetCursor(Line, Column);
    
    // 循环显示字符串中的每个字符,直到遇到字符串结束符 '\0'
    while(*str != '\0')
    {
        LCD1602_WriteData(*str);// 显示当前字符
        str++;                // 移动到下一个字符
    }
}



// 显示16进制数字
void LCD1602_ShowHexNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length)
{
    unsigned char i;
    unsigned char hexDigit;
    unsigned int divisor = LCD_Pow(16, Length - 1); // 初始除数为16的Length-1次方

    LCD1602_SetCursor(Line,Column);

    for (i = 0; i < Length; i++)
    {
        hexDigit = Number / divisor;          // 获取当前最高位的16进制数字
        Number %= divisor;                    // 计算剩余的数值
        divisor /= 16;                        // 更新除数以处理下一位
        
        if (hexDigit < 10)
        {
            LCD1602_WriteData(hexDigit + '0');    // 数字字符
        }
        else
        {
            LCD1602_WriteData(hexDigit - 10 + 'A'); // 字母字符
        }
    }
}


void LCD1602_ShowBinNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length)
{
    unsigned char i;
    unsigned char hexDigit;
    unsigned int divisor = LCD_Pow(2, Length - 1); // 初始除数为16的Length-1次方

    LCD1602_SetCursor(Line,Column);

    for (i = 0; i < Length; i++)
    {
        hexDigit = Number / divisor;          // 获取当前最高位的16进制数字
        Number %= divisor;                    // 计算剩余的数值
        divisor /= 2;                        // 更新除数以处理下一位
        
        if (hexDigit < 10)
        {
            LCD1602_WriteData(hexDigit + '0');    // 数字字符
        }
        else
        {
            LCD1602_WriteData(hexDigit - 10 + 'A'); // 字母字符
        }
    }
}

// 显示数字字符
void LCD_ShowNumber(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length)
{
    unsigned char i;
    unsigned char digit;
    unsigned char displayDigit[10]; // 用于存储每一位的数字字符

    // 计算每一位的数字字符
    for (i = 0; i < Length; i++)
    {
        digit = Number % 10; // 取当前最低位数字
        displayDigit[Length - i - 1] = digit + '0'; // 转换为字符并存储
        Number /= 10; // 处理下一个数字
    }

    // 显示每一位数字
    LCD1602_SetCursor(Line, Column); // 设置光标位置
    for (i = 0; i < Length; i++)
    {
        LCD1602_WriteData(displayDigit[i]); // 显示字符
    }
}


//指定位置显示有符号的数字
void LCD1602_DisplaySignedNum(unsigned char Line, unsigned char Column, int Number, unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
    unsigned char digit;
    unsigned char displayDigit[10]; // 用于存储每一位的数字字符

   
	LCD1602_SetCursor(Line, Column); // 设置光标位置
	
	if(Number > 0)
	{
		LCD1602_WriteData('+'); //写数据
		Number1 = Number;
	}
	else
	{
		LCD1602_WriteData('-'); //写数据
		Number1 = -Number;
	}
		
	// 计算每一位的数字字符
    for (i = 0; i < Length; i++)
    {
        digit = Number1 % 10; // 取当前最低位数字
        displayDigit[Length - i - 1] = digit + '0'; // 转换为字符并存储
        Number1 /= 10; // 处理下一个数字
    }

	for (i = 0; i < Length; i++)
    {
        LCD1602_WriteData(displayDigit[i]); // 显示字符
    }
}


// 显示流动字母的函数
void LCD1602_FlowLetters(unsigned char Line, unsigned char StartColumn, char *str, unsigned char Delay)
{
    unsigned char i, j;
    unsigned char length = 0;
	unsigned int delay;
    char buffer[17]; // 用于存储显示内容(16字符 + 1个终止符)

    // 计算字符串的长度
    while (str[length] != '\0')
    {
        length++;
    }

    // 将字符串末尾添加空格填充到屏幕宽度
    for (i = 0; i < 16 - length; i++)
    {
        buffer[length + i] = ' ';
    }
    for (i = 0; i < length; i++)
    {
        buffer[i] = str[i];
    }
    buffer[16] = '\0'; // 添加字符串结束符

    // 流动显示
    for (i = 0; i < length + (16 - length); i++)
    {
        LCD1602_SetCursor(Line, StartColumn); // 设置光标位置
        for (j = 0; j < 16; j++)
        {
            LCD1602_WriteData(buffer[j + i]); // 显示字符
        }

        // 等待一段时间
        for (delay = 0; delay < Delay * 1000; delay++);

        // 清屏
        LCD1602_WriteCommand(0x01);
    }
}






































LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__

void LCD1602_Init(void); //初始化
void LCD1602_SetCursor(unsigned char Line, unsigned char Column); //设置光标的位置
void LCD1602_ShowChar(unsigned char Line, unsigned char Column,unsigned char Char); //显示字符
void LCD_DisplayString(unsigned char Line, unsigned char Column, char *str); //显示字符串
void LCD1602_ShowHexNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length);// 显示16进制数字
void LCD1602_ShowBinNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length); //显示二进制
void LCD_ShowNumber(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length); // 显示数字字符
void LCD1602_DisplaySignedNum(unsigned char Line, unsigned char Column, int Number, unsigned char Length);  //显示有符号数字
void LCD1602_FlowLetters(unsigned char Line, unsigned char StartColumn, char *str, unsigned char Delay);//流动字母



#endif

LCD1602_W.h

#ifndef __LCD1602_W_H__
#define __LCD1602_W_H__


void LCD1602_WriteCommand(unsigned char Command); //写指令
void LCD1602_WriteData(unsigned char Data); //写数据


#endif

LCD1602_W.c

#include <REGX52.H>
#include "intrins.h"

//管脚定义
sbit LCD_WR = P2^5; //数据写入操作
sbit LCD_RS = P2^6; //指令输入
sbit LCD_EN = P2^7; //使能


#define LCD_DataPort	P0   //端口P0设置为数据位


void Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

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


//RS写指令的驱动
void LCD1602_WriteCommand(unsigned char Command)
{
	LCD_RS = 0; //写入指令
	LCD_WR = 0; //写入数据
	LCD_DataPort = Command; //将指令放到数据总线上,并行端口,Commmand的8位可以直接放上去
	LCD_EN = 1;  //使能1-0,写入数据
	Delay1ms();
	LCD_EN = 0;	
	Delay1ms();
		
}


//RW写数据的驱动
void LCD1602_WriteData(unsigned char Data)
{
	LCD_RS = 1; //写入指令
	LCD_WR = 0; //写入数据
	LCD_DataPort = Data; //将指令放到数据总线上,并行端口,Commmand的8位可以直接放上去
	LCD_EN = 1;  //使能1-0,写入数据
	Delay1ms();
	LCD_EN = 0;	
	Delay1ms();
}

后期调用都非常方便,都已经模块化。

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

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

相关文章

【网络安全的神秘世界】csrf客户端请求伪造

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 一、概述 跨站请求伪造&#xff0c;是一种挟持用户在当前已登陆的web应用程序上执行非本意操作的攻击方法&#xff0c;允许攻…

Comsol 利用多孔材料填充复合吸声器,拓宽低频完美吸声

参考文献&#xff1a;Cheng B , Gao N , Huang Y ,et al.Broadening perfect sound absorption by composite absorber filled with porous material at low frequency:[J].Journal of Vibration and Control, 2022, 28(3-4):410-424.DOI:10.1177/1077546320980214. 为了提高低…

端侧大模型系列 | 斯坦福手机端侧Agent大模型,为Android API而生!

0. 引言 峰峦或再有飞来&#xff0c;坐山门老等。泉水已渐生暖意&#xff0c;放笑脸相迎 小伙伴们好&#xff0c;我是微信公众号《小窗幽记机器学习》的小编&#xff1a;卖铁观音的小男孩。今天这篇小作文主要介绍端侧大模型中的函数调用&#xff0c;即常说的Function calling…

即插即用!高德西交的PriorDrive:统一的矢量先验地图编码,辅助无图自动驾驶

Driving with Prior Maps: Unified Vector Prior Encoding for Autonomous Vehicle Mapping 论文主页&#xff1a;https://misstl.github.io/PriorDrive.github.io/ 论文链接&#xff1a;https://arxiv.org/pdf/2409.05352 代码链接&#xff1a;https://github.com/missTL/Pr…

【数据结构】排序算法---直接插入排序

文章目录 1. 定义2. 算法步骤3. 动图演示4. 性质5. 算法分析6. 代码实现C语言PythonJavaCGo 7. 折半插入排序代码实现——C 结语 1. 定义 直接插入排序是一种简单直观的排序算法。它的工作原理为将待排列元素划分为「已排序」和「未排序」两部分&#xff0c;每次从「未排序的」…

PHP Swoole实现简易聊天室,附加小程序端连接websocket简易代码

目录 用到的工具&#xff1a; PHP Swoole拓展 | PHP Redis拓展 | Redis 7 一、安装上述必要工具&#xff08;下面是以宝塔面板中操作为例&#xff09; 给PHP安装Swoole和Redis拓展&#xff1a; 安装Redis软件 二、创建websocket服务器文件"wss_server.php" 具…

node.js+Koa框架+MySQL实现注册登录

完整视频展示&#xff1a;https://item.taobao.com/item.htm?ftt&id831092436619&spma21dvs.23580594.0.0.52de2c1bg9gTfM 效果展示&#xff1a; 一、项目介绍 本项目是基于node.jsKoamysql的注册登录的项目,主要是给才学习node.js和Koa框架的萌新才写的。 二、项目…

java数据结构----图

图的存储结构: 代码实现 public class Graph {// 标记顶点数目private int V;// 标记边数目private int E;// 邻接表private Queue<Integer>[] adj;public Graph(int v) {V v;this.E 0;this.adj new Queue[v];for (int i 0; i < adj.length; i) {adj[i] new Queu…

C++的类与对象中(主讲默认成员函数)

目录 1.类的默认成员函数 2.构造函数 1.全缺省构造函数 2.第7点中的对自定义类型的成员变量构造&#xff08;调用编译器自动生成的默认构造函数&#xff09; 3.析构函数 4.拷贝构造函数 5.运算符重载 1.概念 2.赋值运算符重载 6.const成员函数 1.类的默认成员函数 默…

微服务——网关路由(Spring Cloud Gateway)

网关路由 1.什么是网关 网关又称网间连接器、协议转换器&#xff0c;是在网络层以上实现网络互连的复杂设备&#xff0c;主要用于两个高层协议不同的网络之间的互连。网关就是网络的关口。数据在网络间传输&#xff0c;从一个网络传输到另一网络时就需要经过网关来做数据的路由…

【深度智能】:迈向高级时代的人工智能全景指南

​ ​ 前几天偶然发现了一个超棒的人工智能学习网站&#xff0c;内容通俗易懂&#xff0c;讲解风趣幽默&#xff0c;简直让人欲罢不能。忍不住分享给大家&#xff0c;人工智能立刻跳转&#xff0c;开启你的AI学习之旅吧&#xff01; 第一阶段&#xff1a;基础知识 1. 计算机科…

人脸防伪检测系统源码分享

人脸防伪检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

【Python基础】Python 装饰器(优雅的代码增强工具)

本文收录于 《Python编程入门》专栏&#xff0c;从零基础开始&#xff0c;分享一些Python编程基础知识&#xff0c;欢迎关注&#xff0c;谢谢&#xff01; 文章目录 一、前言二、装饰器基础三、语法糖 四、带参数的装饰器五、多层装饰器六、总结 一、前言 在Python编程的世界里…

【手撕】快排-分治

1. 颜色分类 . - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/sort-colors/description/ 代码 class Solution {public…

Neo4j入门案例:三星堆

创建一个关于三星堆的知识图谱可以是一个非常有趣的项目&#xff0c;它可以帮助理解如何使用Neo4j来存储和查询复杂的关系数据。三星堆文化以其独特的青铜器、金器和其他文物而闻名&#xff0c;这为我们提供了一个丰富的历史背景来构建知识图谱。 数据模型定义 实体类型&#…

数据安全查询-—SAAS本地化及未来之窗行业应用跨平台架构

一、数据库安全查询 默认数据库查询是不区分大小写的&#xff0c;这样无法区分Mm&#xff0c;Admin&#xff0c;admin 二、thinkphp 区分大小写 $condition "binary appdhj_sn {$应用sn}"; 三、原始mysql select * from TableA where binary columnA aaa; 四、…

mtk7628 网口灯问题

板子上电插入网线到网口&#xff0c;只有wan口灯会亮&#xff0c;插入lan口灯不会亮。对比了ok的代码&#xff0c;先对比设备树&#xff0c;未看到网口相关的GPIO。 mt7628an_WMD-7688A-12816.dts mt7628an_hilink_hlk-7628n.dts 继续查看网口相关代码&#xff0c;加打印&…

Android应用程序启动源码分析

文章目录 Android应用程序启动源码分析一、启动流程二、Launcher通知AndroidOS(用户点击图标)2.1 Activity.java2.2 Instrumentation.java2.3 ActivityTaskManagerService.java2.4 ActivityStarter.java2.5 RootWindowContainer.java2.5.1 Task.java2.5.2 TaskFragment.java 2.…

基于python+django+vue的个性化餐饮管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于pythondjangovueMySQL的视…

勇于尝试,永远行动 - 《洛克菲勒写给儿子的38封信》读书笔记

两倍速听过好几遍的书&#xff0c;洛克菲勒的思想和志向&#xff0c;配得上他的成就。 “在尝试中寻找突破&#xff0c;在行动中成就自我。”这是洛克菲勒写给儿子的箴言&#xff0c;也是他一生的真实写照。在这38封信中&#xff0c;他不仅分享了自己的工作心得&#xff0c;更…