Interface de tela LCD 16×2 com Raspberry Pi Pico
Conteudo
Visão geral
Neste tutorial, aprenderemos como fazer a interface do display LCD 16 × 2 com o Raspberry Pi Pico. Um LCD é um módulo de display eletrônico que usa tecnologia de cristal líquido para produzir uma imagem visível. O display LCD 16 × 2 é um módulo muito básico, comumente usado em aplicações de circuitos eletrônicos. O 16×2 traduz 16 caracteres por linha em 2 dessas linhas. Neste LCD, cada caractere é exibido em uma matriz de 5×8 pixels.
Raspberry Pi Pico, que foi lançado há alguns meses, requer algum display LCD em aplicações de engenharia. Aqui, veremos os detalhes e recursos do visor LCD. O display LCD é baseado no driver HD44780. Existem versões I2C e versões não I2C do display LCD. Tomaremos esses dois LCDs como exemplo e como interface com o Raspberry Pi Pico. Vamos escrever o código MicroPython para fazer a interface do display LCD 16×2 com o Raspberry Pi Pico.
Lista de Materiais
Você precisa adquirir os seguintes componentes para construir este projeto.
Componentes | Descrição | Quantidade | |
---|---|---|---|
1 | Raspberry Pi Pico | RPI Pico Board RP2040 | 1 |
2 | LCD Display | 16×2 I2C LCD Display | 1 |
3 | ProtoBoard | ProtoBoard | 1 |
Breve descrição do display LCD 16X2
O LCD 16×2 tem esse nome porque tem 16 colunas e 2 linhas. Portanto, terá (16×2 = 32) 32 caracteres no total e cada personagem será composto de 5×8 Pixel Dots. Um único personagem com todos os seus pixels é mostrado na imagem abaixo.
Cada personagem tem (5×8 = 40) 40 Pixels e para 32 Personagens teremos (32×40) 1280 Pixels. Além disso, o LCD também deve ser instruído sobre a posição dos pixels. Portanto, será uma tarefa complicada lidar com tudo com a ajuda de um microcontrolador. Portanto, o LCD usa uma interface IC como HD44780. Este IC é montado na parte traseira do Módulo LCD. Você pode verificar a HD44780 Datasheet para mais informações.
A função deste IC é obter os comandos e dados do MCU e processá-los para exibir informações significativas na tela LCD. A tensão de operação do LCD é de 4,7V a 5,3V e o consumo de corrente é de 1mA sem luz de fundo. Pode funcionar no modo de 8 bits e 4 bits Ele também pode exibir quaisquer caracteres gerados de forma personalizada. Esses LCDs estão disponíveis com luz de fundo verde e azul.
Existem dois pinos de seção em todo o módulo LCD 16×2. Alguns deles são pinos de dados e alguns são pinos de comando. De alguma forma, cada pino tem uma função no controle de um único pixel na tela.
Display LCD 16X2 I2C
Este display incorpora uma interface I2C que requer apenas 2 pinos em um microcontrolador para a interface. A interface I2C é uma placa filha conectada à parte traseira do módulo LCD. O endereço I2C para esses monitores é 0x3F ou 0x27.
O adaptador possui um chip de expansão de E/S de 8 bits PCF8574. Este chip converte os dados I2C de um microcontrolador em dados paralelos exigidos pelo display LCD. Há um pequeno trimpot para fazer ajustes finos no contraste da tela. Além disso, há um jumper na placa que fornece energia para a luz de fundo.
Interface de tela LCD 16×2 com Raspberry Pi Pico
Agora, vamos fazer a interface do display LCD 16×2 com o Raspberry Pi Pico. Você pode usar o Fritzing Software para desenhar o esquema. Você pode montar o circuito na placa de ensaio conforme mostrado na imagem abaixo.
Conecte os pinos 1, 5 e 16 do LCD ao GND do Raspberry Pi Pico. Da mesma forma, conecte os pinos 2 e 15 do LCD ao pino 5V, ou seja, Vbus do Raspberry Pi Pico. Conecte os pinos 4, 6, 11, 12, 13, 14 da tela LCD ao pino Raspberry Pi Pico GP16, GP17, GP18, GP19, GP20, GP21.
Para ajustar o contraste do LCD, conecte um potenciômetro de 10K no pino 3 do display LCD.
Código Fonte / Programa
Raspberry Pi Pico oferece suporte ao programa MicroPython para interface de display LCD 16 × 2. Você pode usar Thonny IDE ou uPyCraft IDE para executar o código MicroPython.
Aqui está um código completo para fazer a interface do LCD HD44780 16X2 com o Raspberry Pi Pico. Copie o código para o IDE e salve-o com o nome main.py.
import machine import utime rs = machine.Pin(16,machine.Pin.OUT) e = machine.Pin(17,machine.Pin.OUT) d4 = machine.Pin(18,machine.Pin.OUT) d5 = machine.Pin(19,machine.Pin.OUT) d6 = machine.Pin(20,machine.Pin.OUT) d7 = machine.Pin(21,machine.Pin.OUT) def pulseE(): e.value(1) utime.sleep_us(40) e.value(0) utime.sleep_us(40) def send2LCD4(BinNum): d4.value((BinNum & 0b00000001) >>0) d5.value((BinNum & 0b00000010) >>1) d6.value((BinNum & 0b00000100) >>2) d7.value((BinNum & 0b00001000) >>3) pulseE() def send2LCD8(BinNum): d4.value((BinNum & 0b00010000) >>4) d5.value((BinNum & 0b00100000) >>5) d6.value((BinNum & 0b01000000) >>6) d7.value((BinNum & 0b10000000) >>7) pulseE() d4.value((BinNum & 0b00000001) >>0) d5.value((BinNum & 0b00000010) >>1) d6.value((BinNum & 0b00000100) >>2) d7.value((BinNum & 0b00001000) >>3) pulseE() def setUpLCD(): rs.value(0) send2LCD4(0b0011)#8 bit send2LCD4(0b0011)#8 bit send2LCD4(0b0011)#8 bit send2LCD4(0b0010)#4 bit send2LCD8(0b00101000)#4 bit,2 lines?,5*8 bots send2LCD8(0b00001100)#lcd on, blink off, cursor off. send2LCD8(0b00000110)#increment cursor, no display shift send2LCD8(0b00000001)#clear screen utime.sleep_ms(2)#clear screen needs a long delay setUpLCD() rs.value(1) for x in 'Hello World!': send2LCD8(ord(x))
Portanto, assim que você executar o código, o visor LCD começará a mostrar o Hello World! mensagem no display LCD.
Interface de tela LCD I2C 16×2 com Raspberry Pi Pico
O código acima é válido para display LCD 16×2 sem qualquer módulo I2C. O módulo PCF8574 I2C ou SMBus simplifica a conexão acima. Em vez de usar tantos fios, você pode usar este Módulo IC e converter as linhas de saída de dados apenas para 2 pinos.
Conseqüentemente, o display LCD se torna um display I2C com um endereço I2C de 0x27. A conexão entre o Raspberry Pi Pico e o I2C LCD é muito simples, conforme mostrado no esquema abaixo.
Conecte o VCC do LCD e o pino GND ao Raspberry Pi Pico 5V e o pino GND respectivamente. Conecte o pino SDA e SCL do LCD ao Raspberry Pi Pico GP8 e GP9 respectivamente.
Código Fonte / Programa
O programa desta seção está dividido em 3 partes. Precisamos escrever algum código de driver, bem como código de protocolo I2C para esta parte.
Copie todo esse código e salve todos os 3 códigos no Raspberry Pi Pico Board.
lcd_api.py
import time class LcdApi: LCD_CLR = 0x01 # DB0: limpar exibição LCD_HOME = 0x02 # DB1: retornar à posição inicial LCD_ENTRY_MODE = 0x04 # DB2: definir modo de entrada LCD_ENTRY_INC = 0x02 # --DB1: incremento LCD_ENTRY_SHIFT = 0x01 # --DB0: shift LCD_ON_CTRL = 0x08 # DB3: ligue LCD / cursor LCD_ON_DISPLAY = 0x04 # --DB2: liga a tela LCD_ON_CURSOR = 0x02 # --DB1: liga o cursor LCD_ON_BLINK = 0x01 # --DB0: cursor piscando LCD_MOVE = 0x10 # DB4: mover cursor / exibir LCD_MOVE_DISP = 0x08 # --DB3: mover a tela (0-> mover o cursor) LCD_MOVE_RIGHT = 0x04 # --DB2: mover para a direita (0-> esquerda) LCD_FUNCTION = 0x20 # DB5: conjunto de funções LCD_FUNCTION_8BIT = 0x10 # --DB4: definir modo 8BIT (0-> modo 4BIT) LCD_FUNCTION_2LINES = 0x08 # --DB3: duas linhas (0-> uma linha) LCD_FUNCTION_10DOTS = 0x04 # --DB2: fonte 5x10 (0-> fonte 5x7) LCD_FUNCTION_RESET = 0x30 # Consulte a seção "Inicializando por instrução" LCD_CGRAM = 0x40 # DB6: definir o endereço CG RAM LCD_DDRAM = 0x80 # DB7: definir endereço DD RAM LCD_RS_CMD = 0 LCD_RS_DATA = 1 LCD_RW_WRITE = 0 LCD_RW_READ = 1 def __init__(self, num_lines, num_columns): self.num_lines = num_lines if self.num_lines > 4: self.num_lines = 4 self.num_columns = num_columns if self.num_columns > 40: self.num_columns = 40 self.cursor_x = 0 self.cursor_y = 0 self.implied_newline = False self.backlight = True self.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): """Limpa o visor LCD e move o cursor para o canto superior esquerdo canto. """ self.hal_write_command(self.LCD_CLR) self.hal_write_command(self.LCD_HOME) self.cursor_x = 0 self.cursor_y = 0 def show_cursor(self): """Torna o cursor visível.""" self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY | self.LCD_ON_CURSOR) def hide_cursor(self): """Faz com que o cursor fique oculto.""" self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY) def blink_cursor_on(self): """Liga o cursor e o faz piscar.""" 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): """Liga o cursor e não pisca (ou seja, fica sólido).""" self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY | self.LCD_ON_CURSOR) def display_on(self): """Liga (ou seja, desobstrui) o LCD.""" self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY) def display_off(self): """Desliga (ou seja, apaga) o LCD.""" self.hal_write_command(self.LCD_ON_CTRL) def backlight_on(self): """Liga a luz de fundo. Este não é realmente um comando LCD, mas alguns módulos têm luz de fundo controles, então isso permite que o hal passe pelo comando. """ self.backlight = True self.hal_backlight_on() def backlight_off(self): """Desliga a luz de fundo. Este não é realmente um comando LCD, mas alguns módulos têm luz de fundo controles, então isso permite que o hal passe pelo comando. """ self.backlight = False self.hal_backlight_off() def move_to(self, cursor_x, cursor_y): """Move a posição do cursor para a posição indicada. O cursor a posição é baseada em zero (ou seja, cursor_x == 0 indica a primeira coluna). """ self.cursor_x = cursor_x self.cursor_y = cursor_y addr = cursor_x & 0x3f if cursor_y & 1: addr += 0x40 # Lines 1 & 3 add 0x40 if cursor_y & 2: # Lines 2 & 3 add number of columns addr += self.num_columns self.hal_write_command(self.LCD_DDRAM | addr) def putchar(self, char): """Grava o caractere indicado no LCD no cursor atual posição e avança o cursor uma posição. """ if char == '\n': if self.implied_newline: # self.implied_newline means we advanced due to a wraparound, # so if we get a newline right after that we ignore it. pass else: self.cursor_x = self.num_columns else: self.hal_write_data(ord(char)) self.cursor_x += 1 if self.cursor_x >= self.num_columns: self.cursor_x = 0 self.cursor_y += 1 self.implied_newline = (char != '\n') if self.cursor_y >= self.num_lines: self.cursor_y = 0 self.move_to(self.cursor_x, self.cursor_y) def putstr(self, string): """Escreva a string indicada no LCD no cursor atual posição e avança a posição do cursor apropriadamente. """ for char in string: self.putchar(char) def custom_char(self, location, charmap): """Escreva um personagem para um dos 8 locais CGRAM, disponíveis como chr(0) a chr(7). """ location &= 0x7 self.hal_write_command(self.LCD_CGRAM | (location << 3)) self.hal_sleep_us(40) for i in range(8): self.hal_write_data(charmap[i]) self.hal_sleep_us(40) self.move_to(self.cursor_x, self.cursor_y) def hal_backlight_on(self): """Permite que a camada hal ligue a luz de fundo. Se desejado, uma classe HAL derivada implementará esta função. """ pass def hal_backlight_off(self): """Permite que a camada hal desligue a luz de fundo. Se desejado, uma classe HAL derivada implementará esta função. """ pass def hal_write_command(self, cmd): """Escreva um comando no LCD. Espera-se que uma classe derivada HAL implemente este função. """ raise NotImplementedError def hal_write_data(self, data): """Grave dados no LCD. Espera-se que uma classe derivada HAL implemente este função. """ raise NotImplementedError def hal_sleep_us(self, usecs): """Dormir por algum tempo (dado em microssegundos). """ time.sleep_us(usecs)
pico_i2c_lcd.py
from lcd_api import LcdApi from machine import I2C from time import sleep_ms DEFAULT_I2C_ADDR = 0x27 # Define mudanças ou máscaras para as várias linhas de LCD conectadas ao PCF8574 MASK_RS = 0x01 MASK_RW = 0x02 MASK_E = 0x04 SHIFT_BACKLIGHT = 3 SHIFT_DATA = 4 class I2cLcd(LcdApi): """Implementa um lcd baseado em caracteres conectado via PCF8574 no i2c.""" def __init__(self, i2c, i2c_addr, num_lines, num_columns): self.i2c = i2c self.i2c_addr = i2c_addr self.i2c.writeto(self.i2c_addr, bytearray([0])) sleep_ms(20) # Dê tempo ao LCD para ligar # Enviar reset 3 vezes self.hal_write_init_nibble(self.LCD_FUNCTION_RESET) sleep_ms(5) #precisa atrasar pelo menos 4,1 mseg self.hal_write_init_nibble(self.LCD_FUNCTION_RESET) sleep_ms(1) self.hal_write_init_nibble(self.LCD_FUNCTION_RESET) sleep_ms(1) # Coloque o LCD no modo de 4 bits self.hal_write_init_nibble(self.LCD_FUNCTION) sleep_ms(1) LcdApi.__init__(self, num_lines, num_columns) cmd = self.LCD_FUNCTION if num_lines > 1: cmd |= self.LCD_FUNCTION_2LINES self.hal_write_command(cmd) def hal_write_init_nibble(self, nibble): """Grava um nibble de inicialização no LCD. Esta função específica é usada apenas durante a inicialização. """ byte = ((nibble >> 4) & 0x0f) << SHIFT_DATA self.i2c.writeto(self.i2c_addr, bytearray([byte | MASK_E])) self.i2c.writeto(self.i2c_addr, bytearray([byte])) def hal_backlight_on(self): """Permite que a camada hal ligue a luz de fundo.""" self.i2c.writeto(self.i2c_addr, bytearray([1 << SHIFT_BACKLIGHT])) def hal_backlight_off(self): """Permite que a camada hal desligue a luz de fundo.""" self.i2c.writeto(self.i2c_addr, bytearray([0])) def hal_write_command(self, cmd): """Grava um comando no LCD. Os dados estão travados na borda descendente de 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: # Os comandos home e clear requerem um atraso de pior caso de 4,1 mseg sleep_ms(5) def hal_write_data(self, data): """Grave dados no 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]))
main.py
from pico_i2c_lcd import I2cLcd from machine import I2C from machine import Pin import utime as time i2c = I2C(id=1,scl=Pin(9),sda=Pin(8),freq=100000) lcd = I2cLcd(i2c, 0x27, 2, 16) while True: lcd.move_to(2,0) lcd.putstr('Hello world')
Depois de executar todos esses códigos no Raspberry Pi Pico, o LCD começará a exibir a mensagem Hello World.