前言

很早就入了树莓派,一直没有折腾GPIO功能,虽然我是学自动化的,但是我对引脚之类的一窍不通,做这个也是为了预习一下本专业的知识,而更多的,是乐趣。

在淘宝上网购了原料之后,回家发现网上并没有树莓派3B的教程,大部分都是树莓派2B的教程,而树莓派3B的GPIO图都发生了变化,因此写本文的目的还在于帮助更多的人,填补互联网的空白。

知识储备

  • 数字电子技术基础
  • 微机原理与接口技术
  • python语言

原料

  • 树莓派3B
  • DHT11
  • LCD1602
  • 2K电阻(也可以是电位器)
  • 子-母 和 母-母 杜邦线
  • 电气绝缘胶带
  • 剪刀
  • 一颗耐心和一颗细心

语言

  • Python 2.7

组件

  • python-dev
  • python-rpi.gpio
    如果不具备以上,请执行:
    sudo apt-get update
    sudo apt-get install python-dev
    sudo apt-get install python-rpi.gpio

接线

我们一共要完成两个任务:

  • 1.连接LCD1602
  • 2.连接DHT11

树莓派3B的GPIO图如下:

2K 电阻如何连接到电路

简单粗暴的方法就是把电阻两头连接到两个子-母杜邦线上,然后用绝缘胶布缠上,非常方便美观。

LCD1602 接线方案

LCD 与 树莓派相连 方案图,2K电阻是我自行设计,如果有电位器最好放置电位器:

树莓派的USB端口朝下,电源线位置朝上方向摆放。
右端一共有40个引脚,每个引脚的PIN位置如上。

VSS,接地,RPi PIN 6
VDD,接5V电源,PRi PIN 2
VO,液晶对比度调节,接1K 电阻,另一端相连接地,PIN 9
RS,寄存器选择,接GPIO 14,RPi PIN 8
RW,读写选择,接地,表示写模式,PRi PIN 6
E,使能信号,接GPIO 15,RPi PIN 10
D0,数据位0,4位工作模式下不用,不接
D1,数据位1,4位工作模式下不用,不接
D2,数据位2,4位工作模式下不用,不接
D3,数据位3,4位工作模式下不用,不接
D4,数据位4,接GPIO 17,RPi PIN 11
D5,数据位5,接GPIO 18,RPi PIN 12
D6,数据位6,接GPIO 27,RPi PIN 13
D7,数据位7,接GPIO 22,RPi PIN 15
A,液晶屏背光+,接5V,RPi PIN 4
K,液晶屏背光-,接地,RPi PIN 39

连接好后,务必要仔细检查是否连接正确,以防开机烧坏GPIO甚至树莓派。

建议在关机情况下接线,如果在开机情况下接线,VDD请最后连接。

LCD1602 开机测试

接通电源线,默认情况下,如果连接正确:

  • 肯定没有爆炸
  • 会出现如下图的效果,证明你已经接线成功了

DHT11 接线方案

接线简单,主要是把数据传输到GPIO26上

DHT11有3个脚,VCC,DATA,GND
VCC 接 3.3V PIN 01
DATA 接 GPIO26 PIN 37
GND 接地 PIN 09

#代码
采用python语言编写,由于html对tab和空格的支持不好,复制容易产生编译问题,代码已经传到github

https://github.com/yfgeek/rpi-TmpHmdRuntime

#!/usr/bin/python

# based on code from hugozhu/CharLCD.py https://gist.github.com/hugozhu/6166527
# rewrite by ivan

from time import sleep
from datetime import datetime
from time import sleep
import commands,time
import RPi.GPIO as GPIO

def get_tmp():
channel = 37
data = []
j = 0

GPIO.setmode(GPIO.BOARD)

time.sleep(1)

GPIO.setup(channel, GPIO.OUT)
GPIO.output(channel, GPIO.LOW)
time.sleep(0.5)
GPIO.output(channel, GPIO.HIGH)
GPIO.setup(channel, GPIO.IN)

while GPIO.input(channel) == GPIO.LOW:
continue
while GPIO.input(channel) == GPIO.HIGH:
continue

while j < 40:
k = 0
while GPIO.input(channel) == GPIO.LOW:
continue
while GPIO.input(channel) == GPIO.HIGH:
k += 1
if k > 100:
break
if k < 8:
data.append(0)
else:
data.append(1)

j += 1

print "sensor is working."
print data

humidity_bit = data[0:8]
humidity_point_bit = data[8:16]
temperature_bit = data[16:24]
temperature_point_bit = data[24:32]
check_bit = data[32:40]

humidity = 0
humidity_point = 0
temperature = 0
temperature_point = 0
check = 0

for i in range(8):
humidity += humidity_bit[i] * 2 ** (7-i)
humidity_point += humidity_point_bit[i] * 2 ** (7-i)
temperature += temperature_bit[i] * 2 ** (7-i)
temperature_point += temperature_point_bit[i] * 2 ** (7-i)
check += check_bit[i] * 2 ** (7-i)

tmp = humidity + humidity_point + temperature + temperature_point

if check == tmp:
return 'temp:' + str(temperature) + ' C \nhumidity:' + str(humidity) + '%'
else:
get_tmp()

GPIO.cleanup()

class Adafruit_CharLCD:

# 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

# 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



def __init__(self, pin_rs=8, pin_e=10, pins_db=[11,12,13,15], GPIO = None):
# Emulate the old behavior of using RPi.GPIO if we haven't been given
# an explicit GPIO interface to use
if not GPIO:
import RPi.GPIO as GPIO
GPIO.setwarnings(False)

self.GPIO = GPIO
self.pin_rs = pin_rs
self.pin_e = pin_e
self.pins_db = pins_db

self.GPIO.setmode(GPIO.BOARD)
self.GPIO.setup(self.pin_e, GPIO.OUT)
self.GPIO.setup(self.pin_rs, GPIO.OUT)

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

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

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

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

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

self.clear()


def begin(self, cols, lines):

if (lines > 1):
self.numlines = lines
self.displayfunction |= self.LCD_2LINE
self.currline = 0


def home(self):

self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero
self.delayMicroseconds(3000) # this command takes a long time!


def clear(self):

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


def setCursor(self, col, row):

self.row_offsets = [ 0x00, 0x40, 0x14, 0x54 ]

if ( row > self.numlines ):
row = self.numlines - 1 # we count rows starting w/0

self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))


def noDisplay(self):
""" Turn the display off (quickly) """

self.displaycontrol &= ~self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def display(self):
""" Turn the display on (quickly) """

self.displaycontrol |= self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def noCursor(self):
""" Turns the underline cursor on/off """

self.displaycontrol &= ~self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def cursor(self):
""" Cursor On """

self.displaycontrol |= self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def noBlink(self):
""" Turn on and off the blinking cursor """

self.displaycontrol &= ~self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def noBlink(self):
""" Turn on and off the blinking cursor """

self.displaycontrol &= ~self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)


def DisplayLeft(self):
""" These commands scroll the display without changing the RAM """

self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)


def scrollDisplayRight(self):
""" These commands scroll the display without changing the RAM """

self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT);


def leftToRight(self):
""" This is for text that flows Left to Right """

self.displaymode |= self.LCD_ENTRYLEFT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode);


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


def autoscroll(self):
""" This will 'right justify' text from the cursor """

self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


def noAutoscroll(self):
""" This will 'left justify' text from the cursor """

self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)


def write4bits(self, bits, char_mode=False):
""" Send command to LCD """

self.delayMicroseconds(1000) # 1000 microsecond sleep

bits=bin(bits)[2:].zfill(8)

self.GPIO.output(self.pin_rs, char_mode)

for pin in self.pins_db:
self.GPIO.output(pin, False)

for i in range(4):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i], True)

self.pulseEnable()

for pin in self.pins_db:
self.GPIO.output(pin, False)

for i in range(4,8):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i-4], True)

self.pulseEnable()


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


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


def message(self, text):
""" Send string to LCD. Newline wraps to second line"""

for char in text:
if char == '\n':
self.write4bits(0xC0) # next line
else:
self.write4bits(ord(char),True)

if __name__ == '__main__':

while True:
tmp = get_tmp()
if tmp:
lcd = Adafruit_CharLCD()
lcd.noBlink()
lcd.clear()
lcd.message(tmp)
sleep(5)

运行效果

参考资料

https://gist.github.com/hugozhu/6166527
https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code/tree/2d4678fdccec1b93d8d69ba7768f6698545b2c5f
https://github.com/op2-project/op2-daemon/blob/master/op2d/hal/backend/pihelpers/lcd.py
http://blog.csdn.net/xukai871105/article/details/12684617
https://www.oschina.net/question/1425530\_140979
http://bbs.elecfans.com/jishu\_578437\_1\_1.html
http://blog.csdn.net/netccy/article/details/48098455
https://www.6zou.net/tech/raspberry-pi-lcd1602-system-monitor.html
http://hugozhu.myalert.info/2013/03/23/19-raspberry-pi-drive-1602-lcd.html
http://hugozhu.myalert.info/2013/03/22/19-raspberry-pi-gpio-port-naming.html
http://blog.csdn.net/rocklee/article/details/50082777
http://www.guokr.com/post/718305/
http://www.rs-online.com/designspark/electronics/blog/content-1148
http://bbs.elecfans.com/jishu\_582479\_1\_1.html
https://www.freemindworld.com/blog/2013/130310\_raspberry\_pi\_with\_lcd.shtml
http://blog.csdn.net/u013431550/article/details/40870947
http://www.shumeipai.net/thread-21026-1-1.html?_dsign=0e7b69ba
http://blog.csdn.net/longerzone/article/details/36171381