Example

实验简介

简要做一个小实验,通过检测光线亮暗与烟雾是否存在继而通过短信模块来发送到指定电话号码上

似乎当时想要模拟检测气体泄漏和光线状况的这种情况(如工厂、楼层之类的场景),后来老师提醒光敏不适合这些场景,推荐用红外传感,然后没做成不了了之

实验目的

  • 使用 GPIO 控制引脚来与传感器通信和控制外部设备
  • 配置 GSM 模块以发送短信,包括设置短信模式和字符集

准备材料

  • DragonBoard 410c x1
  • 4脚光敏电阻传感器模块(MH-Sensor Flying-Fish)x1
  • MQ-2 烟雾传感器 x1
  • SIM800A GMS模块 x1
  • 杜邦线若干
  • 面包板 x1
  • 显示屏 x1
  • HDMI转换器、电源适配器

DragonBoard 410c
DragonBoard 410c
Sensors
Sensors
SIM800A
SIM800A

GPIO 引脚相关知识

96Boards 规范要求有高速扩展连接口与低速扩展连接口

实验中仅用到低速扩展连接口,低速扩展连接口 GPIO 与 物理引脚对应图如下

GPIO pin map

低速扩展连接口

410c Signals96Boards SignalsPINPIN96Boards Signals410c Signals
GNDGND12GNDGND
UART0_CTS_N (APQ GPIO_2)UART0_CTS34PWR_BTN_NPHONE_ON_N
UART0_TX (APQ GPIO_0)UART0_TxD56RST_BTN_NPM_RESIN_N
UART0_RX (APQ GPIO_1)UART0_RxD78SPI0_SCLKSPI0_CLK (APQ GPIO_19)
UART0_RTS_N (APQ GPIO_3)UART0_RTS910SPI0_DINSPI0_MISO (APQ GPIO_17)
UART1_TX (APQ GPIO_4)UART1_TxD1112SPI0_CSSPI0_CS_N (APQ GPIO_18)
UART1_RX (APQ GPIO_5)UART1_RxD1314SPI0_DOUTSPI0_MOSI (APQ GPIO_16)
I2C0_SCL (APQ GPIO_7)I2C0_SCL1516PCM_FSLS_EXP_MI2S_WS (APQ GPIO_110)
I2C0_SDA (APQ GPIO_6)I2C0_SDA1718PCM_CLKLS_EXP_MI2S_SCK(APQ GPIO_113)(ALPS_INT)
I2C1_SCL (APQ GPIO_23)I2C1_SCL1920PCM_DOLS_EXP_MI2S_DATA0 (APQ GPIO_114)
I2C1_SDA (APQ GPIO_22)I2C1_SDA2122PCM_DIN.C.
LS_EXP_GPIO_A (APQ GPIO_36) (APQ INT)GPIO-A2324GPIO-BLS_EXP_GPIO_B (APQ GPIO_12) (TS_RST_N)
LS_EXP_GPIO_C (APQ GPIO_13) (TS_INT_N)GPIO-C2526GPIO-DLS_EXP_GPIO_D (APQ GPIO_69) (MAG_INT)
LS_EXP_GPIO_E (APQ GPIO_115) (GYRO_ACCL_INT_N)GPIO-E2728GPIO-FLS_EXP_GPIO_F (PM_MPP_4) (DSI_BLCTRL)
LS_EXP_GPIO_G (APQ GPIO_24) (DSI_VSYNC)GPIO-G2930GPIO-HLS_EXP_GPIO_H (APQ GPIO_25) (DSI_RST)
LS_EXP_GPIO_I (APQ GPIO_35) (CSI0_RST)GPIO-I3132GPIO-JLS_EXP_GPIO_J (APQ GPIO_34) (CSI0_PWDN)
LS_EXP_GPIO_K (APQ GPIO_28) (CSI1_RST)GPIO-K3334GPIO-LLS_EXP_GPIO_L (APQ GPIO_33) (CSI1_PWDN)
LS_EXP_1P8+1V83536SYS_DCINSYS_DCIN
SYS_5P0+5V3738SYC_DCINSYS_DCIN
GNDGND3940GNDGND

Linux 操作系统上控制 GPIO 引脚

#/sys/class/gpio

#get root permission (linaro -> root)
sudo -i #sudo su

#export
echo ${GPIO_NUM} > /sys/class/gpio/export

#unexport
echo ${GPIO_NUM} > /sys/class/gpio/unexport

#direction
echo in > sys/class/gpio/gpio${GPIO_NUM}/direction
echo out > sys/class/gpio/gpio${GPIO_NUM}/direction

电路连接

光敏电阻模块的 VCC 引脚接到 DragonBoard 410c 的 5V 引脚上,将 GND 引脚接到 DragonBoard 410c 的 GND 引脚上,将 DO 引脚接到 DragonBoard 410c 的 GPIO 物理引脚 34 上

将烟雾传感器模块的 VCC 引脚接到 DragonBoard 410c 的 5V 引脚上,将 GND 引脚接到 DragonBoard 410c 的 GND 引脚上,将 DO 引脚接到 DragonBoard 410c 的 GPIO 物理引脚 30 上

物理引脚 40 接 GND

SIM800A 在实验开始前通过 USB 接口连接到开发板上,并开启

电路简图被我损坏,暂无

编写代码

需要准备好 pyserial 库以及下面微调的 GPIOLibrary 库,代码部分可在参考资料栏中的 GitHub 链接处点击浏览

pyserial 负责串口通信,GPIOLibrary 库包括 GPIOProcessor 类GPIO 类,注释有描述作用

GPIOLibrary.py

微调部分指的是 getPin() 部分,获取 DragonBoard 410c 引脚值需要在基础上加上 390

物理引脚 30 对应 GPIO 25,加上 390 后即为 415

物理引脚 34 对应 GPIO 33,加上 390 即为 423

class GPIOProcessor:
    '''This is the GPIO Processor class.  IT is used to create GPIO objects and
    keep track of them. Pins 23-34 have the their corresponding GPIO number
    stored so that they may easily called with the appropriate getPin method.
    '''

    def __init__(self):
        self.GPIOList = []

    def getPin(self, pin_number):
        '''The getPin method is used to create a GPIO object. After a GPIO is
        created it is added to a list to keep track of all GPIO's being used.
        '''
        pin = GPIO(pin_number)
        pin.openPin()
        self.GPIOList.append(pin)
        return pin

    def getPin23(self):
        return self.getPin(36)

    def getPin24(self):
        return self.getPin(12)

    def getPin25(self):
        return self.getPin(13)

    def getPin26(self):
        return self.getPin(69)

    def getPin27(self):
        return self.getPin(115)

    def getPin28(self):
        return self.getPin(901)

    def getPin29(self):
        return self.getPin(24)

    def getPin30(self):
        return self.getPin(415)

    def getPin31(self):
        return self.getPin(35)

    def getPin32(self):
        return self.getPin(424)

    def getPin33(self):
        return self.getPin(28+390)

    def getPin34(self):
        return self.getPin(423)

    def cleanup(self):
        '''The cleanup method should be called at the end of every program that
        uses GPIO's.  It changes the GPIO's back to inputs(which is safer when
        not in use) and then unexports all GPIO's that were used.
        '''
        for pin in self.GPIOList:
            pin.input()
            pin.closePin()
        self.GPIOList = []


class GPIO:
    '''This is the GPIO class.  This class contains methods that can be used to
    control the GPIO's.  It is used by the GPIOProcessor class. These methods
    open the appropriate file to export GPIOs or change direction and value.
    '''
    global PATH
    PATH = "/sys/class/gpio/"

    def __init__(self, pin_number):
        self.pin_number = pin_number

    def openPin(self):
        file = open(PATH + "export", 'w')
        file.write(str(self.pin_number))
        file.close()

    def closePin(self):
        file = open(PATH + "unexport", 'w')
        file.write(str(self.pin_number))
        file.close()

    def setDirection(self, direction):
        file = open(PATH + "gpio" + str(self.pin_number) + "/direction", 'w')
        file.write(str(direction))
        file.close()

    def setValue(self, value):
        file = open(PATH + "gpio" + str(self.pin_number) + "/value", 'w')
        file.write(str(value))
        file.close()

    def getDirection(self):
        file = open(PATH + "gpio" + str(self.pin_number) + "/direction", 'r')
        direction = file.read()
        file.close()
        return direction

    def getValue(self):
        file = open(PATH + "gpio" + str(self.pin_number) + "/value", 'r')
        value = file.read()
        file.close()
        return int(value)

    def high(self):
        self.setValue(1)

    def low(self):
        self.setValue(0)

    def input(self):
        self.setDirection("in")

    def out(self):
        self.setDirection("out")

main.py

phone_num = '' 处可以指定电话号码

from GPIOLibrary import GPIOProcessor
from GPIOLibrary import GPIO
import os
import serial
from time import sleep


class GasLight:

    def __init__(self):
        self.gpio = GPIOProcessor()
        self.port = serial.Serial(port='/dev/ttyUSB0', baudrate=115200, bytesize=8, stopbits=1, timeout=2)

        self.gas_message_sent = False
        self.light_message_sent = False

        if self.port.isOpen():
            print("Serial is opened!")
            print(self.port)
            print(self.port.name)
        else:
            print("Serial do not open!")

    def gpio_close(self, pin):
        self.export_path = f"/sys/class/gpio/gpio{pin}"
        if os.path.exists(self.export_path):
            self.gpioControl = GPIO(pin)
            self.gpioControl.closePin()

    def gpio_input(self):
        self.gpio_30 = self.gpio.getPin30()
        self.gpio_30.setDirection("in")
        self.gpio_34 = self.gpio.getPin34()
        self.gpio_34.setDirection("in")

    def get_gpio_value(self):
        self.gas = self.gpio_30.getValue()
        self.light = self.gpio_34.getValue()
        return self.gas, self.light

    def dbg_sim800a(self, data):
        self.res_ser = ""
        if data != "":
            self.port.write(data.encode())
            sleep(1)
            print("send to sim800a: " + data)
            if "AT" == str(data):
                sleep(3)
            if self.port.inWaiting() > 0:
                while True:
                    self.res_ser = self.port.readall()
                    if self.res_ser == "":
                        continue
                    else:
                        break
                if ">" in str(self.res_ser):
                    print(data + "successfully!")
                    print(self.res_ser)
                    print("you can send message!")
                    self.res_ser = ""
                if "OK" in str(self.res_ser):
                    print(data + "successfully!\n")
                    print(self.res_ser)
                    self.res_ser = ""
                else:
                    print(data + "unsuccessfully!\n")
                    print(self.res_ser)
                    self.res_ser = ""

    def send_gas_message(self):
        if not self.gas_message_sent:
            self.port.write(f"AT+CMGS=\"{phone_num}\"\r\n".encode())
            sleep(1)
            self.port.write("Gas leakage.".encode())
            sleep(1)
            self.port.write("\x1A".encode())
            sleep(5)
            self.gas_message_sent = True

    def send_light_message(self):
        if not self.light_message_sent:
            self.port.write(f"AT+CMGS=\"{phone_num}\"\r\n".encode())
            sleep(1)
            self.port.write("It's dark now!!".encode())
            sleep(1)
            self.port.write("\x1A".encode())
            sleep(5)
            self.light_message_sent = True


if __name__ == '__main__':

    phone_num = ''

    my_board = GasLight()
    my_board.dbg_sim800a("AT\r\n")
    my_board.dbg_sim800a("AT+CMGF=1\r\n")
    my_board.dbg_sim800a("AT+CSCS=\"GSM\"\r\n")
    my_board.dbg_sim800a("AT+CSMP=17,167,0,0\r\n")
    my_board.gpio_close(415)
    my_board.gpio_close(423)
    sleep(1)
    my_board.gpio_input()
    sleep(2)

    while True:
        gas_value, light_value = my_board.get_gpio_value()
        if gas_value == 0:
            print(f"gas: {gas_value}, message will be sent!")
            my_board.send_gas_message()
            my_board.gas_message_sent = False
        else:
            print(f"gas: {gas_value}, status fine.")
            sleep(5)
        if light_value == 1:
            print(f"light: {light_value}, message will be sent.")
            my_board.send_light_message()
            my_board.light_message_sent = False
        else:
            print(f"light: {light_value}, status fine.")
            sleep(5)

实际操作

  1. 使用 SD 卡为 DragonBoard 开发板安装 Linux 操作系统
  2. 设置相应的 Python 环境
  3. 电源处于关闭状态下连线至开发板上
  4. 开机连接至显示器并通过终端测试运行代码
  5. 处于亮暗条件下测试光敏电阻传感器是否正常,释放出一小撮烟雾测试烟雾传感器是否正常
  6. 在 4 的条件下,根据 value 来向 SIM800A 发出指令,发送短信至指定电话号码

参考资料

DragonBoard 410c Hardware User Manual - 96Boards

DragonBoard 410c - Tutorials - Qualcomm Developer Network

Dragonboard Pin Mappings - Windows IoT | Microsoft Learn

DragonBoard: How to Access GPIOs Using Python : 8 Steps - Instructables

Debcharon/BasicAlarmSystem: Simple fire and light detect/alarm system with DragonBoard 410c and SIM800A (github.com)

GPIO export on linux - Invalid argument - Products Support / DragonBoard410c - 96Boards Forum

最后修改:2023 年 11 月 22 日
如果觉得我的文章对你有用,请随意赞赏