Como usar um display LCD I2C com Raspberry Pi
Faz tempo que não falamos de Raspberry Pi aqui no Arduino e Cia… e vamos voltar com um assunto que deve interessar muita gente: como usar um display LCD I2C com Raspberry Pi.
Nós já falamos em um post anterior como ligar o display LCD 16×2 no Raspberry Pi utilizando a conexão normal que no total tem 12 fios ligados no display: controle, alimentação e ajuste de contraste com potenciômetro. Com um display LCD I2C, você usa apenas dois pinos de alimentação e os dois pinos I2C (SDA e SCL) para conexão.
O display LCD I2C
O display LCD I2C é um display comum com um módulo como esse da imagem abaixo soldado na parte de trás:
Esse módulo faz a conexão entre o sinal I2C recebido do microcontrolador/processador e os 16 pinos do display, facilitando a conexão física, já que usamos somente 4 pinos, e deixando o circuito muito mais “limpo”, além de eliminar eventuais erros de conexão.
Conexão do display I2C na Raspberry Pi
Na imagem abaixo temos o esquema de conexão do display LCD I2C 16×2 na Raspberry Pi 3. Note que entre o display e os pinos da GPIO do Raspberry usamos um conversor de nível lógico bidirecional, já que o display trabalha com tensão de 5V e os pinos do Raspberry trabalham com 3.3V.
Finalizada a montagem, vamos passar para a parte de configuração do Raspbian.
Atualização e configuração do Raspbian
Antes de instalar os pacotes necessários para uso da interface I2C no RPi, vamos atualizar o Sistema Operacional:
sudo apt-get update sudo apt-get upgrade
Esse processo pode demorar um pouco, mas é sempre indicado para garantir que temos a última versão dos pacotes do Raspbian.
Primeiramente, vamos habilitar a interface I2C no Raspbian. Abra uma janela de terminal e execute o comando sudo raspi-config, que vai apresentar a tela abaixo:
Vá até a opção 5 (Interfacing Options), depois selecione a opção P5 I2C, que vai habilitar a interface I2C no Raspbian:
Reinicie o sistema operacional.
Agora vamos instalar o I2C-Tools e o smbus. Com eles vamos utilizar o barramento I2C com Python e também descobrir o endereço I2C do display conectado ao Raspberry. Use os comandos abaixo:
sudo apt-get install i2c-tools sudo apt-get install python-smbus
Para mostrar o endereço I2C do nosso display, execute o comando
i2cdetect -y 1
O endereço do nosso display é 27, conforme destacado na imagem acima. Esse endereço deve ser posteriormente configurado na biblioteca que vamos utilizar no programa.
Programa Python display LCD I2C
Antes do programa de teste vamos criar um arquivo chamado I2C_LCD_driver.py e colocar dentro dele o código abaixo, que é a biblioteca I2C (créditos DenisFromHR).
Modifique a linha 22 para que contenha o endereço I2C do seu display, obtido no passo anterior. No nosso caso, o endereço é 27 e a linha ficou assim:
ADDRESS = 0x27
# -*- coding: utf-8 -*- # Original code found at: # https://gist.github.com/DenisFromHR/cc863375a6e19dce359d """ Compiled, mashed and generally mutilated 2014-2015 by Denis Pleic Made available under GNU GENERAL PUBLIC LICENSE # Modified Python I2C library for Raspberry Pi # as found on http://www.recantha.co.uk/blog/?p=4849 # Joined existing 'i2c_lib.py' and 'lcddriver.py' into a single library # added bits and pieces from various sources # By DenisFromHR (Denis Pleic) # 2015-02-10, ver 0.1 """ # i2c bus (0 -- original Pi, 1 -- Rev 2 Pi) I2CBUS = 1 # LCD Address ADDRESS = 0x27 import smbus from time import sleep class i2c_device: def __init__(self, addr, port=I2CBUS): self.addr = addr self.bus = smbus.SMBus(port) # Write a single command def write_cmd(self, cmd): self.bus.write_byte(self.addr, cmd) sleep(0.0001) # Write a command and argument def write_cmd_arg(self, cmd, data): self.bus.write_byte_data(self.addr, cmd, data) sleep(0.0001) # Write a block of data def write_block_data(self, cmd, data): self.bus.write_block_data(self.addr, cmd, data) sleep(0.0001) # Read a single byte def read(self): return self.bus.read_byte(self.addr) # Read def read_data(self, cmd): return self.bus.read_byte_data(self.addr, cmd) # Read a block of data def read_block_data(self, cmd): return self.bus.read_block_data(self.addr, cmd) # 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 # flags for backlight control LCD_BACKLIGHT = 0x08 LCD_NOBACKLIGHT = 0x00 En = 0b00000100 # Enable bit Rw = 0b00000010 # Read/Write bit Rs = 0b00000001 # Register select bit class lcd: #initializes objects and lcd def __init__(self): self.lcd_device = i2c_device(ADDRESS) self.lcd_write(0x03) self.lcd_write(0x03) self.lcd_write(0x03) self.lcd_write(0x02) self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE) self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON) self.lcd_write(LCD_CLEARDISPLAY) self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT) sleep(0.2) # clocks EN to latch command def lcd_strobe(self, data): self.lcd_device.write_cmd(data | En | LCD_BACKLIGHT) sleep(.0005) self.lcd_device.write_cmd(((data & ~En) | LCD_BACKLIGHT)) sleep(.0001) def lcd_write_four_bits(self, data): self.lcd_device.write_cmd(data | LCD_BACKLIGHT) self.lcd_strobe(data) # write a command to lcd def lcd_write(self, cmd, mode=0): self.lcd_write_four_bits(mode | (cmd & 0xF0)) self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0)) # write a character to lcd (or character rom) 0x09: backlight | RS=DR< # works! def lcd_write_char(self, charvalue, mode=1): self.lcd_write_four_bits(mode | (charvalue & 0xF0)) self.lcd_write_four_bits(mode | ((charvalue << 4) & 0xF0)) # put string function with optional char positioning def lcd_display_string(self, string, line=1, pos=0): if line == 1: pos_new = pos elif line == 2: pos_new = 0x40 + pos elif line == 3: pos_new = 0x14 + pos elif line == 4: pos_new = 0x54 + pos self.lcd_write(0x80 + pos_new) for char in string: self.lcd_write(ord(char), Rs) # clear lcd and set to home def lcd_clear(self): self.lcd_write(LCD_CLEARDISPLAY) self.lcd_write(LCD_RETURNHOME) # define backlight on/off (lcd.backlight(1); off= lcd.backlight(0) def backlight(self, state): # for state, 1 = on, 0 = off if state == 1: self.lcd_device.write_cmd(LCD_BACKLIGHT) elif state == 0: self.lcd_device.write_cmd(LCD_NOBACKLIGHT) # add custom characters (0 - 7) def lcd_load_custom_chars(self, fontdata): self.lcd_write(0x40); for char in fontdata: for line in char: self.lcd_write_char(line)
Agora vamos criar um outro programa, que é o teste do display. Utilize o código abaixo:
#Programa: Display LCD I2C com Raspberry Pi #Autor: Arduino e Cia import I2C_LCD_driver import socket import fcntl import struct import time lcdi2c = I2C_LCD_driver.lcd() #Exibe informacoes iniciais lcdi2c.lcd_display_string("Arduino e Cia", 1,1) lcdi2c.lcd_display_string("LCD I2C e RPi", 2,1) time.sleep(4) #Apaga o display lcdi2c.lcd_clear() def get_ip_address(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) return socket.inet_ntoa(fcntl.ioctl( s.fileno(), 0x8915, struct.pack('256s', ifname[:15]) )[20:24]) #Mostra o endereco IP lcdi2c.lcd_display_string("IP", 1) lcdi2c.lcd_display_string(get_ip_address('wlan0'), 1,3) while True: #Mostra a data no display lcdi2c.lcd_display_string("Data: %s" %time.strftime("%d/%m/%y"), 2,1)
O programa carrega as bibliotecas necessárias para acessar o display, mostrar as informações iniciais e depois o endereço IP da placa Raspberry Pi e a data atual do sistema.
Para posicionar o texto no display, utilize os 2 parâmetros numéricos, como na linha 14:
lcdi2c.lcd_display_string(“LCD I2C e RPi”, 2,1)
O valor 2 corresponde à linha do display (linha 2, inferior), e o número 1 corresponde à coluna, lembrando que as colunas são numeradas de 0 a 15.
Gostou? Confira outros posts com Raspberry Pi aqui mesmo no Arduino e Cia!
Ótimo post de férias!
Obrigado Maria! 🙂
Adilson
vocês são feras !!!!!!!!!
Tem como ligar o display com I2C sem o conversor de nível?
Oi Daniel,
Eu já liguei direto mas não recomendo. Como a comunicação é bidirecional, sugiro o uso sim. Você também pode fazer um divisor de tensão usando resistores. Procure por "calculadora" aqui no blog para ver como fazer.
Abraço!
Adilson
Daniel, você pode ligar diretamente sem precisar de divisores de tensão ou conversores lógicos. Porém, terá que remover na placa do LCD I2C os dois resistores de pull-up das linhas SDA e SCL. Mas como o Arduino e Cia falou, não é recomendável.
Boa noite, realizei essa instalação, porém, o lcd só fica acesso, e não escreve nada na tela.
Rodando o comando i2cdetect me retornou o endereço 3f (o que acho muito estranho).
Poderiam me ajudar?
Queridos, bom dia!
Eu queria programar alguns caracteres especiais (smiles), nas posicoes 0 e 1 (um triste e um feliz). Já tenho a definicao das linhas em binário (8linhas de 5bits cada). Sei fazer no Arduino, la uso o "lcd.createchar" onde parametrizo o caractere e já passo o array de 8×5. Depois, só usar o lcd.write (ao inves do lcd.print) para mandar pro LCD.
Olhando o python acima, vi que tem o Add custom char (load_custom+_char), mas não entendi como consigo criar os caracteres. Entendo que para lançar ao LCD, uso o lcd_write_char, com código 0 e 1, mas não como criar os caracteres.
Tem como montar um exemplo de criação e impressão destes caracterez customizados?
Boa noite,
Boa pergunta. rs. Mas acho que esse post aqui pode te ajudar:
https://stackoverflow.com/questions/30017357/create-custom-character-on-lcd-20×4-using-python-code
Abraço!
Adilson
[…] Gostou deste post com módulo I2C e RTC DS1307? Veja também o post onde mostro como ligar um display LCD 16×2 I2C na Raspberry Pi! […]
Não conseguir fazer o program teste reconhecer o arquivo /home/pi/Documents/Dysplay-I2C.py como biblioteca.
File “/home/pi/Documents/Dysplay-I2C/dysplay.py”, line 4, in
import I2C_LCD_driver
ImportError: No module named ‘I2C_LCD_driver’
Oi Henrique,
A biblioteca foi importada corretamente?
Abraço!
Adilson