树莓派通过C语言和python操作LCD液晶屏

    今天实验树莓派通过 I2C 驱动操作 LCD1602 液晶屏,屏幕带I2C 方式的驱动模块,可以极大的简化接线和驱动程序。本文利用C语言和python来实验操作LCD1602液晶屏,python程序方面分别显示字符串,IP地址,树莓派状态信息,功能更加丰富。特别是lcd_status.py程序设置为开机启动,那么树莓派的IP地址、状态都可以一目了然。作为可视化界面,当然也可以显示任何你需要的信息。

    今晚搞了一晚,主要有三个地方花了时间。

    一是模块上有一颗可调电阻,用于调节显示的对比度,如果你的屏幕无论怎么调试都不见显示,记得调节一下这里,这个问题纠结了我好久才发现!!!

    二是运行python程序时,没有把float浮点数转换成字符串str,LCD不能写入浮点数。

    三是树莓派要开启I2C功能。

1、接线图

GND --- GND       VCC --- 接树莓派 3.3V

SDA --- I2C 数据   SCL --- I2C 时钟

2、启用树莓派的I2C功能

可以通过sudo raspi-config命令来开启,也可以VNC到树莓派来可视化开启。

运行命令看一下是否识别到屏幕, 地址为0x27,这说明已经成功连接了 LCD1602 屏幕。

sudo i2cdetect -y 1

3、C语言操作LCD  lcd.c

#include <wiringPi.h>

#include <stdio.h>

#include <sys/time.h>

#include <wiringPiI2C.h>

#include <string.h>


int LCDAddr = 0x27;

int BLEN = 1;

int ad;


void write_word(int data){

         inttemp = data;


         if(BLEN== 1)

            temp |= 0x08;

         else

            temp &= 0xF7;

         wiringPiI2CWrite(ad,temp);

}


void send_command(int comm){

         intbuf;

         buf= comm & 0xF0;

         buf|= 0x04;

         write_word(buf);

         delay(2);

         buf&= 0xFB;

         write_word(buf);


         buf= (comm & 0x0F) << 4;

         buf|= 0x04;

         write_word(buf);

         delay(2);

         buf&= 0xFB;

         write_word(buf);

}


void send_data(int data){

         intbuf;

         buf= data & 0xF0;

         buf|= 0x05;

         write_word(buf);

         delay(2);

         buf&= 0xFB;

         write_word(buf);


         buf= (data & 0x0F) << 4;

         buf|= 0x05;

         write_word(buf);

         delay(2);

         buf&= 0xFB;

         write_word(buf);

}

void init(){

         send_command(0x33);

         delay(5);

         send_command(0x32);

         delay(5);

         send_command(0x28);

         delay(5);

         send_command(0x0C);

         delay(5);

         send_command(0x01);

         wiringPiI2CWrite(ad,0x08);

}

void clear(){

         send_command(0x01);

}

void write(int x,int y, char data[]){

         intaddr,i;

         inttmp;

         if(x<0)  x=0;

         if(x>15)x=15;

         if(y<0)  y=0;

         if(y>1)  y=1;


         addr= 0x80 + 0x40 * y +x;

         send_command(addr);


         tmp= strlen(data);

         for(i= 0; i < tmp; i++){

                   send_data(data[i]);

         }

}

int main(void){

         ad= wiringPiI2CSetup(LCDAddr);

         init();

         write(0,0,"Hello");

         write(1,1,"pi");

         delay(2000);

}

write函数的第一二个参数的含义是列号和行号。

编译C语言:gcc lcd.c -o lcd -lwiringPi

运行程序:./lcd

4、python操作LCD   

4.1 LCD显示字符 lcd1602.py

import time

import smbus

BUS = smbus.SMBus(1)

LCD_ADDR = 0x27

BLEN = 1 #turn on/off background light

def turn_light(key):

    global BLEN

    BLEN = key

    if key ==1 :

        BUS.write_byte(LCD_ADDR ,0x08)

    else:

        BUS.write_byte(LCD_ADDR ,0x00)

def write_word(addr, data):

    global BLEN

    temp = data

    if BLEN == 1:

        temp |= 0x08

    else:

        temp &= 0xF7

    BUS.write_byte(addr ,temp)

def send_command(comm):

    # Send bit7-4 firstly

    buf = comm & 0xF0

    buf |= 0x04              # RS = 0, RW = 0, EN = 1

    write_word(LCD_ADDR ,buf)

    time.sleep(0.002)

    buf &= 0xFB              # Make EN = 0

    write_word(LCD_ADDR ,buf)

    # Send bit3-0 secondly

    buf = (comm & 0x0F) << 4

    buf |= 0x04              # RS = 0, RW = 0, EN = 1

    write_word(LCD_ADDR ,buf)

    time.sleep(0.002)

    buf &= 0xFB              # Make EN = 0

    write_word(LCD_ADDR ,buf)

def send_data(data):

    # Send bit7-4 firstly

    buf = data & 0xF0

    buf |= 0x05              # RS = 1, RW = 0, EN = 1

    write_word(LCD_ADDR ,buf)

    time.sleep(0.002)

    buf &= 0xFB              # Make EN = 0

    write_word(LCD_ADDR ,buf)

    # Send bit3-0 secondly

    buf = (data & 0x0F) << 4

    buf |= 0x05              # RS = 1, RW = 0, EN = 1

    write_word(LCD_ADDR ,buf)

    time.sleep(0.002)

    buf &= 0xFB              # Make EN = 0

    write_word(LCD_ADDR ,buf)

def init_lcd():

    try:

        send_command(0x33) # Must initialize to 8-line mode at first

        time.sleep(0.005)

        send_command(0x32) # Then initialize to 4-line mode

        time.sleep(0.005)

        send_command(0x28) # 2 Lines & 5*7 dots

        time.sleep(0.005)

        send_command(0x0C) # Enable display without cursor

        time.sleep(0.005)

        send_command(0x01) # Clear Screen

        BUS.write_byte(LCD_ADDR ,0x08)

    except:

        return False

    else:

        return True

def clear_lcd():

    send_command(0x01) # Clear Screen

def print_lcd(x, y, str):

    if x < 0:

        x = 0

    if x > 15:

        x = 15

    if y <0:

        y = 0

    if y > 1:

        y = 1

    # Move cursor

    addr = 0x80 + 0x40 * y + x

    send_command(addr)

    for chr in str:

        send_data(ord(chr))

if __name__ == '__main__':

    init_lcd()

    print_lcd(0, 0, 'Hello, world!')

    print_lcd(0, 1, 'Hello, world!')

运行程序:python lcd1602.py,print_lcd函数的前两个参数分别是列号和行号。

4.2 LCD显示时间 lcd_time.py

显示时间的python:lcd_time.py,需要使用到lcd1602.py的 print_lcd函数,所以调用lcd1602.py文件。

#!/user/bin/env python

import smbus

import time

import sys

import lcd1602 as LCD

if __name__ == '__main__':

    LCD.init_lcd()

    time.sleep(1)

    LCD.print_lcd(2, 0, 'Raspberry Pi')

    for x in xrange(1, 4):

        LCD.turn_light(0)

        LCD.print_lcd(4, 1, 'LIGHT OFF')

        time.sleep(0.5)

        LCD.turn_light(1)

        LCD.print_lcd(4, 1, 'LIGHT ON ')

        time.sleep(0.5)

    LCD.turn_light(1)

    while True:

        now = time.strftime('%m/%d %H:%M:%S', time.localtime(time.time()))

        LCD.print_lcd(1, 1, now)

        time.sleep(0.2)

4.3 LCD显示IP地址 lcd_ip.py 

和显示时间类似,显示树莓派的ip地址,这个程序可以设置为开机启动,这样就可以直观知道树莓派的IP地址了。

#!/user/bin/env python

import os

import smbus

import time

import sys

import socket

import subprocess

import lcd1602 as LCD

def getLocalIP():

    ip = None

    try:

        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

        s.connect(('114.114.114.114', 0))

        ip = s.getsockname()[0]

    except:

        name = socket.gethostname()

        ip = socket.gethostbyname(name)

    if ip.startswith("127."):

        cmd = '''/sbin/ifconfig | grep "inet " | cut -d: -f2 | awk '{print $1}' | grep -v "^127."'''

        a = subprocess.Popen(

            cmd,

            shell=True,

            stdout=subprocess.PIPE,

            stderr=subprocess.PIPE)

        a.wait()

        out = a.communicate()

        ip = out[0].strip().split("\n")

        if len(ip) == 1 and ip[0] == "" or len(ip) == 0:

            return False

        ip = "over".join(ip)

    return ip

if __name__ == '__main__':

    LCD.init_lcd()

    time.sleep(1)

    LCD.print_lcd(2, 0, 'Raspberry Pi')

    for x in xrange(1, 4):

        LCD.turn_light(0)

        LCD.print_lcd(4, 1, 'LIGHT OFF')

        time.sleep(0.5)

        LCD.turn_light(1)

        LCD.print_lcd(4, 1, 'LIGHT ON ')

        time.sleep(0.5)

    LCD.turn_light(1)

    while True:

        now = time.strftime('%m/%d %H:%M:%S', time.localtime(time.time()))

        ip=getLocalIP()

        LCD.print_lcd(1, 1, ip)

        time.sleep(0.2)

4.4 LCD显示树莓派状态 lcd_status.py

    和显示IP地址类似,滚动显示树莓派温度,cpu使用率,内存信息和硬盘信息。

#!/user/bin/env python

import os

import smbus

import time

import sys

import socket

import subprocess

import lcd1602 as LCD

def getLocalIP():

    ip = None

    try:

        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

        s.connect(('114.114.114.114', 0))

        ip = s.getsockname()[0]

    except:

        name = socket.gethostname()

        ip = socket.gethostbyname(name)

    if ip.startswith("127."):

        cmd = '''/sbin/ifconfig | grep "inet " | cut -d: -f2 | awk '{print $1}' | grep -v "^127."'''

        a = subprocess.Popen(

            cmd,

            shell=True,

            stdout=subprocess.PIPE,

            stderr=subprocess.PIPE)

        a.wait()

        out = a.communicate()

        ip = out[0].strip().split("\n")

        if len(ip) == 1 and ip[0] == "" or len(ip) == 0:

            return False

        ip = "over".join(ip)

    return ip

# Return CPU temperature as a character string

def getCPUtemperature():

    res = os.popen('vcgencmd measure_temp').readline()

    return(res.replace("temp=","").replace("'C\n",""))

# Return RAM information (unit=kb) in a list

# Index 0: total RAM

# Index 1: used RAM

# Index 2: free RAM

def getRAMinfo():

    p = os.popen('free')

    i = 0

    while 1:

        i = i + 1

        line = p.readline()

        if i==2:

            return(line.split()[1:4])

# Return % of CPU used by user as a character string

def getCPUuse():

    return(str(os.popen("top -n1 | awk '/Cpu\(s\):/ {print $2}'").readline().strip()))

# Return information about disk space as a list (unit included)

# Index 0: total disk space

# Index 1: used disk space

# Index 2: remaining disk space

# Index 3: percentage of disk used

def getDiskSpace():

    p = os.popen("df -h /")

    i = 0

    while 1:

        i = i +1

        line = p.readline()

        if i==2:

            return(line.split()[1:5])

if __name__ == '__main__':

    LCD.init_lcd()

    time.sleep(1)

    LCD.print_lcd(2, 0, 'Raspberry Pi')

    for x in xrange(1, 4):

        LCD.turn_light(0)

        LCD.print_lcd(4, 1, 'LIGHT OFF')

        time.sleep(0.5)

        LCD.turn_light(1)

        LCD.print_lcd(4, 1, 'LIGHT ON ')

        time.sleep(0.5)

        LCD.turn_light(1)

    while True:

        now = time.strftime('%m/%d %H:%M:%S', time.localtime(time.time()))

        ip=getLocalIP()

        # CPU informatiom

        CPU_temp = getCPUtemperature()

        CPU_usage = getCPUuse()

        # RAM information

        # Output is in kb, here I convert it in Mb for readability

        RAM_stats = getRAMinfo()

        RAM_total = round(int(RAM_stats[0]) / 1000,1)

        RAM_used = round(int(RAM_stats[1]) / 1000,1)

        RAM_free = round(int(RAM_stats[2]) / 1000,1)

        # Disk information

        DISK_stats = getDiskSpace()

        DISK_total = DISK_stats[0]

        DISK_used = DISK_stats[1]

        DISK_perc = DISK_stats[3]

        LCD.clear_lcd()

        LCD.print_lcd(0, 0, now)

        LCD.print_lcd(0, 1, ip)

        time.sleep(2)

        LCD.clear_lcd()

        LCD.print_lcd(0, 0, 'CPU Temperature='+CPU_temp)

        LCD.print_lcd(0, 1, 'CPU Use='+CPU_usage)

        time.sleep(2)

        LCD.clear_lcd()

        LCD.print_lcd(0, 0, 'RAM Total='+str(RAM_total)+'MB')

        LCD.print_lcd(0, 1, 'RAM Used='+str(RAM_used)+'MB')

        time.sleep(2)

        LCD.clear_lcd()

        LCD.print_lcd(0, 0, 'RAM Free='+str(RAM_free)+'MB')

        LCD.print_lcd(0, 1, 'DISK Total Space='+str(DISK_total)+'B')

        time.sleep(2)

        LCD.clear_lcd()

        LCD.print_lcd(0, 0, 'DISK Used Space='+str(DISK_used)+'B')

        LCD.print_lcd(0, 1, 'DISK Used Percentage='+str(DISK_perc))

        time.sleep(2)

5、实际效果图

6、设置开机启动

修改 /etc/rc.local 文件,在 exit 0 前面增加一行后台运行lcd_status.py的代码:

sudo  python  /home/pi/sensor/lcd_status.py &

推荐阅读更多精彩内容