这一节我们讲解了如何控制LCD1602显示屏,显示两行字。

一、目的

使用MicroPython开发ESP32开发板控制LCD1602显示屏

二、环境

ESP32 + LCD1602显示屏 + Thonny IDE + 面包板(非必须)+ 几根杜邦线(为了方便讲解,这里使用Wokwi仿真)

I2C配置的有下图的黑色小板(小班上蓝色的为调节LCD亮度的旋钮,旁边是PCF8574T芯片,相当于是开发板和LCD显示屏的桥梁作用):

标准配置的如下图:

接线图:

注意需要使用开发板上的5V电压,而不是3.3V。真实环境下使用3.3V会无法显示或者显示很暗。

三、LCD1602显示屏介绍

请查看官方文档:

wokwi-lcd1602 Reference | Wokwi DocsAn LCD with 2 lines, 16 characters per line.https://docs.wokwi.com/parts/wokwi-lcd1602      LCD1602显示屏有两种:一种是I2C的(4个针脚),两一种是标准的(16个针脚)。

I2C配置模拟控制LCD模块的PCF8574T芯片。

I2C配置(4个针脚):

标准配置(16个针脚):

四、下面举个例子给大家演示一下LCD1602显示屏的使用方法

先给大家讲解一下怎么获得1602LCD的地址:我们打开官方网站,查看:

Quick reference for the ESP32 — MicroPython 1.19.1 documentationhttp://docs.micropython.org/en/latest/esp32/quickref.html#software-i2c-bus

使用以上代码就可以打印出1602lcd显示屏的地址。

from machine import Pin, SoftI2Ci2c = SoftI2C(sda=Pin(15), scl=Pin(2), freq=100000)lcdAddr = i2c.scan() # scan for devices
print(lcdAddr)  # 打印出lcd的地址

从上图可以看到地址是39。

上代码:

main.py

import time
from machine import SoftI2C, Pin
from esp32_i2c_1602lcd import I2cLcdDEFAULT_I2C_ADDR = 0x27  # lcd1602的地址是0x27
i2c = SoftI2C(sda=Pin(15),scl=Pin(2),freq=100000)  # 定义一个SoftI2C的对象,指定sda和scl的GPIO口,并设置好通信的频率
lcd = I2cLcd(i2c, DEFAULT_I2C_ADDR, 2, 16)  # 定义一个I2CLcd对象,设置模式为i2c,地址,行数,行的大小16个字节for i in range(1, 10):lcd.clear()  # 清屏lcd.putstr("...{}...\n".format(i))  # 显示第一行数据,\n为换行符lcd.putstr("I love Shanghai")   # 显示第二行数据time.sleep(1)

diagram.json

{"version": 1,"author": "Anonymous maker","editor": "wokwi","parts": [{"type": "wokwi-esp32-devkit-v1","id": "esp","top": -12,"left": -168.66,"attrs": { "env": "micropython-20220618-v1.19.1" }},{"type": "wokwi-lcd1602","id": "lcd1","top": 3.77,"left": -4.5,"attrs": { "pins": "i2c", "background": "blue", "color": "white" }}],"connections": [[ "esp:TX0", "$serialMonitor:RX", "", [] ],[ "esp:RX0", "$serialMonitor:TX", "", [] ],[ "lcd1:GND", "esp:GND.1", "black", [ "h-30.66", "v101.73" ] ],[ "esp:D2", "lcd1:SCL", "green", [ "h22.86", "v-50.9" ] ],[ "lcd1:SDA", "esp:D15", "cyan", [ "h-11.33", "v65.4" ] ],[ "lcd1:VCC", "esp:VIN", "red", [ "h-20.38", "v152.84", "h-162.43", "v-55.67" ] ]]
}

lcd_api.py

"""Provides an API for talking to HD44780 compatible character LCDs."""import timeclass LcdApi:"""Implements the API for talking with HD44780 compatible character LCDs.This class only knows what commands to send to the LCD, and not how to getthem to the LCD.It is expected that a derived class will implement the hal_xxx functions."""# The following constant names were lifted from the avrlib lcd.h# header file, however, I changed the definitions from bit numbers# to bit masks.## HD44780 LCD controller command setLCD_CLR = 0x01              # DB0: clear displayLCD_HOME = 0x02             # DB1: return to home positionLCD_ENTRY_MODE = 0x04       # DB2: set entry modeLCD_ENTRY_INC = 0x02        # --DB1: incrementLCD_ENTRY_SHIFT = 0x01      # --DB0: shiftLCD_ON_CTRL = 0x08          # DB3: turn lcd/cursor onLCD_ON_DISPLAY = 0x04       # --DB2: turn display onLCD_ON_CURSOR = 0x02        # --DB1: turn cursor onLCD_ON_BLINK = 0x01         # --DB0: blinking cursorLCD_MOVE = 0x10             # DB4: move cursor/displayLCD_MOVE_DISP = 0x08        # --DB3: move display (0-> move cursor)LCD_MOVE_RIGHT = 0x04       # --DB2: move right (0-> left)LCD_FUNCTION = 0x20         # DB5: function setLCD_FUNCTION_8BIT = 0x10    # --DB4: set 8BIT mode (0->4BIT mode)LCD_FUNCTION_2LINES = 0x08  # --DB3: two lines (0->one line)LCD_FUNCTION_10DOTS = 0x04  # --DB2: 5x10 font (0->5x7 font)LCD_FUNCTION_RESET = 0x30   # See "Initializing by Instruction" sectionLCD_CGRAM = 0x40            # DB6: set CG RAM addressLCD_DDRAM = 0x80            # DB7: set DD RAM addressLCD_RS_CMD = 0LCD_RS_DATA = 1LCD_RW_WRITE = 0LCD_RW_READ = 1def __init__(self, num_lines, num_columns):self.num_lines = num_linesif self.num_lines > 4:self.num_lines = 4self.num_columns = num_columnsif self.num_columns > 40:self.num_columns = 40self.cursor_x = 0self.cursor_y = 0self.backlight = Trueself.display_off()self.backlight_on()self.clear()self.hal_write_command(self.LCD_ENTRY_MODE | self.LCD_ENTRY_INC)self.hide_cursor()self.display_on()def clear(self):"""Clears the LCD display and moves the cursor to the top leftcorner."""self.hal_write_command(self.LCD_CLR)self.hal_write_command(self.LCD_HOME)self.cursor_x = 0self.cursor_y = 0def show_cursor(self):"""Causes the cursor to be made visible."""self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY |self.LCD_ON_CURSOR)def hide_cursor(self):"""Causes the cursor to be hidden."""self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY)def blink_cursor_on(self):"""Turns on the cursor, and makes it blink."""self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY |self.LCD_ON_CURSOR | self.LCD_ON_BLINK)def blink_cursor_off(self):"""Turns on the cursor, and makes it no blink (i.e. be solid)."""self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY |self.LCD_ON_CURSOR)def display_on(self):"""Turns on (i.e. unblanks) the LCD."""self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY)def display_off(self):"""Turns off (i.e. blanks) the LCD."""self.hal_write_command(self.LCD_ON_CTRL)def backlight_on(self):"""Turns the backlight on.This isn't really an LCD command, but some modules have backlightcontrols, so this allows the hal to pass through the command."""self.backlight = Trueself.hal_backlight_on()def backlight_off(self):"""Turns the backlight off.This isn't really an LCD command, but some modules have backlightcontrols, so this allows the hal to pass through the command."""self.backlight = Falseself.hal_backlight_off()def move_to(self, cursor_x, cursor_y):"""Moves the cursor position to the indicated position. The cursorposition is zero based (i.e. cursor_x == 0 indicates first column)."""self.cursor_x = cursor_xself.cursor_y = cursor_yaddr = cursor_x & 0x3fif cursor_y & 1:addr += 0x40    # Lines 1 & 3 add 0x40if cursor_y & 2:addr += 0x14    # Lines 2 & 3 add 0x14self.hal_write_command(self.LCD_DDRAM | addr)def putchar(self, char):"""Writes the indicated character to the LCD at the current cursorposition, and advances the cursor by one position."""if char != '\n':self.hal_write_data(ord(char))self.cursor_x += 1if self.cursor_x >= self.num_columns or char == '\n':self.cursor_x = 0self.cursor_y += 1if self.cursor_y >= self.num_lines:self.cursor_y = 0self.move_to(self.cursor_x, self.cursor_y)def putstr(self, string):"""Write the indicated string to the LCD at the current cursorposition and advances the cursor position appropriately."""for char in string:self.putchar(char)def custom_char(self, location, charmap):"""Write a character to one of the 8 CGRAM locations, availableas chr(0) through chr(7)."""location &= 0x7self.hal_write_command(self.LCD_CGRAM | (location << 3))time.sleep_us(40)for i in range(8):self.hal_write_data(charmap[i])time.sleep_us(40)self.move_to(self.cursor_x, self.cursor_y)def hal_backlight_on(self):"""Allows the hal layer to turn the backlight on.If desired, a derived HAL class will implement this function."""passdef hal_backlight_off(self):"""Allows the hal layer to turn the backlight off.If desired, a derived HAL class will implement this function."""passdef hal_write_command(self, cmd):"""Write a command to the LCD.It is expected that a derived HAL class will implement thisfunction."""raise NotImplementedErrordef hal_write_data(self, data):"""Write data to the LCD.It is expected that a derived HAL class will implement thisfunction."""raise NotImplementedError

esp32_i2c_lcd1602lcd.py

"""Implements a HD44780 character LCD connected via PCF8574 on I2C.This was tested with: https://www.wemos.cc/product/d1-mini.html"""from lcd_api import LcdApi
from machine import I2C
from time import sleep_ms# Defines shifts or masks for the various LCD line attached to the PCF8574MASK_RS = 0x01
MASK_RW = 0x02
MASK_E = 0x04
SHIFT_BACKLIGHT = 3
SHIFT_DATA = 4class I2cLcd(LcdApi):"""Implements a HD44780 character LCD connected via PCF8574 on I2C."""def __init__(self, i2c, i2c_addr, num_lines, num_columns):self.i2c = i2cself.i2c_addr = i2c_addrself.i2c.writeto(self.i2c_addr, bytearray([0]))sleep_ms(20)   # Allow LCD time to powerup# Send reset 3 timesself.hal_write_init_nibble(self.LCD_FUNCTION_RESET)sleep_ms(5)    # need to delay at least 4.1 msecself.hal_write_init_nibble(self.LCD_FUNCTION_RESET)sleep_ms(1)self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)sleep_ms(1)# Put LCD into 4 bit modeself.hal_write_init_nibble(self.LCD_FUNCTION)sleep_ms(1)LcdApi.__init__(self, num_lines, num_columns)cmd = self.LCD_FUNCTIONif num_lines > 1:cmd |= self.LCD_FUNCTION_2LINESself.hal_write_command(cmd)def hal_write_init_nibble(self, nibble):"""Writes an initialization nibble to the LCD.This particular function is only used during initialization."""byte = ((nibble >> 4) & 0x0f) << SHIFT_DATAself.i2c.writeto(self.i2c_addr, bytearray([byte | MASK_E]))self.i2c.writeto(self.i2c_addr, bytearray([byte]))def hal_backlight_on(self):"""Allows the hal layer to turn the backlight on."""self.i2c.writeto(self.i2c_addr, bytearray([1 << SHIFT_BACKLIGHT]))def hal_backlight_off(self):"""Allows the hal layer to turn the backlight off."""self.i2c.writeto(self.i2c_addr, bytearray([0]))def hal_write_command(self, cmd):"""Writes a command to the LCD.Data is latched on the falling edge of E."""byte = ((self.backlight << SHIFT_BACKLIGHT) | (((cmd >> 4) & 0x0f) << SHIFT_DATA))self.i2c.writeto(self.i2c_addr, bytearray([byte | MASK_E]))self.i2c.writeto(self.i2c_addr, bytearray([byte]))byte = ((self.backlight << SHIFT_BACKLIGHT) | ((cmd & 0x0f) << SHIFT_DATA))self.i2c.writeto(self.i2c_addr, bytearray([byte | MASK_E]))self.i2c.writeto(self.i2c_addr, bytearray([byte]))if cmd <= 3:# The home and clear commands require a worst case delay of 4.1 msecsleep_ms(5)def hal_write_data(self, data):"""Write data to the LCD."""byte = (MASK_RS | (self.backlight << SHIFT_BACKLIGHT) | (((data >> 4) & 0x0f) << SHIFT_DATA))self.i2c.writeto(self.i2c_addr, bytearray([byte | MASK_E]))self.i2c.writeto(self.i2c_addr, bytearray([byte]))byte = (MASK_RS | (self.backlight << SHIFT_BACKLIGHT) | ((data & 0x0f) << SHIFT_DATA))self.i2c.writeto(self.i2c_addr, bytearray([byte | MASK_E]))self.i2c.writeto(self.i2c_addr, bytearray([byte]))

五、演示效果,请参考如下链接

Wokwi Arduino and ESP32 Simulatorhttps://wokwi.com/projects/345562142596923987

 六、扩展

在实际产品开发中,开发的GPIO口等是十分珍贵的资源,我们常用i2c模式来进行开发,减少IO口的占用,同时布线也十分简单。

我在GitHub上找到LCD1602的驱动,其中包含其他开发板的LCD1602驱动,大家有空可以学习一下。

GitHub - dhylands/python_lcd: Python based library for talking to character based LCDs.

你也可以去Micropython论坛寻找有用的资料:

MicroPython Forum (Archive) - Searchhttps://forum.micropython.org/search.php?keywords=lcd1602&fid%5B0%5D=18

物联网开发笔记(25)- 使用Micropython开发ESP32开发板之控制LCD1602显示屏相关推荐

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

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

  2. MLX90640开发笔记(一)概述及开发资料准备

    现在自己在做红外成像仪的越来越多了,两年前有个井下机电设备运行状态的科研项目,当时使用了AMG8833(8*8像素).前段时间因为公司生产电路板测试需要,打算买一台红外成像仪测量电路板发热是否正常,商 ...

  3. 物联网开发笔记(9)- 使用Wokwi仿真MicroPython on ESP32开发板实现温度和湿度检测并使用屏幕显示

    一.测试环境 我们同样使用在Wokwi网站上选择Micropython with ESP32进行仿真,来进行温度和湿度的检测. ESP32官方技术参考手册: https://www.espressif ...

  4. 基于MicroPython的ESP32开发

    很久前入手了一块ESP32 DEVKIT V1,当时基于C_SDK开发.最近想搞下MicroPython,就又把这块板子找出来了. 一.先下载支持MicroPython的ESP32固件 去MicroP ...

  5. Android开发笔记(七十一)区分开发模式和上线模式

    为什么要区分两种模式 许多开发者(包括博主在内)都是闷骚的程序员,为了开发调试方便,常常在代码里加上日志,还经常在页面上各种弹窗提示.这固然有利于发现bug.提高软件质量,但过多的调试信息往往容易泄露 ...

  6. 【Visual C++】游戏开发笔记三十一 回归季 游戏开发资料整理打包下载 专栏行文思路整理

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...

  7. 外设驱动库开发笔记25:FM25xxx FRAM存储器驱动

    在我们的项目中,时常会有参数或数据需要保存.铁电存储器的优良性能和操作方便常常被我们选用.FM25xxx FRAM存储器就是我们经常使用到的一系列铁电存储器,这一篇我们将讨论FM25xxx FRAM存 ...

  8. 嵌入式系统开发笔记25:win10防火墙打开特定端口

    本系列文章将向大家介绍嵌入式系统开发的各方面知识. 本文将向大家介绍dakaiwin10防火墙特定端口的方法. 1.引言 win10上位机编写程序,启动TCP服务器应用程序,并绑定1000端口:lin ...

  9. STM32开发笔记25:STM32L0低功耗设计—— 使用Keil和ST-Link下载低功耗程序

    单片机型号:STM32L053R8T6 继续项目的开发工作,突然发现,程序不能够正常下载到单片机中了,提示如下图所示的错误,我使用的是keil和ST-Link. 这个问题在我第1次调试的时候发生过1次 ...

最新文章

  1. 互联网1分钟 |1207
  2. Git、TortoiseGit、GitHub、Gitee、GitLab 安装与入门使用
  3. 武汉计算机应用中职学校,武汉市中职学校计算机应用基础课程抽考.Doc
  4. 还在担心没有服务器做不了数据分析?这个免费资源看一下!
  5. 暖心社区(2018-07-17)
  6. 百倍训练效率提升,微软通用语言表示模型T-ULRv5登顶XTREME
  7. 高性能tornado框架简单实现restful接口及运维开发实例
  8. python中tell函数_PYTHON学习14.09:Python seek()和tell()函数详解
  9. iOS App Extensions之Share Extension
  10. 什么是Photoshop中的图层和蒙版?
  11. 纯C#实现JPEG解码器在超大图片切割中的应用
  12. Python编程要点:列表操作和Python的Fraction类(代码实现和练习)
  13. 2016杭州云栖大会回顾网址
  14. 关于声音的前后左右上下的控制以及单声道立体声的区别
  15. mongodb 分片集群安装 -- 二进制文件安装
  16. oCam 中文绿色版 - 免费实用的屏幕录像与截图软件 (制作视频教程/录制直播视频)
  17. J-link OB 读取不了的问题
  18. c语言流控制(20180710)
  19. 分层结构的生活例子_层次分析法经典案例
  20. 使用@media实现网页字体大小自适应

热门文章

  1. DEM影像下载、拼接、裁剪(ArcGIS)
  2. centos 7.5 安装桌面环境及报错
  3. CDMA码片序列问题
  4. 2-直观体验OAuth2
  5. BUCT-2021年ACM竞赛班训练(一)2021.3.25-问题 A: 大佬的高级IDLE-题解
  6. 刷脸支付服务商市场空白大有可为
  7. Envi处理MODIS流程
  8. 数据集fer2013
  9. 推荐阅读:《我在赶集网的两个月(完整版)》
  10. 前端html + js视频播放器(快进,快退,倍速,全屏等功能)