问题来源

在此之前学习了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()输出格式

树莓派通过I2C驱动LCD1602显示屏相关推荐

  1. 通过 I2C 驱动 LCD1602 液晶屏(51单片机)

    通过 I2C 驱动 LCD1602 液晶屏(51单片机) 硬件实物 原理图 3.程序 #include <reg51.h> #include <intrins.h>#defin ...

  2. 51单片机使用 8线/4线/PCF8574(I2C) 驱动 LCD1602

    51单片机使用 8线/4线/PCF8574_I2C驱动 LCD1602 一.8线驱动 二.4线驱动 三.PCF8574(I2C) 驱动 1.PCF8574 介绍 2.接线图 3.示例代码 一.8线驱动 ...

  3. stm32cubeide驱动LCD1602显示屏

    STM32驱动LCD1602 硬件连接关系 STM32CUBEIDE设置 代码 项目设置 最后运行 硬件连接关系 LCD1602 STM32 VCC VCC GND GND VO VCC-滑动变阻 R ...

  4. 树莓派 使用 i2c 连接 LCD1602/LCD1602A 模块

    成品 准备 LCD1602/LCD1602A 模块 IIC LCD1602 拓展板 配置 raspi-config >>> Interfacing Options >>& ...

  5. 8051单片机Proteus仿真与开发实例-OLED显示屏(SSD1306控制器)I2C驱动显示中文及图片仿真

    OLED显示屏(SSD控制器)I2C驱动显示中文及图片仿真 1.OLED显示屏介绍 在前面的实例中,已经介绍了OLED显示屏,在这里就不展开介绍了,请参考: OLED显示屏(SSD1306控制器)I2 ...

  6. Arduino与Proteus仿真实例-OLED显示屏(SSD1306)I2C驱动仿真

    OLED显示屏(SSD1306)I2C驱动仿真 首字母缩写词"OLED"代表有机发光二极管 - 一种使用 LED 的技术,其中的光由有机分子产生. 这些有机 LED 用于制造被认为 ...

  7. 物联网开发笔记(25)- 使用Micropython开发ESP32开发板之控制LCD1602显示屏

    这一节我们讲解了如何控制LCD1602显示屏,显示两行字. 一.目的 使用MicroPython开发ESP32开发板控制LCD1602显示屏 二.环境 ESP32 + LCD1602显示屏 + Tho ...

  8. Arduino 和LCD1602显示屏

    LCD1602显示屏 带I2C接口 引脚说明 GND ------ 地线 VCC ------ 电源(5V or 3.3v 电源不同显示效果有点差别) SDA ------ I2C 数据线 SCL - ...

  9. 物联网开发笔记(26)- 使用Micropython开发ESP32开发板之控制LCD1602显示屏(续)

    上一节介绍了使用i2c来控制LCD1602显示屏,那么使用GPIO怎么控制LCD1602显示屏呢?使用GPIO又分为8bit和4bit两种模式,比较常用的4bit模式,因为它占用GPIO口比较少.   ...

最新文章

  1. jython在MyEclipse控制台出现Failed to install
  2. UFS和eMMC闪存差异在哪?
  3. Java与C++Socket通讯注意事项
  4. python详细安装教程环境配置-[Python] 安装及环境配置
  5. WCF RIA Service实体类中发复杂类型
  6. 文档扫描识别——OpenCV与C++实现OCR文字识别
  7. php加密解密p源码可以吗,论 如何做好PHP的加密解密呐,源码教学
  8. Java内存模型的历史变迁
  9. 3d点击_gooood合辑:3D打印 | 精选全部3D打印案例
  10. Android中handler的使用及原理---学习笔记
  11. z17刷机miui12教程_《蝙蝠侠3百度影音》
  12. mysql学习笔记--表操作
  13. 最喜欢计算机和科学英语作文,英语作文:我最喜欢的科学家
  14. caffe MNIST官方文档中文版
  15. webflow ajax,java开发之spring webflow实现上传单个文件及多个文件功能实例
  16. java 广告插件_徒手创建一个chrome扩展-屏蔽广告插件
  17. 2022-03-13 转载 Dockerfile 高阶使用指南及镜像优化
  18. 比亚迪汉鸿蒙系统测评_深度:预判比亚迪汉EV电驱动系统技术状态
  19. Java中的双冒号::是什么玩意?有这个语法?
  20. Knoll Light Factory 3.2 for mac完整汉化版|灯光工厂 for mac中文版

热门文章

  1. 【论文阅读】Convolutional MKL Based MultimodalEmotion Recognition and Sentiment Analysis
  2. java反射机制到底是什么?
  3. Excel数据的分类汇总
  4. 12个常用前端UI框架集都在这了!!!
  5. 剑破冰山:Oracle开发艺术(目录)
  6. 计算机应用基础试题及答案作业4,计算机应用基础试题及答案
  7. GoDaddy主机一键安装WordPress
  8. 隐藏站长统计4个字的方法
  9. TCP FACK 与 RACK
  10. 爱思助手更新后无法连接服务器,刷机提升 无法连接到苹果服务器 怎么解决