树莓派通过I2C驱动LCD1602显示屏

news/2025/2/5 5:52:35/

问题来源

在此之前学习了Arduino驱动LCD1602(Arduino通过I2C控制1602LCD显示屏),其过程比较简单,现在想通过树莓派实现控制功能,提升树莓派编程控制能力,在此过程中虽然能正常让LCD显示文字,但是对于网上代码有些不理解,遂形成这篇博文,希望有人能解答文末问题。

LCD1602知识

  • LCD1602引脚
    在这里插入图片描述

  • 指令寄存器(IR)和数据寄存器(DR)
    本系列模块内部具有两个 8 位寄存器:指令寄存器(IR)和数据寄存器(DR)。用户可以通过 RS 和 R/W 输入信号的组合选择指定的寄存器,进行相应的操作。下表中列出了组合选择方式:
    在这里插入图片描述

  • LCD1602的基本操作
      1. 读状态:输入RS=0,RW=1,E=高脉冲。输出:D0—D7为状态字。
      2. 读数据:输入RS=1,RW=1,E=高脉冲。输出:D0—D7为数据。
      3. 写命令:输入RS=0,RW=0,E=低脉冲。输出:无。(写完置E=高脉冲)
      4. 写数据:输入RS=1,RW=0,E=低脉冲。输出:无。
    注意:E(或EN)端为使能(enable)端,写操作时,下降沿使能。读操作时,E高电平有效

  • 显示位置设置
    若想在00H处显示数据的话,则必须将00H加上80H,即0x00H+0x80H,若要在01H处显示数据,也必须加0x80H, 例如要将某字符显示在第2行第5列,则确定地址的指令代码应为80H+44H=C4H。依次类推
    在这里插入图片描述

I2C转接板引脚

  • I2C引脚

GND ------ 地线
VCC ------ 电源(5V or 3.3v 电源不同显示效果有点差别)
SDA ------ I2C 数据线
SCL ------ I2C 时钟线

  • 树莓派40Pin引脚图
    在这里插入图片描述
    这个接线还是比较简单的。

树莓派设置

  • 安装wiringPi库
    相关操作自行搜索,有很多。也可以参看官方指南
  • 开启I2C

树莓派需要开启I2C功能,这个可以通过VNC远程或者直接树莓派接显示屏进行设置,相关操作搜索一下有很多。一个是在raspi-config中设置,另一个是在图形界面start按钮中修改树莓派preference。注意:这两个有可能是重复的,我不清楚,我是啷个都设置了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

程序代码

将下列代码保存为".c"文本,树莓派终端编译运行即可。在此请看下一节对代码提出的一个问题,我没搞懂。此外,程序中的初始化未必是必须的,因为我看1602手册时说上电电压超过4.5V时会自动初始化。

#include <stdio.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <string.h>int LCDAddr = 0x27;	//LCD设备地址
int BLEN = 1;		//BLEN是控制啥的  
int fd;void write_word(int data){int temp = data;//BLEN是控制啥的 if ( BLEN == 1 )temp |= 0x08;elsetemp &= 0xF7;wiringPiI2CWrite(fd, temp);
}
/****************************************************************
RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器
R/W为读写选择,高电平(1)时进行读操作,低电平(0)时进行写操作。
E(或EN)端为使能(enable)端,写操作时,下降沿使能。读操作时,E高电平有效
****************************************************************///发送命令的函数
void send_command(int comm){int buf;// Send bit7-4 firstlybuf = comm & 0xF0;buf |= 0x04;			// RS = 0(低电平0时选择指令寄存器), RW = 0(此时发送指令), EN = 1write_word(buf);delay(2);buf &= 0xFB;			// Make EN = 0,EN从1——>0,下降沿,进行写操作write_word(buf);// Send bit3-0 secondlybuf = (comm & 0x0F) << 4;buf |= 0x04;			// RS = 0, RW = 0, EN = 1write_word(buf);delay(2);buf &= 0xFB;			// Make EN = 0write_word(buf);
}
/*******************  问题    ***********************************
此处发送数据的函数与Arduino锁使用的LiquidCrystal_I2C.h函数区别很大;
问题是不论是发送命令还是发送数据,所传送的一个字节的后4位都是用于
控制的,只有高4位才是具有实际意义的,不知道为什么。官方在wiringPiI2C.h
介绍中wiringPiI2CWrite()函数介绍比较简单。
****************************************************************/
//发送数据的函数
void send_data(int data){int buf;// Send bit7-4 firstlybuf = data & 0xF0;buf |= 0x05;			// RS = 1, RW = 0, EN = 1write_word(buf);delay(2);buf &= 0xFB;			// Make EN = 0write_word(buf);// Send bit3-0 secondlybuf = (data & 0x0F) << 4;buf |= 0x05;			// RS = 1, RW = 0, EN = 1write_word(buf);delay(2);buf &= 0xFB;			// Make EN = 0write_word(buf);
}//初始化函数
void init(){send_command(0x33);	// Must initialize to 8-line mode at firstdelay(5);send_command(0x32);	// Then initialize to 4-line modedelay(5);send_command(0x28);	// 2 Lines & 5*7 dotsdelay(5);send_command(0x0C);	// Enable display without cursordelay(5);send_command(0x01);	// Clear ScreenwiringPiI2CWrite(fd, 0x08);
}
//清屏
void clear(){send_command(0x01);	//clear Screen
}void write(int x, int y, char data[]){int addr, i;int tmp;if (x < 0)  x = 0;if (x > 15) x = 15;if (y < 0)  y = 0;if (y > 1)  y = 1;// Move cursor//第一行地址起止为00H,第二行起止为40H;//但这个0x80干嘛的,为什么要加?addr = 0x80 + 0x40 * y + x;send_command(addr);tmp = strlen(data);for (i = 0; i < tmp; i++){send_data(data[i]);}
}void main(){fd = wiringPiI2CSetup(LCDAddr);init();write(0, 0, "Greetings!");write(1, 1, "WWW.HNZHIYU.CN");delay(2000);//clear();
}

问题

此处发送数据的函数与Arduino锁使用的LiquidCrystal_I2C.h函数区别很大;问题是不论是发送命令还是发送数据,所传送的一个字节的后4位都是用于控制的,只有高4位才是具有实际意义的,不知道为什么。官方在wiringPiI2C.h介绍中wiringPiI2CWrite()函数介绍比较简单。
而LCD1602的手册中发送数据是可以一次发送8位的,如下图,
在这里插入图片描述
不知是否有专业人士解答一下这个。

另外在写数据是,写数据函数执行了两次。我觉得原因是第一次只是是EN变成高电平,第二次是EN变成低电平,因为EN是下降沿有效。

	buf = comm & 0xF0;buf |= 0x04;			// RS = 0(低电平0时选择指令寄存器), RW = 0(此时发送指令), EN = 1write_word(buf);delay(2);buf &= 0xFB;			// Make EN = 0,EN从1——>0,下降沿,进行写操作write_word(buf);

解答

  • 地址中0x80的原因
    0x80是因为在设置DDRAM地址时,DB7固定是为1的。DB7是BF忙碌标志位,
    在这里插入图片描述
  • 输出字符与命令为什么分两次
    因为LCD1602字符发生器RAM中 GROM 中,字符码与字符字模之间的对应关系决定。每个字符分高四位与第四位,对应关系如下图,可以看到字母A高四位为LHLL,第四位为LLLH,即0100 0001,在上述程序输出字符的函数中,每次输出时添加打印函数printf()输出到终端,可以发现字母A的两次输出数值为65(0100 0001),与17(0001 0001),这两个数字高四位拼起来为 0100 0001,即与字符A对应。
    在这里插入图片描述
    在附上另一种表达形式的表
    在这里插入图片描述
  • 附验证所需代码,去除了标注
#include <stdio.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <string.h>int LCDAddr = 0x27;
int BLEN = 1;
int fd;void write_word(int data){int temp = data;if ( BLEN == 1 )temp |= 0x08;else{temp &= 0xF7;printf("BLEN is not 1\n");}wiringPiI2CWrite(fd, temp);
}void send_command(int comm){int buf;// Send bit7-4 firstlybuf = comm & 0xF0;buf |= 0x04;			// RS = 0, RW = 0, EN = 1write_word(buf);delay(2);buf &= 0xFB;			// Make EN = 0write_word(buf);printf("send_command buf bit7-4 is %d\n", buf);delay(2000);// Send bit3-0 secondlybuf = (comm & 0x0F) << 4;buf |= 0x04;			// RS = 0, RW = 0, EN = 1write_word(buf);delay(2);buf &= 0xFB;			// Make EN = 0write_word(buf);printf("send_command buf bit3-0 is %d\n", buf);
}void send_data(int data){int buf;// Send bit7-4 firstlybuf = data & 0xF0;buf |= 0x05;			// RS = 1, RW = 0, EN = 1write_word(buf);delay(2);buf &= 0xFB;			// Make EN = 0write_word(buf);printf("send_data buf bit7-4 is   %d\n", buf);delay(2000);// Send bit3-0 secondlybuf = (data & 0x0F) << 4;buf |= 0x05;			// RS = 1, RW = 0, EN = 1write_word(buf);delay(2);buf &= 0xFB;			// Make EN = 0write_word(buf);printf("send_data buf bit3-0 is %d\n",buf);
}void init(){send_command(0x33);	// Must initialize to 8-line mode at firstdelay(5);send_command(0x32);	// Then initialize to 4-line modedelay(5);send_command(0x28);	// 2 Lines & 5*7 dotsdelay(5);send_command(0x0C);	// Enable display without cursordelay(5);send_command(0x01);	// Clear ScreenwiringPiI2CWrite(fd, 0x08);
}void clear(){send_command(0x01);	//clear Screen
}void write(int x, int y, char data[]){int addr, i;int tmp;if (x < 0)  x = 0;if (x > 15) x = 15;if (y < 0)  y = 0;if (y > 1)  y = 1;// Move cursoraddr = 0x80 + 0x40 * y + x;send_command(addr);tmp = strlen(data);for (i = 0; i < tmp; i++){send_data(data[i]);
//		wiringPiI2CWrite(fd, data[i]);printf("Now   %c   is printed\n", data[i]);}
}void main(){fd = wiringPiI2CSetup(LCDAddr);init();write(0, 0, "A1 B2!");write(1, 4, "");delay(2000);//clear();
}

参考

http://www.elecfans.com/xianshi/20171020567470.html
http://www.51hei.com/bbs/dpj-83245-1.html
http://bbs.elecfans.com/jishu_451276_1_4.html
LCD1602模块如何显示自定义字符
printf()输出格式


http://www.ppmy.cn/news/478619.html

相关文章

windows 错误代码2

4056-关机操作正在执行。4057-提供的对象已经无效。4058-元素已经存在&#xff0c;并且未被替换。4059-由于请求的操作已经完成&#xff0c;故无法取消。4060-由于请求的操作已经完成&#xff0c;故无法执行。4061-操作访问的数据超出有效数据的范围。4062-请求的版本不受支持。…

解决安装黑苹果出现提示应用程序副本已损坏,不能用来安装macOS的解决方法

安装黑苹果系统出现提示 应用程序副本已损坏&#xff0c;不能用来安装macOS的解决方法 不管是实体机黑苹果安装&#xff0c;还是虚拟机安装&#xff0c;都会遇得到 原因&#xff0c;苹果系统镜像文件中内置的时间证书到期 比如现在的时间是2019/11/08&#xff0c;安装黑苹果1…

Mac 在终端下复制粘贴出现:00~ xxx 01~ 问题的解决方案

在 Mac 在终端下复制粘贴字符串的时候&#xff0c;偶然出现了粘贴的字符串收尾会多了一对字符&#xff1a;00~ xxx 01~。 经过一番研究发现&#xff0c;原来这是终端本身的功能&#xff1a;括号粘贴模式。 那这个括号粘贴模式有什么用呢&#xff1f;其实他的用处很简单&#…

应用程序无法正常启动0xc0150002

应用程序无法正常启动0xc0150002 1 介绍2 分析3 处理步骤 3.1 下载VC90的动态库3.2 工具包中放入VC90动态库 附 downloading Microsoft Visual C 2008 Redistributable Package (x86) 参考 1 介绍 安装内部开发的工具时&#xff0c;遇到报错“0xc0150002”。 之后查看系统日志…

【解决方案】mac:stack Error: `gyp` failed with exit code:1

【20200730更新】 最下面是之前的答案。我发现这个问题其实不那么简单&#xff0c;是因为搜索gypfailed with exit code:1还不够具体&#xff0c;看看报的错误&#xff0c;其实可以更详细一些的。分隔符下面的是之前的一种解决方案&#xff0c;这种解决方案只解决报文件node-gy…

mac解决“您的电脑因为出现问题问题而重新启动 SOCD report detected: (iBoot panic)“报错, 重置SMC与重置NVRAM(PRAM)

背景 mac monterey 12.5.1 关机后再开机出现报错 SOCD report detected: (iBoot panic)关机重启更新系统都不管用 解决办法 按一下音量加,再按一下音量减再长按5秒关机键, 开机后没再出现自动重启和报错, 鬼知道这是个什么神仙bug, 估计可能是软件和系统不兼容卡死, 按我理…

LCD1602 通过转接板 i2c显示

1.安装库文件 2.输入如下代码 #include <LiquidCrystal_I2C.h> //引用I2C库 #include <Wire.h> LiquidCrystal_I2C lcd(0x27,16,2); void setup() { lcd.init(); // 初始化LCD lcd.backlight(); //设置LCD背景等亮 lcd.setCursor(0,0); //设置显示指针 lcd.…

rk3128-android7.1-遇到一个i2c错误

遇到一个logo界面卡死或者使用途中没有触摸 获取kernel里面的log打印如下: 1248.792175] rockchip_i2c 20056000.i2c: Error applying setting, reverse things back [ 1248.985890] rockchip_i2c 20056000.i2c: Addr[0x0014] wait event timeout, state: 1, is_busy: 1, erro…