51单片机-LCD1602(液晶显示屏)- 写驱动
时间永远是检验真理唯一标准!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();
}
后期调用都非常方便,都已经模块化。