系列文章目录
项目一 基于 SIM800 天气语音广播服务机器人的时间 项目二 树莓派多环境参数监测站 等待后续添加……
文章目录
- 系列文章目录
- 前言
- 2 硬件设计
-
- 2.1 树莓派
-
- 2.1.1 树莓派软硬件问题
- 2.2 传感器
-
- 2.2.1 温湿度传感器 DHC1080
- 2.2.2 光强传感器 BH1750
- 2.2.3 PM2.5 传感器 GP2Y1014AU
- 2.2.4 CO2 传感器 KQM6600
- 3 软件设计
-
- 3.1 界面设计
- 3.2 matplotlib 画图
- 3.3 模拟环境数据
- 3.4 传感器采集数据
-
- 3.4.1 DHC1080
- 3.4.2 BH1750
- 3.4.3 gp2y1014au
- 3.4.4 kqm6600ta
- 3.5 传感器数据集成
- 4 总结
前言
利用树莓派创建一个环境参数监测站,具有图像界面,可以检测各种环境参数。
用树莓派加几个传感器硬件 Python 语言开发。UI 界面包括曲线显示和表格显示。
2 硬件设计
2.1 树莓派
2.1.1 树莓派软硬件问题
版本:树莓派的最新版本已经发布到第一版 4 这里的性能要求不高,不管是用的 3 代还是 4 代都没问题。本项目使用最新版本 4B。
系统:小白用户最好使用最新版本的官方图像界面系统。本项目采用最新版本,无图像界面系统。:如果使用 ssh 树莓派系统连接无图形界面,需要依靠连接软件显示图形界面。我用的是 Mobaxterm ,使用免费版本。
2.2 传感器
温度、湿度、光强、PM2.5、CO五种浓度数据。原计划使用所有传感器 IIC 接口,挂载到同一个 IIC 外设。调试时用于阅读。 CO2 浓度的 SGP30 传感器调试不好,一直看不到数据,最后改用 串口驱动的 KQM6600 获取 CO2 浓度数据。
2.2.1 温湿度传感器 DHC1080
HDC1080是集成温度传感器的数字湿度传感器,具有优异的测量精度和超低功耗。具有14位测量分辨率,相对湿度精度为±2%,温度精度为±0.2°C,平均工作电流为uA级。
2.2.2 光强传感器 BH1750
BH1750FVI 它是一种用于两线串行总线接口的数字光强度传感器集成电路。该集成电路可根据收集的光强数据调整液晶或键盘背景灯的亮度。利用其高分辨率,可以探测到大范围的光强度变化。
2.2.3 PM2.5 传感器 GP2Y1014AU
GP2Y1014AU粉尘传感器是夏普开发的光学粉尘监测传感器模块。中间有一个大洞,空气可以自由流动。红外发光二极管和光晶管放置在对角位置。红外发光二极管定向发送红外线。当空气中有颗粒阻碍红外线时,光晶管接收到的红外线发生变化,因此信号输出引脚电压发送变化。其属性值如下; 供电电压;5-7V 工作温度;-10-65℃ 监测最小直径;0.8μm 灵敏度;0.5V/(0.1mg/m3)灰尘浓度每变化0).1mg/m3,输出电压变化0.5V。 树莓派 4B 上没有 ADC 所以要加一个外设 ADC 芯片。
ADS1115是德州仪器推出的IIC接口的16位ADC转换器,超小X2QFN或VSSOP 包装,低功耗(20)uA),宽电压输入2.0V-5.5V,可编程数据转换率8SPS-860SPS,四个单端输入或两个差异输入。可用于电池电压电流检测、低速便携式仪表和温度测量系统。 网上买这个传感器会带来 150Ω 电阻和一个 220u 按下图连接电容器。 LED 可直接引脚 GPIO 引脚上。AOUT 引脚直接接ADS1115 第一通道。反正我是这样接的。
2.2.4 CO2 传感器 KQM6600
本来打算用 SGP30 来采集 CO2 数据经过长时间的调试,驱动器无法很好地调整。最好换个传感器。
KQM6600可UART输出VOC\甲醛、CO2浓度数据,3-5V供电。使用起来很简单,直接用树莓派 UART 外设可以获取数据。
3 软件设计
软件设计一般分为主 UI 设计和传感器数据读取都是使用的 Python 语言。 总所周知,Python 它是一种跨平台语言,因此 UI 部分可以先在 Windows 系统系统,然后去树莓派 将传感器数据读取部分结合起来。
作者水平有限,以前没做过 UI 设计,一切复杂而简单,如何简单。
先选择一个 Python 图形界面引擎。首先想到的是 PyQt5.但想想以前从未接触过,学习时间成本太高了。鉴于图像界面的设计非常简单(简单),直接使用 Python 原生图像界面 tkinter 就够了。如果用曲线画图,用上 matplotlib 库。
3.1 界面设计
设计两个界面,一个界面显示五个数据的曲线图,一个界面显示表格。完美。下面的渲染。 非常 Very 简单的一个界面。这个界面是我在 windows 只要有模拟数据显示在系统上, Python 环境可以运行。
另一个界面,将所有数据制作成一个表,每秒更新一次最终数据,并将所有数据向前循环到一个位置。
#!/user/bin/env python3 # -*- coding:utf-8 -*- # author :Yi Zhenkai # create date:2022-04-20 # update date:2022-04-28 # function :Windows shift import tkinter as tk from tkinter import ttk import tkinter from tkinter import * import random import time import matplotlib.animation as animation from matplotlib import pyplot as plt import matplotlib from draw import Draw import getData from numpy import * import threading FREQUENCY = 500 #用于显示正常中文
标签 plt.rcParams['font.sans-serif']=['SimHei'] #用于正常显示负号 plt.rcParams['axes.unicode_minus'] = False matplotlib.use('TkAgg') class basedesk(object): def __init__(self, master): self.root = master self.root.config() self.root.title('环境参数监测') root.iconbitmap('lens.ico') # 更改窗口图标 screenwidth = root.winfo_screenwidth() # 屏幕宽度 screenheight = root.winfo_screenheight() # 屏幕高度 width = 1000 height = 500 x = int((screenwidth - width) / 2) y = int((screenheight - height) / 2) self.root.geometry('1400x800') # 大小以及位置 #self.root.geometry('{}x{}+{}+{}'.format(width, height, x, y)) # 大小以及位置 self.root.resizable(0,0) #界面不能放大缩小 self.init = curveface(self.root) class curveface(object): def __init__(self, master): self.master = master self.master.config(bg='white') #基准界面 curveface self.curveface = tk.Frame(self.master,) self.curveface.pack(fill='both', expand=True) self.btn = tk.Button(self.curveface,text='表格显示',command=self.change) self.btn.pack() self.draw = Draw(self.curveface) def change(self): self.curveface.destroy() tableface(self.master) class tableface(object): def __init__(self, master): self.master = master self.master.config(bg='white') self.tableface = tk.Frame(self.master,) self.tableface.pack(fill='both', expand=True) self.btn_back = tk.Button(self.tableface,text='曲线显示',command=self.back) self.btn_back.pack() columns = ['温度', '湿度', '光强', 'CO2', 'PM2.5'] self.table = ttk.Treeview( master=self.tableface, # 父容器 height=10, # 表格显示的行数,height行 columns=columns, # 显示的列 show='headings', # 隐藏首列 ) self.table.heading('温度', text='温度', ) # 定义表头 self.table.heading('湿度', text='湿度', ) # 定义表头 self.table.heading('光强', text='光强', ) # 定义表头 self.table.heading('CO2', text='CO2', ) # 定义表头 self.table.heading('PM2.5', text='PM2.5', ) # 定义表头 self.table.column('温度', width=100, minwidth=100, anchor=S, ) # 定义列 self.table.column('湿度', width=100, minwidth=100, anchor=S) # 定义列 self.table.column('光强', width=100, minwidth=100, anchor=S) # 定义列 self.table.column('CO2', width=100, minwidth=100, anchor=S) # 定义列 self.table.column('PM2.5', width=100, minwidth=100, anchor=S) # 定义列 self.table.pack(fill='both',pady=50) temp, humi, light, CO2, PM2_5 = getData.get_env_data() all_data = list(zip(temp, humi, light, CO2, PM2_5)) for index, data in enumerate(all_data): self.table.insert('', END, values=data) # 添加数据到末尾 t = threading.Thread(target=self.table_insert) t.start() def table_insert(self): while True: temp, humi, light, CO2, PM2_5 = getData.get_env_data() all_data = list(zip(temp, humi, light, CO2, PM2_5)) for x in range(10): self.table.insert('', x, values=all_data[x]) time.sleep(1) def back(self): self.tableface.destroy() self.init = curveface(self.master) anim = animation.FuncAnimation(fig=self.init.draw.fig, func=self.init.draw.update, interval=FREQUENCY, blit=True, repeat=True) anim.save() #writer='pillow' if __name__ == '__main__': root = tk.Tk() base = basedesk(root) anim = animation.FuncAnimation(fig=base.init.draw.fig, func=base.init.draw.update, interval=FREQUENCY, blit=True, repeat=True) root.mainloop()
3.2 matplotlib 画图
画图是这个设计最难的部分,也是因为以前基本上没有用过 Python matplotlib 画图的原因吧,真是让我绞尽脑汁,几经放弃。
这里先放代码。这里使用 animation 画动图,然后使用子图的方式把四个动图放置到一个界面上。
有点基础的同学完全可以依葫芦画瓢,很简单就可以再加几个子图上去。
#!/user/bin/env python3 # -*- coding:utf-8 -*- # author :Yi Zhenkai # create date:2022-04-20 # update date:2022-04-28 # function :Draw curves import random import matplotlib.pyplot as plt import numpy as np import matplotlib.animation as animation import tkinter as tk from tkinter import ttk from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg,NavigationToolbar2Tk import matplotlib import getData #用于显示正常中文标签 plt.rcParams['font.sans-serif']=['SimHei'] #用于正常显示负号 plt.rcParams['axes.unicode_minus'] = False matplotlib.use('TkAgg') #常量 RANGE = 10 FREQUENCY = 500 class Draw(object): def __init__(self, root): self.fig = plt.figure(figsize=(5, 4), tight_layout=True) ax_1 = self.fig.add_subplot(221)##设置坐标轴 ax_1.set_xlim(0, 10) #设置x轴的范围 ax_1.set_ylim(0, 100)#设置y轴的范围 ax_1.grid(axis='both') ax_1.set_title('温湿度曲线') my_x_ticks = np.arange(0, 11, 1) my_y_ticks = np.arange(0, 110, 10) plt.xticks(my_x_ticks) plt.yticks(my_y_ticks) self.t_x_line = [0] self.t_y_line = [0] self.h_x_line = [0] self.h_y_line = [0] self.line_t, = plt.plot(self.t_x_line, self.t_y_line, linestyle='-', label='温度', linewidth=1, color='red') self.line_h, = plt.plot(self.h_x_line, self.h_y_line, label='湿度', linestyle='-', linewidth=1, color='green') self.text_t = plt.text(3, 90, '', ha='center', va= 'bottom', fontsize=15) self.text_h = plt.text(6, 90, '', ha='center', va= 'bottom', fontsize=15) plt.ylabel("温湿度:℃ / %RH") # x轴的标签 plt.legend() ax_2 = self.fig.add_subplot(222) ax_2.set_xlim(0, 10) #设置x轴的范围 ax_2.set_ylim(0, 2000) #设置y轴的范围 ax_2.grid(axis='both') ax_2.set_title('光强曲线') my_x_ticks = np.arange(0, 11, 1) my_y_ticks = np.arange(0, 2110, 300) plt.xticks(my_x_ticks) plt.yticks(my_y_ticks) self.l_x_line = [0] self.l_y_line = [0] self.line_l, = plt.plot(self.l_x_line, self.l_y_line, linestyle='-', label='光强', linewidth=1, color='blue') self.text_l = plt.text(5, 1860, '', ha='center', va= 'bottom', fontsize=15) plt.ylabel("光强: lx") # x轴的标签 plt.legend() ax_3 = self.fig.add_subplot(223) ax_3.set_xlim(0, 10) #设置x轴的范围 ax_3.set_ylim(300, 1000) #设置y轴的范围 ax_3.grid(axis='both') ax_3.set_title('CO2 曲线') my_x_ticks = np.arange(0, 11, 1) my_y_ticks = np.arange(300, 1100, 100) plt.xticks(my_x_ticks) plt.yticks(my_y_ticks) self.c_x_line = [0] self.c_y_line = [0] self.line_c, = plt.plot(self.c_x_line, self.c_y_line, linestyle='-', label='CO2', linewidth=1, color='c') self.text_c = plt.text(5, 900, '', ha='center', va= 'bottom', fontsize=15) plt.ylabel("CO2: ppm") # x轴的标签 plt.legend() ax_4 = self.fig.add_subplot(224) ax_4.set_xlim(0, 10) #设置x轴的范围 ax_4.set_ylim(0, 200) #设置y轴的范围 ax_4.grid(axis='both') ax_4.set_title('PM2.5 曲线') my_x_ticks = np.arange(0, 11, 1) my_y_ticks = np.arange(0, 201, 25) plt.xticks(my_x_ticks) plt.yticks(my_y_ticks) self.p_x_line = [0] self.p_y_line = [0] self.line_p, = plt.plot(self.p_x_line, self.p_y_line, linestyle='-', label='PM2.5', linewidth=1, color='purple') self.text_p = plt.text(5, 175, '', ha='center', va= 'bottom', fontsize=15) plt.ylabel("PM2.5: ppm") # x轴的标签 plt.legend() canvas = FigureCanvasTkAgg(self.fig, master=root) # A tk.DrawingArea. canvas.draw() canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) # matplotlib的导航工具栏显示上来(默认是不会显示它的) toolbar = NavigationToolbar2Tk(canvas, root) toolbar.update() canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=tk.YES) # get_tk_widget()得到的就是_tkcanvas def update(self, c): getData.get_env_data() self.t_x_line = [i for i in range(0, RANGE)] self.line_t.set_data(self.t_x_line, getData.temp) self.text_t.set_text("T = %d" % getData.temp[9]) self.h_x_line = [i for i in range(0, RANGE)] self.line_h.set_data(self.h_x_line, getData.humi) self.text_h.set_text("H = %d" % getData.humi[9]) self.l_x_line = [i for i in range(0, RANGE)] self.line_l.set_data(self.l_x_line, getData.light) self.text_l.set_text("L = %d" % getData.light[9