基于树莓派的实时温度湿度监测平台

Posted by Ivan on 2016-08-25

前言

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

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

知识储备

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

原料

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

语言

  • Python 2.7

组件

  • python-dev
  • python-rpi.gpio
    如果不具备以上,请执行:
    1
    2
    3
    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

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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#!/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