1. 程式人生 > >自己動手實現智慧家居之溫溼度數碼管展示(四位共陽數碼管)

自己動手實現智慧家居之溫溼度數碼管展示(四位共陽數碼管)

【前言】

一個熱愛技術的人一定向往有一個科技感十足的環境吧,那何不親自實踐一下屬於技術人的座右銘:“技術改變世界”。

就讓我們一步步動手搭建一個屬於自己的“智慧家居平臺”吧(不要對這個名詞抬槓啦,技術在手,怎麼設計實現因人而異),本文只做拋磚引玉,各路大神如果有更好的想法可以各顯神通,當然能在評論區留下更好的想法讓大家共同學習是再好不過啦。

在文章最後附有所有原始碼,有需要的可以自行下載,感謝Star~

【系列目錄】

  1. 樹莓派GPIO簡介(Python版)
  2. 溫溼度資料採集儲存(DHT11,MySql)
  3. 溫溼度數碼管展示(四位共陽數碼管)
  4. 構建App展示溫溼度報表(ApiCloud,Python Flask)
  5. 普通家用排插整合繼電器手工改造
  6. App遠端控制“自制智慧”排插
  7. 使用花生棒內網穿透實現外網訪問
  8. App遠端監控(攝像頭模組整合)

【本節概要】

上一節我們介紹了基於樹莓派基於DHT11採集溫溼度並將記錄儲存到mysql資料庫中,這一節我們將分享四位共陽數碼管的使用以及將我們的溫溼度資料在數碼管展示。

效果圖:

那麼接下來我們就一步步講解這個"窮且益艱"的過程...

【硬體採購】

”某寶“購買一個四路共陽數碼管模組,不貴,一兩瓶飲料的價格。下圖很明顯有四個顯示位,並且是公用陽極,而用陰極控制顯示與否,因此叫四路共陽。

說明書有一張圖就夠了:

1,2,3,4 高電平控制顯示的位置 ABCDEFG/DP 對應顯示右面各個部位(低電平)

【四路共陽數碼管的控制】

四路共陽數碼管的控制我沒有找到好用的現成包,因此我這裡直接自行封裝了一個,涵蓋了能顯示的數字和字母小數點,類如下,可直接複製呼叫:

# coding=utf-8
import sys
sys.path.append('..')

import time
import RPi.GPIO as GPIO

# 共陽4位數字管
class Yang4():
    # 顯示位數
    p1 = 1
    p2 = 2
    p3 = 3
    p4 = 4
    # 顯示狀態
    a = 5
    b = 6
    c = 7
    d = 8
    e = 9
    f = 10
    g = 11
    dp = 12
    positionPoints = []
    numberPoints = []

    # 初始化並設定控制針腳
    # 針腳連線順序:位置1-4,數字a-dp
    def __init__(self, p1, p2, p3, p4, a, b, c, d, e, f, g, dp):
        self.p1 = p1
        self.p2 = p2
        self.p3 = p3
        self.p4 = p4
        self.a = a
        self.b = b
        self.c = c
        self.d = d
        self.e = e
        self.f = f
        self.g = g
        self.dp = dp
        self.positionPoints = [p1, p2, p3, p4]
        self.numberPoints = [a, b, c, d, e, f, g, dp]

        # Board模式
        GPIO.setmode(GPIO.BOARD)
        # 關閉提示
        GPIO.setwarnings(False)

        for item in self.positionPoints+self.numberPoints:
            GPIO.setup(item, GPIO.OUT)

    # 輸入一個字串
    def Display(self, str8bit):
        self.__DisplayCode(str8bit)

    # 篩選並控制顯示各位置
    def __DisplayCode(self, str8bit):
        # 當前位置
        index = -1
        for i in range(0, len(str8bit)):
            if index > 8:
                return

            arg = str(str8bit[i])
            if arg == '.' and index % 2 != 0:
                index = index + 1
            elif arg != '.' and index % 2 != 1:
                index = index + 1
            
            index = index + 1

            self.__ResetPosition()
            self.__ResetNumber()
            self.__DisplayNumberSwitch(arg)
            GPIO.output(self.positionPoints[index//2], 1)
            time.sleep(0.002)


    def __ResetPosition(self):
        for item in self.positionPoints:
            GPIO.output(item, 0)

    def __ResetNumber(self):
        for item in self.numberPoints:
            GPIO.output(item, 1)

    def __DisplayNumberSwitch(self, arg):
        # print('arg='+str(arg))
        if arg == '.':
            self.__Display_DOT()
        # 上方小圈用小o,下方小圈用中文句號
        elif arg == 'o':
            self.__Display_TopCircle()
        elif arg == '。':
            self.__Display_DownCircle()
        # -----------------------------
        elif arg == '0':
            self.__Display_0()
        elif arg == '1':
            self.__Display_1()
        elif arg == '2':
            self.__Display_2()
        elif arg == '3':
            self.__Display_3()
        elif arg == '4':
            self.__Display_4()
        elif arg == '5':
            self.__Display_5()
        elif arg == '6':
            self.__Display_6()
        elif arg == '7':
            self.__Display_7()
        elif arg == '8':
            self.__Display_8()
        elif arg == '9':
            self.__Display_9()
        # -----------------------------
        elif arg == 'A':
            self.__Display_A()
        elif arg == 'B':
            self.__Display_B()
        elif arg == 'C':
            self.__Display_C()
        elif arg == 'D':
            self.__Display_D()
        elif arg == 'd':
            self.__Display_d()
        elif arg == 'E':
            self.__Display_E()
        elif arg == 'F':
            self.__Display_F()
        elif arg == 'G':
            self.__Display_G()
        elif arg == 'H':
            self.__Display_H()
        elif arg == 'I':
            self.__Display_I()
        elif arg == 'J':
            self.__Display_J()
        elif arg == 'L':
            self.__Display_L()
        elif arg == 'O':
            self.__Display_O()
        elif arg == 'P':
            self.__Display_P()
        elif arg == 'S':
            self.__Display_S()
        elif arg == 'U':
            self.__Display_U()
        elif arg == 'V':
            self.__Display_V()
        else:
            None

    def __Display_DOT(self):
        GPIO.output(self.dp, 0)

    def __Display_TopCircle(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.b, 0)
        GPIO.output(self.g, 0)
        GPIO.output(self.f, 0)

    def __Display_DownCircle(self):
        GPIO.output(self.c, 0)
        GPIO.output(self.d, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.g, 0)

    # -----------------------------
    def __Display_0(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.b, 0)
        GPIO.output(self.c, 0)
        GPIO.output(self.d, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.f, 0)

    def __Display_1(self):
        GPIO.output(self.b, 0)
        GPIO.output(self.c, 0)

    def __Display_2(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.b, 0)
        GPIO.output(self.d, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.g, 0)

    def __Display_3(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.b, 0)
        GPIO.output(self.c, 0)
        GPIO.output(self.d, 0)
        GPIO.output(self.g, 0)

    def __Display_4(self):
        GPIO.output(self.b, 0)
        GPIO.output(self.c, 0)
        GPIO.output(self.f, 0)
        GPIO.output(self.g, 0)

    def __Display_5(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.c, 0)
        GPIO.output(self.d, 0)
        GPIO.output(self.f, 0)
        GPIO.output(self.g, 0)

    def __Display_6(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.c, 0)
        GPIO.output(self.d, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.f, 0)
        GPIO.output(self.g, 0)

    def __Display_7(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.b, 0)
        GPIO.output(self.c, 0)

    def __Display_8(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.b, 0)
        GPIO.output(self.c, 0)
        GPIO.output(self.d, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.f, 0)
        GPIO.output(self.g, 0)

    def __Display_9(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.b, 0)
        GPIO.output(self.c, 0)
        GPIO.output(self.d, 0)
        GPIO.output(self.f, 0)
        GPIO.output(self.g, 0)

    # -----------------------------
    def __Display_A(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.b, 0)
        GPIO.output(self.c, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.f, 0)
        GPIO.output(self.g, 0)

    def __Display_B(self):
        self.__Display_8()

    def __Display_C(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.d, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.f, 0)

    def __Display_d(self):
        GPIO.output(self.b, 0)
        GPIO.output(self.c, 0)
        GPIO.output(self.d, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.g, 0)

    def __Display_D(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.b, 0)
        GPIO.output(self.c, 0)
        GPIO.output(self.d, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.f, 0)

    def __Display_E(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.d, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.f, 0)
        GPIO.output(self.g, 0)

    def __Display_F(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.f, 0)
        GPIO.output(self.g, 0)

    def __Display_G(self):
        self.__Display_6()

    def __Display_H(self):
        GPIO.output(self.b, 0)
        GPIO.output(self.c, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.f, 0)
        GPIO.output(self.g, 0)

    def __Display_I(self):
        self.__Display_1()

    def __Display_J(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.b, 0)
        GPIO.output(self.c, 0)
        GPIO.output(self.d, 0)

    def __Display_L(self):
        GPIO.output(self.d, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.f, 0)

    def __Display_O(self):
        self.__Display_0()

    def __Display_P(self):
        GPIO.output(self.a, 0)
        GPIO.output(self.b, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.f, 0)
        GPIO.output(self.g, 0)

    def __Display_S(self):
        self.__Display_5()

    def __Display_U(self):
        GPIO.output(self.b, 0)
        GPIO.output(self.c, 0)
        GPIO.output(self.d, 0)
        GPIO.output(self.e, 0)
        GPIO.output(self.f, 0)

    def __Display_V(self):
        self.__Display_U()

當然使用的demo也得拱手獻上:

# coding=utf-8
from GPIO.NixieTube import 

# 需要的針腳對應的樹莓派GPIO針腳
# 針腳連線順序:位置1-4,數字a-dp
# 可以參考引數順序,對應數碼管定義的各個引腳 __init__(self, p1, p2, p3, p4, a, b, c, d, e, f, g, dp):
y4 = Yang4(35, 16, 22, 32, 31, 36, 38, 33, 37, 12, 18, 40)
delay = 600

# 顯示時間
while(True):
    # time
    timenow = datetime.datetime.now()

    for i in range(0, delay):
        y4.Display(str(timenow.year))
        time.sleep(0.005)

    for i in range(0, delay):
        y4.Display(str(timenow.month).zfill(
            2)+'.'+str(timenow.day).zfill(2))
        time.sleep(0.005)

    for i in range(0, delay):
        y4.Display(str(timenow.hour).zfill(
            2)+'.'+str(timenow.minute).zfill(2))
        time.sleep(0.005)

    y4.Display('....')

上述程式碼的功能為:按一定的間隔迴圈顯示年月日時分。

因為數碼管實際上是無限迴圈展示各個需要顯示的位置,肉眼無法捕捉時間間隔很短的顯隱變化。也就是看起來顯示的年月日時分秒,真實應該是數碼管的各個小節迴圈在顯示,這樣就可以用幾個引腳顯示較為複雜的影象。

【整合溫溼度資料獲取儲存和顯示】

可以運算元碼管顯示之後,我們將之前的溫溼度的資料和數碼管的顯示整合在一起(可以參考前面博文)

# coding=utf-8
from Utility.MySqlHelper import MySqlHelper
import _thread
import Adafruit_DHT
from GPIO.NixieTube import Yang4
import time
import datetime
import RPi.GPIO as GPIO
import sys
sys.path.append('..')


def WriteToDb(timenow, year, month, day, hour, temp, humi):
    smartHomeDb = MySqlHelper("SmartHome")
    smartHomeDb.executeSql("INSERT INTO DailyMonitor (DateTime,Year,Month,Day,Hour,Temperature,Humidity) VALUES ('{0}',{1},{2},{3},{4},{5},{6})".format(
        timenow, year, month, day, hour, temp, humi))


y4 = Yang4(35, 16, 22, 32, 31, 36, 38, 33, 37, 12, 18, 40)
delay = 600

# 已經寫入資料庫的小時標識,插入資料的同時,修改為下一個小時,用於比較是否需要寫入
hasWriteToDbHour = datetime.datetime.now().hour

while(True):
    # time
    timenow = datetime.datetime.now()

    for i in range(0, delay):
        y4.Display(str(timenow.year))
        time.sleep(0.005)

    for i in range(0, delay):
        y4.Display(str(timenow.month).zfill(
            2)+'.'+str(timenow.day).zfill(2))
        time.sleep(0.005)

    for i in range(0, delay):
        y4.Display(str(timenow.hour).zfill(
            2)+'.'+str(timenow.minute).zfill(2))
        time.sleep(0.005)

    y4.Display('....')

    # Use read_retry method. This will retry up to 15 times to
    # get a sensor reading (waiting 2 seconds between each retry).
    # this is bcm code
    humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.DHT11, 4)
    print('time:{0},humidity:{1}%,temperature:{2}*C'.format(
        datetime.datetime.now(), humidity, temperature))

    # 非同步將資料寫入mysql
    if hasWriteToDbHour == timenow.hour:
        _thread.start_new_thread(WriteToDb, (timenow, timenow.year,
                                             timenow.month, timenow.day, timenow.hour, temperature, humidity))
        if hasWriteToDbHour == 23:
            hasWriteToDbHour = 0
        else:
            hasWriteToDbHour = hasWriteToDbHour + 1

    if temperature is not None:
        for i in range(0, delay):
            y4.Display('{0:0.1f}C'.format(temperature))
            time.sleep(0.005)

    if humidity is not None:
        for i in range(0, delay):
            y4.Display('H{0:0.1f}'.format(humidity))
            time.sleep(0.005)

上述程式碼的功能:

  1. 迴圈獲取溫溼度,判斷一小時寫入資料庫一次
  2. 數碼管迴圈展示年/月日/時分/溫度/溼度

【樹莓派執行】

我們通過SSH遠端連線到樹莓派的終端

通過FTP將我們的專案上傳到樹莓派伺服器

採用後臺程序的方式執行我們的主指令碼(關閉終端程序不會退出)

nohup python SmartHomeScreen.py

這樣我們的資訊採集指令碼就一直在工作中了,每小時會採集一次溫溼度,並存儲到資料庫表中。隔幾秒採集的資料同時實時顯示在數碼管上,我們抬頭便可以看到當前溫溼度。

效果圖(一張圖用到底):

【總結】

通過本節內容,我們實現了利用樹莓派的GPIO控制共陽數碼管展示溫溼度,並已經實現了我們開始規劃好的溫溼度面板。

後續章節我們會介紹利用我們採集的24小時溫溼度資料製作溫溼度報表... 效果預熱:

【原始碼地址】

Github:https://github.com/sevenTiny/SevenTiny.SmartHome