27 dezembro 2016

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.

Display LCD 16x2 I2C Raspberry Pi

Nós já falamos em um post anterior como ligar o display LCD 16x2 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:
Módulo LCD I2C

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.

LCD 16x2 com módulo I2C

Conexão do LCD I2C no Raspberry Pi


Na imagem abaixo temos o esquema de conexão do display LCD I2C 16x2 no 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.

Circuito Raspberry Pi 3 e Display LCD I2C

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:

Tela Principal Raspi-config


Vá até a opção 5 (Interfacing Options), depois selecione a opção P5 I2C, que vai habilitar a interface I2C no Raspbian:

Raspi-Config I2C


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

i2cdetect Raspberry Pi

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 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

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# -*- 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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#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.

Display LCD 16x2 I2C Informações Iniciais

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.

3 comentários: