RaspberryPi 由I2C总线通过PCF8574控制 LCD1602的Python3及C代码

Sad news (see http://wiringpi.com/wiringpi-deprecated/) .

Talk is cheap, here is the code.

 

PCF8574ForLCD1602.py

# -*- coding: utf-8 -*-
"""
Python3 Code for LCD1602 Control via PCF8574

Created on Tue Aug 20 10:21:33 2019

@author: Farman
"""

import smbus
import time

'''
Hardware Connection

LCD1602  PCF8574T
-----------------
01 - VSS 
02 - VDD
03 -- V0
04 -- RS 04 - P0 : 0 - command  1 - data
05 -- RW 05 - P1 : 0 - write    1 - read
06 --- E 06 - P2 : rising  edge - data set to bus
                   falling edge - data read/write trig
07 -- D0 
08 -- D1
09 -- D2
10 -- D3
11 -- D4 09 - P4
12 -- D5 10 - P5
13 -- D6 11 - P6
14 -- D7 12 - P7
15 --- A
16 --- K

Python3 module smbus is used for I2C communication.

Use "sudo raspi-config" to enable I2C interface.

Use "sudo apt install python3-smbus, i2c-tools" to install smbus module
of python3 and make command "i2cdetect" ready. 

I2C address of PCF8574 is hardware configurable,
use "i2cdetect -y 1" for PCF8574 address detection 
after correct hardware connection.

I2C bus related pins (physical name) of RaspberryPi:
    pin 1 - 3.3V
        2 - 5.0V
        3 - SDA of I2C bus
        4 - 5.0V
        5 - SCL of I2C bus
        6 - GND
        
Adjust the LCD contrast risistor first for perfect display after LCD power-on.
'''

class PCF8574ForLCD1602:
    def __init__(self, bus=1, addr=0x27):
        self.bus   = bus
        self.smbus = smbus.SMBus(self.bus)
        self.addr  = addr
        return
    
    
    def write_command_byte(self, byte):
        def write_half_command_byte(smbus, half_byte):
            i2c_data = (half_byte<<4) & 0xF0 # RS = RW = E = 0
            smbus.write_byte(self.addr, i2c_data)
            time.sleep(0.001)
            
            i2c_data |= 0x04 # RS = RW = 0, E = 1
            smbus.write_byte(self.addr, i2c_data)
            time.sleep(0.001)
            
            i2c_data ^= 0x04 # RS = RW = 0, E = 1
            smbus.write_byte(self.addr, i2c_data)
            time.sleep(0.001)        
            return
    
        write_half_command_byte(self.smbus, byte >> 4) # high half-byte
        write_half_command_byte(self.smbus, byte)      # low  half_byte
        return
    
    
    def write_command_bytes(self, command_bytes):
        for byte in command_bytes:
            #print('Output:', hex(byte))
            self.write_command_byte(byte)
        return
        
    
    def write_data_byte(self, byte):
        def write_half_data_byte(smbus, half_byte):
            i2c_data = (half_byte<<4) & 0xF0 # RS = RW = E = 0
            i2c_data |= 0x01
            smbus.write_byte(self.addr, i2c_data)
            
            i2c_data |= 0x04 # RS = RW = 0, E = 1
            smbus.write_byte(self.addr, i2c_data)
            
            i2c_data ^= 0x04 # RS = RW = 0, E = 1
            smbus.write_byte(self.addr, i2c_data)
            return
           
        write_half_data_byte(self.smbus, byte >> 4) # high half-byte
        write_half_data_byte(self.smbus, byte)      # low  half_byte
        return
    
    
    def write_data_bytes(self, byte_list):
        for byte in byte_list:
            self.write_data_byte(byte)
        return


if __name__ == '__main__':
    pcf8574 = PCF8574ForLCD1602()
    
    bus_width=4
    lines=2
    font_big=0
    
    display_on=1
    cursor_on=0
    blink_on=0
    display_entire_shift_on=1
    display_shift_increase=1
    
    commands =  [0x02, # set bus width 
                 0x20 + (0x10 if bus_width==8 else 0x00) + (0x08 if lines==2 else 0x00) + (0x04 if font_big else 0x00), # function set
                 0x08 + (0x04 if display_on else 0x00) + (0x02 if cursor_on else 0x00) + (0x01 if blink_on else 0x00),
                 0x01,
                 0x06,
                        ]
    pcf8574.write_command_bytes(commands)
    
    pcf8574.write_command_byte(0x80)
    pcf8574.write_data_bytes("1234567890".encode())

LCD1602.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
LCD1602 Display Control in Python3 on RaspberryPi

Created on Tue Aug 20 10:21:33 2019

@author: Farman
"""
from PCF8574ForLCD1602 import PCF8574ForLCD1602 as pcf8574
import time

'''
Commands of HD44780/KS0066(Controller of LCD1602)
------------------------------------------------
clear display 0x01

return home   0x02

entry mode    0x04 + ID*2 + S
                      |     |: 1 - entire shift on  0 - entire shift off
                      |
                      |: 1-increment 0 - decrement
                     
display on/off 0x08 + D*4 + C*2 + B
                      |     |     |: blink of cursor, 1 - on  0 - off
                      |     |
                      |     |: cursor on/off, 1 - on  0 - off
                      |
                      |: entire display on/off, 1 - on  0- off
                      
cursor/display shift 0x10 + SC*8 + RL*4
                             |     |: 1-shift to right 0-shift to left
                             |
                             |: 1-display shift 2-cursor move
                            
function set 0x20 + DL*0x10 + N*8 + F*4
                     |        |     F: 1 - 5*10dots 0-5*8 dots
                     |        N: 1 - 2 lines  0 - 1 lines
                    DL: 1 - 8-bit bus  0 - 4-bit bus
                    
set CGRAM address 0x40 + addr (6-bit width)
set DDRAM address 0x80 + addr (7-bit width)
read buzy flag and address : RS=0, RW=1
write data to CG or DDRAM : RS=1, RW=0
read data from CG or DDRAM: RS=1, RW=1


For any character LCD display module with cotroller compatible with
HD44780 and/or KS0066, such as LCD2002, LCD2402, LCD4002 and LCD4004,
this code should could be used with perfect hardware parameter configuration.
'''

class LCD1602:
    def __init__(self, communicator):
        self.communicator = communicator
        self.lines = 2
        return
    
    def reset(self, bus_width=4, lines=2, font_big=0,
                    display_on=1, cursor_on=0, blink_on=0,
                    display_entire_shift_on=0, display_shift_increase=1):
        '''
        bus_width : 8 - 8-bit,  else - 4-bit
        lines     : 2 - 2-line, else - 1-line
        font_big  : 1 - 5*10,   else - 5*8

        display_on: 1 - on, else off
        cursor_on : 1 - on, else off
        blink_on  : 1 - on, else off
        
        display_entire_shift_on : 1 - on, else off
        display_shift_increase  : 1 - on, else off
        '''
        self.lines = lines
        
        self.communicator.write_command_bytes(
                [0x02, # set bus width 
                 0x20 + (0x10 if bus_width==8 else 0x00) + (0x08 if lines==2 else 0x00) + (0x04 if font_big else 0x00), # function set
                 0x08 + (0x04 if display_on else 0x00) + (0x02 if cursor_on else 0x00) + (0x01 if blink_on else 0x00), # display cursor set
                 0x01, # clear display
                 0x04 + (0x01 if display_entire_shift_on else 0x00) + (0x02 if display_shift_increase else 0x01), # entry mode
                        ])
    
        if self.lines == 1:
            self.write_string(0, 0, "LCD1602 DISPLAY Farman@2019")
        else:
            self.write_string(0, 0, "LCD1602  DISPLAY")
            self.write_string(1, 0, "Farman@20190820*")
            
        time.sleep(3)
        self.clear_all()
    
    
    def write_string(self, line, column, string):
        '''
        line   : 0 - the upper line, else the lower line (2-line mode)
        column : the first column to write string, value should be
                 [0, 80) for 1-line mode
                 [0, 40) for 2-line mode
        '''
        line = min(line, 1)
        data = string.encode()

        if self.lines == 1:
            column = min(column, 79)
            addr = column
            data = data[:min(len(data), 79-column)]
        else:
            column = min(column, 39)
            addr = line * 0x40 + column
            data = data[:min(len(data), 39-column)]
        
        self.communicator.write_command_byte(0x80|addr)
        self.communicator.write_data_bytes(string.encode())
        return
    
    
    def clear_line(self, line):
        '''
        line : 0 - the upper line, else the lower line (2-line mode)
        '''
        self.write_string(line, 0, ' '*20)
        return
    
    
    def clear_all(self):
        '''
        Clear all display.
        '''
        self.communicator.write_command_byte(0x01)
        return


if __name__ == '__main__':
    communicator = pcf8574()
    lcd = LCD1602(communicator)
    lcd.reset()
    lcd.clear_all()
    lcd.write_string(0, 0, '123456789jhu0')
    
    while True:
        for line in range(2):
            for column in range(16):
                lcd.clear_all()
                lcd.write_string(line, column, '#')
                lcd.write_string(0, 0, "%s %s"%(line, column))
                time.sleep(0.2)
        break
    
    if lcd.lines == 1:
        lcd.write_string(0, 0, "LCD1602 DISPLAY Farman@2019")
    else:
        lcd.write_string(0, 0, "LCD1602  DISPLAY")
        lcd.write_string(1, 0, "Farman@20190820*")
    
    time.sleep(1)
    
    lcd.clear_line(0)
    time.sleep(1)
    
    lcd.clear_line(1)
    time.sleep(1)
    
    if lcd.lines == 1:
        lcd.write_string(0, 0, "LCD1602 DISPLAY Farman@2019")
    else:
        lcd.write_string(0, 0, "LCD1602  DISPLAY")
        lcd.write_string(1, 0, "Farman@20190820*")
        
    time.sleep(1)
    lcd.clear_all()
    
            

pcf8574.h

#ifndef __PCF8574_H__
#define __PCF8574_H__

#include     // in /usr/include
#include  // in /usr/include

/*
    device_addr :
        I2C addr of PCF8574, which is hardware configurable.
        
        Use "sudo raspi-config" to enable I2C interface.

        Use "sudo apt install i2c-tools" to make command "i2cdetect" ready. 

        I2C address of PCF8574 is hardware configurable,
        use "i2cdetect -y 1" for PCF8574 address detection 
        after correct hardware connection.
*/
int  pcf8574_init(int device_addr);

/*
    device is get by pcf8574_init().
    Low half of half_byte is actual value send.
*/
void pcf8574_write_half_command_byte(int device, char half_byte);

/*
    device is get by pcf8574_init().
*/
void pcf8574_write_command_byte(int device, char byte);

/*
    device is get by pcf8574_init().
    bytes[] contains bytes to send.
    n is length in byte of bytes[].
*/
void pcf8574_write_command_bytes(int device, char bytes[], int n);

/*
    device is get by pcf8574_init().
    Low half of half_byte is actual value send.
*/
void pcf8574_write_half_data_byte(int device, char half_byte);

/*
    device is get by pcf8574_init().
*/
void pcf8574_write_data_byte(int device, char byte);

/*
    device is get by pcf8574_init().
    bytes[] contains bytes to send.
    n is length in byte of bytes[].
*/
void pcf8574_write_data_bytes(int device, char bytes[], int n);

#endif // #ifndef __PCF8574_H__

pcf8574.c

#include 
#include "pcf8574.h"

int pcf8574_init(int device_addr)
{
    wiringPiSetupGpio();
    return wiringPiI2CSetup(device_addr);
}


void pcf8574_write_half_command_byte(int device, char half_byte)
{
    half_byte <<= 4;
    wiringPiI2CWrite(device, half_byte);
    usleep(50);

    half_byte |= 0x04;
    wiringPiI2CWrite(device, half_byte);
    usleep(50);

    half_byte ^= 0x04;
    wiringPiI2CWrite(device, half_byte);
    usleep(50);
    return;
}


void pcf8574_write_command_byte(int device, char byte)
{
    pcf8574_write_half_command_byte(device, byte>>4);
    pcf8574_write_half_command_byte(device, byte);
    usleep(50);
    return;
}


void pcf8574_write_command_bytes(int device, char bytes[], int n)
{
    int i;

    for(i=0; i>4);
    pcf8574_write_half_data_byte(device, byte);
    return;
}


void pcf8574_write_data_bytes(int device, char bytes[], int n)
{
    int i;

    for(i=0; i

pcf8574_test.c


#include 
#include "pcf8574.h"

int main()
{
    int device;

    device = init();

    if (device < 0)
    {
        printf("I2C bus initialize failed ---.\n");
        return 0;
    }

    int bus_width = 4;
    int lines = 2;
    int font_big = 0;

    int display_on = 1;
    int cursor_on = 0;
    int blink_on = 0;

    int display_entire_on = 1;
    int display_shift_increase = 1;

    char command;
    
    write_command_byte(device, 0x02);

    command = 0x20;
    command += bus_width==8 ? 0x10 : 0x00;
    command += lines==2 ? 0x08 : 0x00;
    command += font_big==1 ? 0x04 : 0x00;
    write_command_byte(device, command);

    command = 0x08;
    command += display_on==1 ? 0x04 : 0x00;
    command += cursor_on==1 ? 0x02 : 0x00;
    command += blink_on==1 ? 0x01 : 0x00;
    write_command_byte(device, command);

    write_command_byte(device, 0x01);

    command = 0x04;
    command += display_entire_on==1 ? 0x02 : 0x00;
    command += display_shift_increase==1 ? 0x01 : 0x00;
    write_command_byte(device, command);

    write_data_bytes(device, "01234567890!", 12);

    return 0;
}

lcd1602.h

#include 
#include 
#include 
#include "pcf8574.h"
/*
CONNECTIONS OF

LCD1602  PCF8574T
-----------------
01 - VSS 
02 - VDD
03 -- V0
04 -- RS 04 - P0 
05 -- RW 05 - P1
06 --- E 06 - P2
07 -- D0 
08 -- D1
09 -- D2
10 -- D3
11 -- D4 09 - P4
12 -- D5 10 - P5
13 -- D6 11 - P6
14 -- D7 12 - P7
15 --- A
16 --- K
*/

/*
    hold the parameter of LCD1602 display lines,
    which is used by hd44780_write_string().
*/
int hd44780_display_lines;

/*
    device_addr :
        I2C addr of PCF8574, which is hardware configurable.
        
        Use "sudo raspi-config" to enable I2C interface.

        Use "sudo apt install i2c-tools" to make command "i2cdetect" ready. 

        I2C address of PCF8574 is hardware configurable,
        use "i2cdetect -y 1" for PCF8574 address detection 
        after correct hardware connection.
    
    return device id for further operation by other functions.
*/
int hd44780_init(int device_addr);

void hd44780_reset(
    int device, // get by hd44780_init()

    int bus_width, // 8 - 8-bit bus, 4 - 4-bit bus 
    int lines,     // 1 - 1-line, 2 - 2-line, depend on LCD hardware.
    int font_big,  // 1 - 8*10 font, 0 - 5*8 font

    int display_on, // 1 - entire display on, 0 - entire display off
    int cursor_on,  // 1 - cursor on, 0 - cursor off
    int blink_on,   // 1 - cursor blink on, 0 - cursor blink off.

    int display_entire_shift_on, // entire display shift : 1 - on, 0 - off
    int display_shift_increase   // DDRAM address (cursor or blink): 1 - increase 0 -decrease
);


void hd44780_write_string(
    int device, // get by hd44780_init()
    int line,   // write to which line. If hd44780_display_lines==1, this parameter is ignored.
    int column, // write to which column, max column is 39 for hd44780_display_lines==2, else 79.
    char string[], // buffer contains string to write.
    int str_len    // buffer length in byte.
);

/*
    device : get by hd44780_init()
    line   : which line to clear, 1 or 2. If hd44780_display_lines==1, this parameter is ignored.
*/
void hd44780_clear_line(int device, int line);

/*
    device : get by hd44780_init()
    Clear all display.
*/
void hd44780_clear_all(int device);

lcd1602.c

#include "lcd1602.h"

/*
    device_addr :
        I2C addr of PCF8574, which is hardware configurable.
        
        Use "sudo raspi-config" to enable I2C interface.

        Use "sudo apt install i2c-tools" to make command "i2cdetect" ready. 

        I2C address of PCF8574 is hardware configurable,
        use "i2cdetect -y 1" for PCF8574 address detection 
        after correct hardware connection.
*/
int hd44780_init(int device_addr)
{
    return pcf8574_init(device_addr);
}


void hd44780_reset(
    int device, 

    int bus_width,
    int lines,
    int font_big,

    int display_on,
    int cursor_on,
    int blink_on,

    int display_entire_shift_on,
    int display_shift_increase
)
{
    hd44780_display_lines = lines;

    char command;
    
    pcf8574_write_command_byte(device, 0x02);

    command = 0x20;
    command += bus_width==8 ? 0x10 : 0x00;
    command += lines==2 ? 0x08 : 0x00;
    command += font_big==1 ? 0x04 : 0x00;
    pcf8574_write_command_byte(device, command);

    command = 0x08;
    command += display_on==1 ? 0x04 : 0x00;
    command += cursor_on==1 ? 0x02 : 0x00;
    command += blink_on==1 ? 0x01 : 0x00;
    pcf8574_write_command_byte(device, command);

    pcf8574_write_command_byte(device, 0x01);
    usleep(50000);

    command = 0x04;
    command += display_entire_shift_on==1 ? 0x02 : 0x00;
    command += display_shift_increase==1 ? 0x01 : 0x00;
    pcf8574_write_command_byte(device, command);

    return;
}


void hd44780_write_string(
    int device,
    int line,
    int column,
    char string[],
    int str_len
)
{
    int addr;

    line = line < 1 ? line : 1;
    
    if (hd44780_display_lines == 1)
    {
        column = column < 79 ? column : 79;
        str_len = str_len < 79 - column ? str_len : 79 - column;
        addr = column;
    }
    else
    {
        column = column < 39 ? column : 39;
        str_len = str_len < 39 - column ? str_len : 39 - column;;
        addr = line * 0x40 + column;
    }

    pcf8574_write_command_byte(device, 0x80 | addr);
    pcf8574_write_data_bytes(device, string, str_len);
    return;
}


void hd44780_clear_line(int device, int line)
{
    char blanks[80];
    int n;

    for (n=0; n<80; ++n)
    {
        blanks[n] = 0x20; // ' '
    }

    hd44780_write_string(device, line, 0, blanks, 80);
    return;
}


void hd44780_clear_all(int device)
{
    pcf8574_write_command_byte(device, 0x01);
    usleep(1600);
    return;
}

lcd1602_test.c

#include "lcd1602.h"

int main()
{
    int device = hd44780_init(0x27);

    if (device < 0)
    {
        printf("Init PCF8574 Failed.");
        return 0;
    }

    hd44780_reset(device, 4, 2, 1, 1, 0, 0, 1, 0);
    hd44780_clear_all(device);
    hd44780_write_string(device, 0, 0, "Too young,      ", 16);
    hd44780_write_string(device, 1, 0, "Too naive, boy!!", 16);
    //return 0;
    sleep(2);
    hd44780_clear_all(device);

    int n;
    char buf[40];

    for (n=0; n<64; ++n)
    {
        sprintf(buf, "%016X", n);
        hd44780_write_string(device, 1, 0, buf, strlen(buf));
        usleep(50000);
    }


    return 0;
}

command for compile and run

rm pcf
gcc -Wall -o pcf pcf8574.c lcd1602.c lcd1602_test.c -lwiringPi
./pcf

That's all.

你可能感兴趣的:(硬件,开源,树莓派,raspberry,pi,python,硬件,显示,PCF8574,LCD1602,RaspberryPi,I2C)