我的第一个IOT项目(二) 2019-03-02 程序之旅 暂无评论 774 次阅读 ## 我的第一个Iot项目 上次已经简单的实现了设备模块中的GPIO控制,现在到感应器的数据采集设计,经过树莓派控制器的数据转换,然后进行打包上传到云服务器,实现温度湿度数字化模型。 ### 需求分析 - 2s间隔采集一次数据,数据内容包括温度、湿度,并匹配当时获取的时间,时间为10位长整形时间戳 - 数据打包,把数据每5条打一包,集够5条数据后发布数据到云端 - 保证数据可靠性和完整性 ------ ### DHT11--温湿度感应器 本次试验采用的是一个简单的感应器,温湿度感应器,再淘宝上买的套餐,还有其他的感应器,比如声音感应器、土壤感应器和人体感应器等等,后面会慢慢的添加到设备上。先上一张图。 ![25F3EF6E7997ED6C32181AC0CD64162C.jpg][1] #### 分析使用方法 先看结构,从图中可以看到三个引脚:VDD、DATA和GND,分别接3.3~5.5V的电压,串行数据,接地。 > 树莓派的供电分两种,一个3.3V和5V电压,可以在GPIO引脚图中看到 数据传输,DHT11 器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。单总线传送数据位定义,DATA 用于微处理器与 DHT11 之间的通讯和同步,采用单总线数据格式,一次传送 40 位数据,高位先出。 **数据格式:** 8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据+8bit 校验位。 > 注:其中湿度小数部分为 0。 **校验位数据定义:** “8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据”8bit 校验位等于所得结果的末 8 位。 例子: 00110101 00000000 00011000 00000000 01001101 湿度高 8 位 湿度低 8 位 温度高 8 位 温度低 8 位 校验位 计算: 0011 0101+0000 0000+0001 1000+0000 0000= 0100 1101 接收数据正确: 湿度:0011 0101=35H=53%RH 温度:0001 1000=18H=24℃ #### 数据时序 用户主机(MCU)发送一次开始信号后,DHT11 从低功耗模式转换到高速模式,待主机开始信号结束 后,DHT11 发送响应信号,送出 40bit 的数据,并触发一次信采集。大概说说型号的时序图。 1. DHT11上电后等待1S,等待器件越过不稳定期间,之后器件开始测试环境,并记录数据,同时DHT11的DATA数据线保持高电位;此时等待DATA引脚处于输入状态,时刻检测外部信号。 2. 微处理器(树莓派)的I/O设置为输出同时输出低电平,且低电平保持时间不能小于18ms,然后微处理器的 I/O设置为输入状态,由于上拉电阻,微处理器的 I/O 即 DHT11 的 DATA 数据线也随之变高,等待 DHT11 作出回答信号,发送信号如图所示: ![QHZRU7C7-1551520019087.png][2] 3. DHT11 的 DATA 引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后 DHT11 的 DATA引脚处于输出状态,输出 80 微秒的低电平作为应答信号,紧接着输出 80 微秒的高电平通知外设准备接收数据,微处理器的 I/O 此时处于输入状态,检测到 I/O 有低电平(DHT11 回应信号)后,等待 80 微秒的高电平后的数据接收,发送信号如图所示: ![1551520078870.png][3] 4. 由 DHT11 的 DATA 引脚输出 40 位数据,微处理器根据 I/O 电平的变化接收 40 位数据, - 位数据“0”的格式为: 50 微秒的低电平和 26-28 微秒的高电平, - 位数据“1”的格式为: 50 微秒的低电平加 70微秒的高电平。 位数据“0”、“1”格式信号如图所示: ![1551520118683.png][4] **结束信号:** DHT11 的 DATA 引脚输出 40 位数据后,继续输出低电平 50 微秒后转为输入状态,由于上拉电阻随之变为高电平。但 DHT11 内部重测环境温湿度数据,并记录数据,等待外部信号的到来。 #### 代码实战 基于器件的数据时序我们大可用这么来获取信息: - **响应信号:**80us + 80us = 160 us - **数字0:**50 + 26 = 76 us - **数字1:**50 + 70 = 120 us ```python def get_data(self, pin): gpio.pinMode(pin, 1) # 设置针脚为输出状态 gpio.digitalWrite(pin, 1) # 输出高电平 gpio.delay(50) ### 发开始指令,要求DHT11发送数据 gpio.digitalWrite(pin, 0) gpio.delay(25) gpio.digitalWrite(pin, 1) gpio.pinMode(pin, 0) # 设置针脚为输入状态 data_interval = [] # 多获取几次结果 for i in range(45): tc = gpio.micros() # 过滤低电平 while(gpio.digitalRead(pin) == 0):pass while(gpio.digitalRead(pin) == 1): if gpio.micros()-tc > 500: break data_interval.append(gpio.micros() - tc) # 记录每次周期时间 #print(data_interval) data_bit = [] for i in data_interval[1:]: if i > 100: data_bit.append(1) # 由于时间会有相应的误差,大于100 为1 else: data_bit.append(0) # 小于为0 # print(data_bit) return data_bit ``` > 之前使用的是RPi.GPIO模块来对GPIO的控制,这里使用的是wiringPi模块,主要是因为RPi.GPIO缺乏高进度定时功能,且wiringPi处理提供C语言接口。 主函数代码 ```python import sys import time import json from DHT11 import DHT11 from mqtt_client import MQTTClient from DHT11_wiringpi import DHT11Wiringpi from apscheduler.schedulers.background import BackgroundScheduler import threading import queue q = queue.Queue() # 生产者与消费者之间的消息传递,使用FIFO def wait_2s(): time.sleep(2) def get_2s_data(port): print('time = ', time.strftime('%H %M %S', time.localtime(time.time()))) # log日志 t = (int(round(time.time()))) dht11_thread = DHT11Wiringpi(port) thread_2s = threading.Thread(target=wait_2s) thread_list = [dht11_thread, thread_2s] for thread in thread_list: thread.start() for thread in thread_list: thread.join() # 阻塞等待两个线程同时完成 temperature, humidity = dht11_thread.get_result() # 返回获取温度、湿度 data = [{ "ts": t, "temperature": temperature, "humidity": humidity}] q.put(data) if __name__ == '__main__': client = MQTTClient('60.***.***.214', 1883) # 获取mqtt连接客户端 topic = 'data/tp/meas' #thread_list = [] data = [] while True: # data = [] get_2s_data(16) # if q.qsize() == 5: while not q.empty(): data.extend(q.get()) msg = json.dumps({ "sn":"tp0000001", "data": data }) print('send msg ', msg) client.send_msg(topic, msg) data = [] ``` 这段主函数代码其实不是很完善,比如没有使用守护线程等,后期还会进行改进。 数据格式实例 ```java { "sn": "tp0000001", "data": [ { "ts": 1551517623, "temperature": 29.5, "humidity": 16.0 }, { "ts": 1551517625, "temperature": 29.5, "humidity": 16.0 }, {...}} ] } ``` PS:换了markdown来写博客真的是方便,省了很多事。 [1]: https://mufeng-blog.oss-cn-beijing.aliyuncs.com/usr/uploads/2019/03/2590525589.jpg [2]: https://mufeng-blog.oss-cn-beijing.aliyuncs.com/usr/uploads/2019/03/1764473332.png [3]: https://mufeng-blog.oss-cn-beijing.aliyuncs.com/usr/uploads/2019/03/644018040.png [4]: https://mufeng-blog.oss-cn-beijing.aliyuncs.com/usr/uploads/2019/03/3280830536.png 打赏: 微信, 支付宝 标签: iot, 树莓派 本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。