Tutorial #4 de Raspberry Pi Pico: Pantalla LCD

Anuncio
RaspberryPi

Uno de los elementos más vistosos que se pueden usar con una Raspberry Pi Pico es la pantalla LCD Grove. Prácticamente es el elemento faltante para tener una “computadora” en miniatura. Entre algunos de los métodos para comunicarse con este tipo de dispositivos existe el llamado protocolo I2C, el cual veremos de forma rápida. En este tutorial estaremos usando los siguientes materiales:

  • Raspberry Pi Pico
  • Cable micro USB
  • Protoboard
  • Pantalla LCD I2C de Grove
  • Cable conector Grove a pines Macho
  • Librería LCD I2C de Grove

Librería LCD I2C de Grove

Para manejar el módulo de LCD de Grove necesitarás utilizar una librería que contiene todas las funciones necesarias para controlar tu LCD. A grandes rasgos es un código que incluye como mover el cursor en la pantalla, borrarla y poner caracteres en ella. Para usarla solo copia el código en un archivo llamado grove_lcd_i2c.py y guárdalo en la carpeta donde tengas tu código o dentro de la Raspberry Pi Pico. Al final del post encontrarás el código.

Usando el puerto I2C

El puerto I2C permite conectar una gran diversidad de módulos con solo dos cables a tu Pico. Para lograr esto manda datos digitales a una dirección que corresponde al módulo que quieres usar y un comando. Puedes conectar tantos módulos como direcciones haya disponibles. En nuestro caso conectaremos la LCD en el puerto I2C_0 que está en los pines 0 y 1 de tu Pico.

En tu caso, la LCD Grove tiene marcados dos cables, SDA y SCL, en blanco y amarillo respectivamente. SDA va al pin 0 y SCL va al pin 1. Vía: Raspberry Pi Foundation

Código

Este código es una prueba simple para desplegar mensajes en la Raspberry Pi Pico. Como puedes ver estamos asignando dos pines digitales, llamados LCD_SDA y LCD_SCL. Estos corresponden a los pines de datos del protocolo I2C. Además, definimos una variable LCD_ADDR, con un valor de 62. Esa es la dirección de nuestra pantalla LCD. Para iniciar la comunicación serial, usamos la función I2C() y para iniciar la pantalla LCD, usamos la función Grove_LCD_I2C(). Por último, la función home() manda el cursor de la pantalla al primer caracter y la función write() escribe el mensaje.

Anuncio
RaspberryPi
from machine import *
import utime
from grove_lcd_i2c import Grove_LCD_I2C

utime.sleep(1)
led = Pin(25, Pin.OUT)

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

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

Leyendo una entrada analógica

La pantalla puede actualizarse con datos que leamos desde la Pico, no necesariamente datos de texto que hayamos programado previamente. Para lograr esto, podemos configurar una lectura analógica y mostrarla en la pantalla cada segundo. Para ello, solo tenemos que asignar el pin analógico, y guardar la lectura en una variable de texto tipo string. En este caso, el valor lo convertimos a un porcentaje, que representa el ancho de pulso de una salida PWM. En este caso, usamos una nueva función llamada clear() que nos permite borrar la pantalla.

from machine import *
import utime
from grove_lcd_i2c import Grove_LCD_I2C

utime.sleep(1)
led = Pin(25, Pin.OUT)

LCD_SDA = Pin(0)
LCD_SCL = Pin(1)
LCD_ADDR = 62 # 0x3E or 62
i2c = I2C(0, sda=LCD_SDA, scl=LCD_SCL)
lcd = Grove_LCD_I2C(i2c, LCD_ADDR)

adc = machine.ADC(26)
conversion_factor = 100 / (65535)

while True:
    porcentaje = adc.read_u16() * conversion_factor
    lcd.home()
    lcd.clear()
    out_string = "PWM %: " + str(porcentaje)
    lcd.write(out_string)
    utime.sleep(1)

Conclusiones:

Con estos comandos podrás mandar mensajes a tu pantalla LCD Grove, mientras quepan en la pantalla. Prueba a combinarlo con otros sensores, como un sensor de temperatura o de luz. Igual y si lo usas como una tarjeta de presentación en un negocio también está perfecto. ¡Te invitamos a que sigas los demás tutoriales de Raspberry Pi Pico que tenemos para ti!

Referencias:

Making A Lucky Draw Device Using Raspberry Pi Pico

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

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