3回答

0收藏

[原创] [Raspberry Pi]PCF8574扩展IO口实现I2C转LCD1602(Python)

Raspberry Pi Raspberry Pi 9296 人阅读 | 3 人回复 | 2015-11-26

上次很偶然的秒到了I2C转LCD1602,
秒到IIC控制LCD1602转换版到货啦!
https://www.cirmall.com/bbs/forum ... 45305&fromuid=23447


LCD1602多引脚面对Raspberry Pi 引脚有限的情况,就显得由为重要。

先来来Python 的实现方法,主要是利用python-smbus
方案方法
sudo apt-get install python-smbus
sudo apt-get install i2c-tools


MCP8574 的代码如下Qtgz_PCF8574.py
  1. from Qtgz_I2C import Qtgz_I2C
  2. import smbus
  3. import time

  4. class Qtgz_MCP8574(object):
  5.     OUTPUT = 0
  6.     INPUT = 1

  7.     def __init__(self, address, num_gpios, busnum=-1):
  8.         assert num_gpios >= 0 and num_gpios <= 8, "Number of GPIOs must be between 0 and 16"
  9.         self.i2c = Qtgz_I2C(address=address, busnum=busnum)
  10.         self.address = address
  11.         self.num_gpios = num_gpios

  12.     def _changebit(self, bitmap, bit, value):
  13.         assert value == 1 or value == 0, "Value is %s must be 1 or 0" % value
  14.         if value == 0:
  15.             return bitmap & ~(1 << bit)
  16.         elif value == 1:
  17.             return bitmap | (1 << bit)

  18.     def _readandchangepin(self, pin, value, currvalue = None):
  19.         assert pin >= 0 and pin < self.num_gpios, "Pin number %s is invalid, only 0-%s are valid" % (pin, self.num_gpios)
  20.         #assert self.direction & (1 << pin) == 0, "Pin %s not set to output" % pin
  21.         if not currvalue:
  22.              currvalue = self.i2c.readRaw8()
  23.         newvalue = self._changebit(currvalue, pin, value)
  24.         self.i2c.writeRaw8(newvalue)
  25.         return newvalue

  26.     def config(self, pin, mode):
  27.         if self.num_gpios <= 8:
  28.             self.direction = self._readandchangepin(pin, mode)
  29.         return self.direction

  30.     def output(self, pin, value):
  31.         if self.num_gpios <= 8:
  32.             self.outputvalue = self._readandchangepin(pin, value, self.i2c.readRaw8())
  33.         return self.outputvalue

  34.     def input(self, pin):
  35.         assert pin >= 0 and pin < self.num_gpios, "Pin number %s is invalid, only 0-%s are valid" % (pin, self.num_gpios)
  36.         assert self.direction & (1 << pin) != 0, "Pin %s not set to input" % pin
  37.         if self.num_gpios <= 8:
  38.             value = self.i2c.readRaw8()
  39.         return value & (1 << pin)

  40.     def readU8(self):
  41.         result = self.i2c.readRaw8()
  42.         return(result)

  43.     def readS8(self):
  44.         result = self.i2c.readRaw8()
  45.         if (result > 127): result -= 256
  46.         return result

  47.     def write8(self, value):
  48.         self.i2c.writeRaw8(value)

  49. class PCF8574_GPIO(object):
  50.     OUT = 0
  51.     IN = 1
  52.     BCM = 0
  53.     BOARD = 0
  54.     def __init__(self, busnum, address, num_gpios):
  55.         self.chip = Qtgz_MCP8574(address, num_gpios, busnum)
  56.     def setmode(self, mode):
  57.         # do nothing
  58.         pass
  59.     def setup(self, pin, mode):
  60.         self.chip.config(pin, mode)
  61.     def input(self, pin):
  62.         return self.chip.input(pin)
  63.     def output(self, pin, value):
  64.         self.chip.output(pin, value)

  65. if __name__ == '__main__':
  66.     # ***************************************************
  67.     # Set num_gpios to 8 for MCP8574
  68.     # ***************************************************
  69.     mcp = Qtgz_MCP8574(address = 0x27, num_gpios = 8) # MCP8574

  70.     mcp.config(3, mcp.OUTPUT)

  71.     # Set pin 3 to input with the pullup resistor enabled
  72.     #mcp.config(3, mcp.INPUT)

  73.     # Read input pin and display the results
  74.     #print "Pin 3 = %d" % (mcp.input(3) >> 3)

  75.     # Python speed test on output 3 toggling at max speed
  76.     print "Starting blinky on pin 3 (CTRL+C to quit)"
  77.     while (True):
  78.       mcp.output(3, 1)  # Pin 0 High
  79.       time.sleep(1);
  80.       mcp.output(3, 0)  # Pin 0 Low
  81.       time.sleep(1);
复制代码
LCD1602 的代码
  1. from time import sleep


  2. class Adafruit_CharLCD(object):

  3.     # commands
  4.     LCD_CLEARDISPLAY        = 0x01
  5.     LCD_RETURNHOME          = 0x02
  6.     LCD_ENTRYMODESET        = 0x04
  7.     LCD_DISPLAYCONTROL      = 0x08
  8.     LCD_CURSORSHIFT         = 0x10
  9.     LCD_FUNCTIONSET         = 0x20
  10.     LCD_SETCGRAMADDR        = 0x40
  11.     LCD_SETDDRAMADDR        = 0x80

  12.     # flags for display entry mode
  13.     LCD_ENTRYRIGHT          = 0x00
  14.     LCD_ENTRYLEFT           = 0x02
  15.     LCD_ENTRYSHIFTINCREMENT = 0x01
  16.     LCD_ENTRYSHIFTDECREMENT = 0x00

  17.     # flags for display on/off control
  18.     LCD_DISPLAYON           = 0x04
  19.     LCD_DISPLAYOFF          = 0x00
  20.     LCD_CURSORON            = 0x02
  21.     LCD_CURSOROFF           = 0x00
  22.     LCD_BLINKON             = 0x01
  23.     LCD_BLINKOFF            = 0x00

  24.     # flags for display/cursor shift
  25.     LCD_DISPLAYMOVE         = 0x08
  26.     LCD_CURSORMOVE          = 0x00

  27.     # flags for display/cursor shift
  28.     LCD_DISPLAYMOVE         = 0x08
  29.     LCD_CURSORMOVE          = 0x00
  30.     LCD_MOVERIGHT           = 0x04
  31.     LCD_MOVELEFT            = 0x00

  32.     # flags for function set
  33.     LCD_8BITMODE            = 0x10
  34.     LCD_4BITMODE            = 0x00
  35.     LCD_2LINE               = 0x08
  36.     LCD_1LINE               = 0x00
  37.     LCD_5x10DOTS            = 0x04
  38.     LCD_5x8DOTS             = 0x00

  39.     def __init__(self, pin_rs=25, pin_e=24, pins_db=[23, 17, 21, 22], GPIO=None):
  40.         # Emulate the old behavior of using RPi.GPIO if we haven't been given
  41.         # an explicit GPIO interface to use
  42.         if not GPIO:
  43.             import RPi.GPIO as GPIO
  44.             GPIO.setwarnings(False)
  45.         self.GPIO = GPIO
  46.         self.pin_rs = pin_rs
  47.         self.pin_e = pin_e
  48.         self.pins_db = pins_db

  49.         self.GPIO.setmode(GPIO.BCM) #GPIO=None use Raspi PIN in BCM mode
  50.         self.GPIO.setup(self.pin_e, GPIO.OUT)
  51.         self.GPIO.setup(self.pin_rs, GPIO.OUT)

  52.         for pin in self.pins_db:
  53.             self.GPIO.setup(pin, GPIO.OUT)

  54.         self.write4bits(0x33)  # initialization
  55.         self.write4bits(0x32)  # initialization
  56.         self.write4bits(0x28)  # 2 line 5x7 matrix
  57.         self.write4bits(0x0C)  # turn cursor off 0x0E to enable cursor
  58.         self.write4bits(0x06)  # shift cursor right

  59.         self.displaycontrol = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF

  60.         self.displayfunction = self.LCD_4BITMODE | self.LCD_1LINE | self.LCD_5x8DOTS
  61.         self.displayfunction |= self.LCD_2LINE

  62.         # Initialize to default text direction (for romance languages)
  63.         self.displaymode = self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT
  64.         self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)  # set the entry mode

  65.         self.clear()

  66.     def begin(self, cols, lines):
  67.         if (lines > 1):
  68.             self.numlines = lines
  69.             self.displayfunction |= self.LCD_2LINE

  70.     def home(self):
  71.         self.write4bits(self.LCD_RETURNHOME)  # set cursor position to zero
  72.         self.delayMicroseconds(3000)  # this command takes a long time!

  73.     def clear(self):
  74.         self.write4bits(self.LCD_CLEARDISPLAY)  # command to clear display
  75.         self.delayMicroseconds(3000)  # 3000 microsecond sleep, clearing the display takes a long time

  76.     def setCursor(self, col, row):
  77.         self.row_offsets = [0x00, 0x40, 0x14, 0x54]
  78.         if row > self.numlines:
  79.             row = self.numlines - 1  # we count rows starting w/0
  80.         self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))

  81.     def noDisplay(self):
  82.         """ Turn the display off (quickly) """
  83.         self.displaycontrol &= ~self.LCD_DISPLAYON
  84.         self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)

  85.     def display(self):
  86.         """ Turn the display on (quickly) """
  87.         self.displaycontrol |= self.LCD_DISPLAYON
  88.         self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)

  89.     def noCursor(self):
  90.         """ Turns the underline cursor off """
  91.         self.displaycontrol &= ~self.LCD_CURSORON
  92.         self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)

  93.     def cursor(self):
  94.         """ Turns the underline cursor on """
  95.         self.displaycontrol |= self.LCD_CURSORON
  96.         self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)

  97.     def noBlink(self):
  98.         """ Turn the blinking cursor off """
  99.         self.displaycontrol &= ~self.LCD_BLINKON
  100.         self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)

  101.     def blink(self):
  102.         """ Turn the blinking cursor on """
  103.         self.displaycontrol |= self.LCD_BLINKON
  104.         self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)

  105.     def DisplayLeft(self):
  106.         """ These commands scroll the display without changing the RAM """
  107.         self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)

  108.     def scrollDisplayRight(self):
  109.         """ These commands scroll the display without changing the RAM """
  110.         self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT)

  111.     def leftToRight(self):
  112.         """ This is for text that flows Left to Right """
  113.         self.displaymode |= self.LCD_ENTRYLEFT
  114.         self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)

  115.     def rightToLeft(self):
  116.         """ This is for text that flows Right to Left """
  117.         self.displaymode &= ~self.LCD_ENTRYLEFT
  118.         self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)

  119.     def autoscroll(self):
  120.         """ This will 'right justify' text from the cursor """
  121.         self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT
  122.         self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)

  123.     def noAutoscroll(self):
  124.         """ This will 'left justify' text from the cursor """
  125.         self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT
  126.         self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)

  127.     def write4bits(self, bits, char_mode=False):
  128.         """ Send command to LCD """
  129.         self.delayMicroseconds(1000)  # 1000 microsecond sleep
  130.         bits = bin(bits)[2:].zfill(8)
  131.         self.GPIO.output(self.pin_rs, char_mode)
  132.         for pin in self.pins_db:
  133.             self.GPIO.output(pin, False)
  134.         for i in range(4):
  135.             if bits[i] == "1":
  136.                 self.GPIO.output(self.pins_db[::-1][i], True)
  137.         self.pulseEnable()
  138.         for pin in self.pins_db:
  139.             self.GPIO.output(pin, False)
  140.         for i in range(4, 8):
  141.             if bits[i] == "1":
  142.                 self.GPIO.output(self.pins_db[::-1][i-4], True)
  143.         self.pulseEnable()

  144.     def delayMicroseconds(self, microseconds):
  145.         seconds = microseconds / float(1000000)  # divide microseconds by 1 million for seconds
  146.         sleep(seconds)

  147.     def pulseEnable(self):
  148.         self.GPIO.output(self.pin_e, False)
  149.         self.delayMicroseconds(1)       # 1 microsecond pause - enable pulse must be > 450ns
  150.         self.GPIO.output(self.pin_e, True)
  151.         self.delayMicroseconds(1)       # 1 microsecond pause - enable pulse must be > 450ns
  152.         self.GPIO.output(self.pin_e, False)
  153.         self.delayMicroseconds(1)       # commands need > 37us to settle

  154.     def message(self, text):
  155.         """ Send string to LCD. Newline wraps to second line"""
  156.         for char in text:
  157.             if char == '\n':
  158.                 self.write4bits(0xC0)  # next line
  159.             else:
  160.                 self.write4bits(ord(char), True)


  161. if __name__ == '__main__':
  162.     lcd = Adafruit_CharLCD()
  163.     lcd.clear()
  164.     lcd.message("  Adafruit 16x2\n  Standard LCD")
复制代码
实现代码如下,打印内部温度,内存使用情况
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. from Adafruit_CharLCD import Adafruit_CharLCD
  4. from Qtgz_PCF8574 import PCF8574_GPIO

  5. from subprocess import *
  6. from time import sleep, strftime
  7. from datetime import datetime
  8. import commands


  9. def get_cpu_temp():
  10.     tmp = open('/sys/class/thermal/thermal_zone0/temp')
  11.     cpu = tmp.read()
  12.     tmp.close()
  13.     return '{:.2f}'.format( float(cpu)/1000 ) + ' C'

  14. def get_gpu_temp():
  15.     tmp = commands.getoutput('vcgencmd measure_temp|awk -F= \'{print $2}\'').replace('\'C','')
  16.     gpu = float(tmp)
  17.     return '{:.2f}'.format( gpu ) + ' C'

  18. def get_time_now():
  19.     return datetime.now().strftime('    %H:%M:%S\n   %Y-%m-%d')

  20. def get_ip_info():
  21.     return commands.getoutput('ifconfig wlan0|grep inet|awk -Faddr: \'{print $2}\'|awk \'{print $1}\'')

  22. def get_mem_info():
  23.     total= commands.getoutput('free -m|grep Mem:|awk \'{print $2}\'')  
  24.     free = commands.getoutput('free -m|grep cache:|awk \'{print $4}\'')
  25.     return 'MEM:\n    ' + free +' / '+ total +' M'


  26. bus = 1         # Note you need to change the bus number to 0 if running on a revision 1 Raspberry Pi.
  27. address = 0x27  # I2C address of the PCF8574 chip.
  28. gpio_count = 8  # Number of GPIOs exposed by the PCF8574 chip, should be 8 or 16 depending on chip.

  29. # Create PCF8574 GPIO adapter.
  30. mcp = PCF8574_GPIO(bus, address, gpio_count)
  31. # Create LCD, passing in MCP GPIO adapter.
  32. lcd = Adafruit_CharLCD(pin_rs=0, pin_e=2, pins_db=[4,5,6,7], GPIO=mcp)


  33. if __name__ == '__main__':

  34.     while(1):
  35.         lcd.clear()
  36.         lcd.message( get_ip_info() )
  37.         sleep(1)
  38.          
  39.         lcd.clear()
  40.         lcd.message( get_time_now() )
  41.         sleep(1)
  42.          
  43.         lcd.clear()
  44.         lcd.message( get_mem_info() )
  45.         sleep(1)

  46.         lcd.clear()
  47.         lcd.message( 'CPU: ' + get_cpu_temp()+'\n' )
  48.         lcd.message( 'GPU: ' + get_gpu_temp() )
  49.         sleep(1)
复制代码
效果如下




分享到:
回复

使用道具 举报

回答|共 3 个

倒序浏览

沙发

斑斑

发表于 2015-11-27 09:07:29 | 只看该作者

楼主真厉害,用C语言和Python都实现了!
板凳

陆小六小六

发表于 2016-6-26 14:16:29 | 只看该作者

请问lZ,from Qtgz_I2C import Qtgz_I2C这个模块在哪里啊。。
地板

盛京老驴

发表于 2016-9-12 22:38:07 | 只看该作者

I2C很神奇的,只是我是硬件小白!!!
您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条