Připojíme Grove LCD display 16x2 s čipem JHD1802M1 k Pi pomocí I2C sběrnice a budeme měřit interní teplotu.

LCD display 16x2 s čipem JHD18002M1

lcd display JHD1802M1

Poznámka: Zespodu připájené 10k rezistory mezi SDA-Vcc, SCL-Vcc výrobce zapomněl zapojit.
Zapojení pinů na Raspbery Pi Pico

rpi pico pin settings

Tabulka 1. Shield je zapojen takto
Sběrnice SDA pin (bílá) SCL pin (žlutá) Piny v MicroPythonu

I2C 0

GP8 pin 11

GP9 pin 12

8 a 9

I2C 1

GP6 pin 9

GP7 pin 10

6 a 7

MicroPython

Modul grove_lcd_i2c.py
#
# Grove 16x2 I2C LCD (White on Blue)
# - https://my.cytron.io/p-grove-16-x-2-lcd-white-on-blue?tracking=idris
#
# Update:
# 22 Jan 2021 - Tested with MicroPython Pico V1.13-290-g556ae7914
#

from machine import Pin, I2C
import utime

class Grove_LCD_I2C(object):
    # Commands
    LCD_CLEARDISPLAY = 0x01
    LCD_RETURNHOME = 0x02
    LCD_ENTRYMODESET = 0x04
    LCD_DISPLAYCONTROL = 0x08
    LCD_CURSORSHIFT = 0x10
    LCD_FUNCTIONSET = 0x20
    LCD_SETCGRAMADDR = 0x40
    LCD_SETDDRAMADDR = 0x80

    # Flags for display entry mode
    LCD_ENTRYRIGHT = 0x00
    LCD_ENTRYLEFT = 0x02
    LCD_ENTRYSHIFTINCREMENT = 0x01
    LCD_ENTRYSHIFTDECREMENT = 0x00

    # Flags for display on/off control
    LCD_DISPLAYON = 0x04
    LCD_DISPLAYOFF = 0x00
    LCD_CURSORON = 0x02
    LCD_CURSOROFF = 0x00
    LCD_BLINKON = 0x01
    LCD_BLINKOFF = 0x00

    # Flags for display/cursor shift
    LCD_DISPLAYMOVE = 0x08
    LCD_CURSORMOVE = 0x00
    LCD_MOVERIGHT = 0x04
    LCD_MOVELEFT = 0x00

    # Flags for function set
    LCD_8BITMODE = 0x10
    LCD_4BITMODE = 0x00
    LCD_2LINE = 0x08
    LCD_1LINE = 0x00
    LCD_5x10DOTS = 0x04
    LCD_5x8DOTS = 0x00

    def __init__(self, i2c, address, oneline=False, charsize=LCD_5x8DOTS):

        self.i2c = i2c
        self.address = address

        self.disp_func = self.LCD_DISPLAYON # | 0x10
        if not oneline:
            self.disp_func |= self.LCD_2LINE
        elif charsize != 0:
            # For 1-line displays you can choose another dotsize
            self.disp_func |= self.LCD_5x10DOTS

        # Wait for display init after power-on
        utime.sleep_ms(50) # 50ms

        # Send function set
        self.cmd(self.LCD_FUNCTIONSET | self.disp_func)
        utime.sleep_us(4500) ##time.sleep(0.0045) # 4.5ms
        self.cmd(self.LCD_FUNCTIONSET | self.disp_func)
        utime.sleep_us(150) ##time.sleep(0.000150) # 150µs = 0.15ms
        self.cmd(self.LCD_FUNCTIONSET | self.disp_func)
        self.cmd(self.LCD_FUNCTIONSET | self.disp_func)

        # Turn on the display
        self.disp_ctrl = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF
        self.display(True)

        # Clear it
        self.clear()

        # Set default text direction (left-to-right)
        self.disp_mode = self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT
        self.cmd(self.LCD_ENTRYMODESET | self.disp_mode)

    def cmd(self, command):
        assert command >= 0 and command < 256
        command = bytearray([command])
        self.i2c.writeto_mem(self.address, 0x80, bytearray([]))
        self.i2c.writeto_mem(self.address, 0x80, command)

    def write_char(self, c):
        assert c >= 0 and c < 256
        c = bytearray([c])
        self.i2c.writeto_mem(self.address, 0x40, c)

    def write(self, text):
        for char in text:
            if char == '\n':
                self.cursor_position(0, 1)
            else:
                self.write_char(ord(char))

    def cursor(self, state):
        if state:
            self.disp_ctrl |= self.LCD_CURSORON
            self.cmd(self.LCD_DISPLAYCONTROL  | self.disp_ctrl)
        else:
            self.disp_ctrl &= ~self.LCD_CURSORON
            self.cmd(self.LCD_DISPLAYCONTROL  | self.disp_ctrl)

    def cursor_position(self, col, row):
        col = (col | 0x80) if row == 0 else (col | 0xc0)
        self.cmd(col)

    def autoscroll(self, state):
        if state:
            self.disp_ctrl |= self.LCD_ENTRYSHIFTINCREMENT
            self.cmd(self.LCD_DISPLAYCONTROL  | self.disp_ctrl)
        else:
            self.disp_ctrl &= ~self.LCD_ENTRYSHIFTINCREMENT
            self.cmd(self.LCD_DISPLAYCONTROL  | self.disp_ctrl)

    def blink(self, state):
        if state:
            self.disp_ctrl |= self.LCD_BLINKON
            self.cmd(self.LCD_DISPLAYCONTROL  | self.disp_ctrl)
        else:
            self.disp_ctrl &= ~self.LCD_BLINKON
            self.cmd(self.LCD_DISPLAYCONTROL  | self.disp_ctrl)

    def display(self, state):
        if state:
            self.disp_ctrl |= self.LCD_DISPLAYON
            self.cmd(self.LCD_DISPLAYCONTROL  | self.disp_ctrl)
        else:
            self.disp_ctrl &= ~self.LCD_DISPLAYON
            self.cmd(self.LCD_DISPLAYCONTROL  | self.disp_ctrl)

    def clear(self):
        self.cmd(self.LCD_CLEARDISPLAY)
        utime.sleep_ms(2) # 2ms

    def home(self):
        self.cmd(self.LCD_RETURNHOME)
        utime.sleep_ms(2) # 2m
main.py
#
# Read internal temperature in Raspberry Pi Pico
# and display to Grove I2C LCD
#
# Raspberry Pi Pico
# - [Bare Board] https://my.cytron.io/p-raspberry-pi-pico?tracking=idris
# - [Pre-soldered Headers] https://my.cytron.io/p-raspberry-pi-pico-pre-soldered-headers?tracking=idris
# - [Maker Pi Pico] https://my.cytron.io/p-maker-pi-pico?tracking=idris
# Grove 16x2 I2C LCD (White on Blue)
# - https://my.cytron.io/p-grove-16-x-2-lcd-white-on-blue?tracking=idris
#
# Update:
# 22 Jan 2021 - Tested with MicroPython Pico V1.13-290-g556ae7914
#

from machine import *
from utime import sleep
from grove_lcd_i2c import Grove_LCD_I2C

sleep(1)
print("MicroPython on Raspberry Pi Pico")
print()

temp_builtin = ADC(ADC.CORE_TEMP)

LCD_SDA = Pin(8)                            (1)
LCD_SCL = Pin(9)
LCD_ADDR = 62 # 0x3E or 62
i2c = I2C(0, sda=LCD_SDA, scl=LCD_SCL)      (2)
print(i2c.scan())
lcd = Grove_LCD_I2C(i2c, LCD_ADDR)

lcd.home()                                  (3)
lcd.write("Raspberry Pi\nPico")             (4)

conversion_factor = 3.3 / (65535)

duty = 0
direction = 1

lcd.clear()
lcd.write("Internal Temp:")

while True:
    for _ in range(256):
        duty += direction
        if duty > 255:
            duty = 255
            direction = -1
        elif duty < 0:
            duty = 0
            direction = 1
        sleep(0.001)

    reading = temp_builtin.read_u16() * conversion_factor
    temperature = 27 - (reading - 0.706)/0.001721
    lcd.cursor_position(0, 1)
    lcd.write("{:.2f}".format(temperature))
1 Při zapojení do konektoru I2C0 se nastavují piny SDA=8 a SCL=9
2 Nastavení I2C 0
3 Nastavení domovské pozice (1.řádek, 1.znak)
4 Zápis na display.
Fungující program

IMG 20231027 035525

Nejtěžší je správně nastavit piny SDA a SLC a potom I2C adresu. Je to vždy jinak, než se píše v návodech.

Zdroje a odkazy