室内温湿度检测系统设计
摘要
数字化和智能化的浪潮对传统的室内温湿度检测系统构成新的挑战,同时也带来了新的机遇。本课题将使用Raspberry Pi Pico开发具有MQTT(Message Queuing Telemetry Transport)通信功能的基于DHT20传感器的室内温湿度检测系统,能够通过网页的前端页面或手机应用查看测量值,同时也能在本地端通过基于SSD1306控制芯片的OLED显示屏读取测量值,并具有阈值蜂鸣器报警功能。本课题一方面在硬件上深入各模块驱动的底层原理、在软件上涉及128*64点阵显示算法的实现、基于Godot游戏引擎的UI的设计、意外情况的处理等,较为全面的阐述了室内温湿度检测系统的开发流程;另一方面,本课题将详细阐述Home Assistant开源智能家居平台与室内温湿度系统的MQTT通信流程。
关键词:Raspberry Pi Pico;MQTT;Home Assistant;Godot;SSD1306;DHT20
ABSTRACT
The wave of digitization and intelligence poses new challenges to traditional indoor temperature and humidity detection systems, while also bringing new opportunities. This project will utilize Raspberry Pi Pico to develop an indoor temperature and humidity detection system based on the DHT20 sensor with MQTT(Message Queuing Telemetry Transport) communication functionality. It will allow viewing of the measured values through a frontend webpage or mobile application, and also enable local reading of the measurements through an OLED display screen based on the SSD1306 control chip, with threshold buzzer alarm functionality. On one hand, this project delves into the underlying principles of each module driver in hardware, implements algorithms for 128*64 dot matrix display in software, designs UI based on the Godot game engine, and addresses handling of unexpected situations, providing a comprehensive exposition of the development process of the indoor temperature and humidity detection system. On the other hand, the project will elaborate on the MQTT communication process between the Home Assistant open-source smart home platform and the indoor temperature and humidity system.
Key words:Raspberry Pi Pico; MQTT; Home Assistant; Godot; SSD1306; DHT20
第 1 章 绪论
1.1 课题研究背景和意义
随着智能手机的发展以及数字化时代的到来,特别是近年来物联网(Internet of Things,简称IOT)概念的兴起与人工智能的爆发式发展,推动了智能化设备需求的增长。一方面,当今的传感器市场早已不再局限于工业领域。小区楼道里的光学感应灯、高铁上的烟雾报警器、河流水位警戒线上的液位检测器等等,各式各样的传感器在生活场景中得到了大量应用;另一方面,随着总体生活水平的提升,越来越多的家庭购置空调、加湿器、加热器等环境设备,室内环境检测系统具有空前的市场规模。
然而,随着社会数字化、智能化程度的提高,传统的室内环境检测系统很难满足当今市场复杂多变的需求。在时代革新和经济效益的驱使下,各传统行业都在积极进行数字化转型,借此提升企业核心竞争力[1]。在数年前,谷歌、苹果、小米等科技公司开始大力发展智能家居生态,市场上因此诞生了一系列智能家居设备,其中就包含多个基于室内温湿度检测系统的产品。如今用户能够轻易在手机、电脑、平板等设备上控制家中的智能设备,还可以根据家中传感器的数据,自定义家电自动化。近年来人工智能的高速发展,又进一步加快了智能化设备更替的脚步。
与此同时,当下环境中的不同设备之间的协作经常存在很多隔阂,甚至是相互不兼容[2]。随着市场上用于改善环境的产品数量和种类增多,多设备之间的协调运行成为了一个不得不关注的问题。由于室内温度场是一个复杂的物理场,它影响因素众多,例如太阳辐射、窗墙比、供暖方式、暖通设备设置参数等等[3]。因此,室内各处的温度往往存在偏差,在面积较大以及外墙较多的房间,这一问题尤为突出。而湿度也同样受到复杂的物理场影响。各设备测量值的偏差成为了阻碍多设备协调运行的原因之一。
为了解决这一问题,本课题在实现能够正常准确检测当前的温度和湿度,并在温度超过一定阈值后报警这一传统室内温湿度检测系统的基础上,将自身所检测的数据转化为JSON格式并通过MQTT协议发送到Home Assistant系统上的MQTT Broker,使其它设备能够订阅该室内温湿度检测系统的测量数据。此外,得益于强大的开源社区,Home Assistant支持绝大多数类型的物联网通信协议,并且打破了众多品牌的生态壁垒。该平台也有一套成熟的前端控制系统,用户能通过网页端或手机应用(APP)上实时查看检测数据。
1.2 国内外研究综述
1.2.1 温湿度传感器
截止到2024年,在价格低廉的温湿度传感器中,奥松电子生产的DHT11备受市场欢迎。即使在各大学术网站上有关温湿度检测系统的期刊以及学位论文中,采用DHT11作为温湿度传感器的研究也占据相当一部分。然而,产品官方近年来推出了其迭代产品DHT20,在价格几乎相等的前提下,产品性能得到了大幅提升:湿度测量误差由原来的±5%提升到±3%,温度测量误差由原来的±2℃提升到±0.5℃。但由于目前开源社区以及学术研究上有关的资料较少、DHT11和DHT20的数据格式不兼容、推出时间较近等因素,市场对其较为保守,如今仍有许多温湿度检测项目继续采用上一代产品DHT11作为温湿度传感器。
1.2.2 微控制器
室内温湿度检测系统本质作为一个嵌入式系统,离不开微控制器的控制。受到行业历史、学习成本、开发周期等多种因素影响,硬件领域在技术迭代上具有一定的滞后性。目前国内外仍有大量基于C51和STM32F系列芯片开发的温湿度检测系统项目。但这两个芯片推出时间较早,并不支持蓝牙和WLAN通信。若要在原本项目上实现IOT通信,则需要在原来的基础上外接无线模块来实现,但这必然导致项目成本的上涨和产品体积的增加,与当前追求降本增效的市场理念不符。近年来,随着物联网概念及相关技术的兴起,总部位于上海的乐鑫公司逐渐引起世界各地开发者的关注。该公司推出的ESP32系列微控制器集成了自家的ESP8266无线模块,支持蓝牙和WLAN通信,以极高的性价比在海内外赢得了广泛市场。乐鑫公司的成功也吸引着更多企业争夺物联网微控制器市场,例如英国树莓派基金会的Raspberry Pi Pico系列、Arduino公司的Arduino NANO 33 IoT、意法半导体的STM32Wx系列等等。
1.2.3 通信协议
物联网领域中有大量的通信协议,每一种都有自身的优缺点,需要根据应用场景选择适用的协议。其中Wi-Fi的传输距离较远,且应用广泛,很多家庭都有购置路由器。与Wi-Fi相比,ZigBee 技术相对成熟,功耗较低,但其缺点是速度慢,穿墙性能差,通信距离短,通常在100米左右[4]。LoRa拥有很长的通信距离和功耗优势,但同时也因其优势带来了传输速率低和延时较高的缺点,比较适合空旷的超大型场地和对延时性要求不太高的场合,不适合对延时性有一定要求的智能家居领域[5]。HaLow和LTE-M具有较高的传输速率和超远距离的传输距离,适合用于远距离的图像测试传输,如:室外环境监控、外部站点测试[6]。此外还有提供一对多消息发布的MQTT,以及低功耗的蓝牙等等。
1.2.4 数据交换格式
当今常见的数据交换格式包括XML、JSON和YAML等。XML格式类似于HTML语言,层级结构清晰,但由于重复性较高,导致数据量较大;JSON克服了XML的一些缺点,在保留了较好可读性的同时,具备更高的传输效率;YAML格式较为灵活,支持使用复杂的数据结构,但是对缩进的要求严格。
本课题采用的Home Assistant OS使用JSON进行MQTT通信。JSON被认为是发布和交换数据的有用格式,因为他它结合了XML的灵活性和众所周知的数据结构,如记录和数组[7]。
1.2.5 智能家居系统
当下物联网有着势不可挡的发展趋势并且技术日渐成熟,依托于物联网的智能家居电子设备也层出不穷,用途也越来越多,同时也提出了更加适合智能家居发展的解决方案[8]。目前市场主流通过智能家居系统向多个智能设备收发数据进行控制,例如谷歌公司的Google Home、苹果公司的HomeKit、三星公司的SmartThings等,其与自身公司的生态产品高度集成,具有良好的生态体验,但是存在一定的生态壁垒,几乎都无法接入自己的DIY设备。也有如Home Assistant的开源智能家居平台,具有良好的扩展性和跨平台性。
1.3 本课题主要内容
本课题将详细介绍基于Raspberry Pi Pico的具有MQTT通信功能的室内温湿度检测系统的设计过程。该过程包括温湿度传感器DHT20的驱动程序设计、OLED屏控制芯片SSD1306的驱动程序设计、基于Godot的像素字体编辑软件设计、电路原理图设计、Home Assistant服务器的配置和MQTT通信的建立。一方面,本课题将以全面的视角阐述基于Raspberry Pi Pico的具有MQTT通信功能的室内温湿度检测系统的工作流程,并深入探讨涵盖硬件和软件各部分的技术路线(如图1-1所示),为该领域的从业者提供实质性的帮助。另一方面,本课题还将积极探索硬件前沿领域,采用目前研究较少的DHT20和Raspberry Pi Pico这一类新兴产品作为本课题的研究对象。而在软件方面,本课题将涉及交互UI、服务器通信、显示算法等多个领域。
本课题一共分为六章,每章的大致内容如下:
第一章,绪论。主要阐述了室内温湿度检测系统的研究背景和意义,提出了传统的室内温湿度检测系统在数字化、智能化时代所面临的挑战和机遇,紧接着对当下室内温湿度检测系统发展的方向提出了看法,确立了本课题的主题。同时分析了当前国内外在该领域的研究进展以及存在的部分短板。
第二章,DHT20驱动程序设计。主要阐述了该温湿度测量模块的工作原理,以及硬件配置、初始化、数据采集和数据处理过程。
第三章,SSD1306驱动程序设计。主要阐述了OLED驱动芯片SSD1306的工作原理、指令集、硬件及软件初始化配置过程、字体设计软件开发和显示算法的实现。
第四章,电路设计。主要阐述了基于三极管开关电路的蜂鸣器驱动电路设计和外部上拉的\(I^2C\)电路设计和总体设计。
第五章,Home Assistant。主要阐述基于Raspberry Pi 4的Home Assistant OS安装及配置、MQTT工作原理、MQTT Broker配置、Raspberry Pi Pico的MQTT通信、前端实现和外部访问。
第六章,结论。进行对本课题工作的总结,提出对该领域未来发展方向的展望。
第 2 章 DHT20驱动程序设计
2.1 \(I^2C\)通信
DHT20的供电范围为2.2到5.5V之间,采用标准的\(I^2C\)协议进行通信。\(I^2C\)为双向两线式串列汇流线路标准,只需要两条线便能传输数据,其中一条是时钟线SCL(Serial Clock),另一条是数据线SDA(Serial Data)[9]。每个\(I^2C\)设备都有自己唯一的7位地址,用于主从机通信的建立,并根据读写操作分为读地址和写地址。
在\(I^2C\)通信中,当SCL为高电平时,SDA由高电平转为低电平,启动传输状态,即\(I^2C\)通信中的起始信号(START)。当SCL为高电平时,SDA由低电平转为高电平,停止传输状态,即\(I^2C\)通信中的停止信号(STOP)。在传输过程中,只有当SCL时钟信号处于低电平时,SDA线上的数据才能改变;相反,当SCL处于高电平时,SDA线上的数据被认为是稳定的[10],即SDA在SCL的每个时钟周期传输一位数据。\(I^2C\)通信的简易时序图如图2-1所示。
2.2 \(I^2C\)配置
在最开始,需要先创建一个\(I^2C\)对象,为其分配\(I^2C\)通信所需的引脚并配置相关参数。由于本课题的驱动程序均使用MicroPython编写,因此首先创建一个后缀为py的DHT20模块文件并导入machine模块中的I2C和Pin子模块。之后调用该模块的I2C((id, *, scl, sda, freq=400000, timeout=50000)函数进行相关配置。
在该函数中,id为用于识别该\(I^2C\)通信的唯一标识符;符号”*”表示该符号右侧的参数是仅关键字参数,需要指定关键字才能传递参数。例如第二个和第三个参数用于设定\(I^2C\)通信的SCL、SDA引脚,而本课题采用PIN21作为SCL、PIN20作为SDA,因此参数分别应为scl = Pin(21)和sda = Pin(20);第四个参数为SCL的最大频率;最后一个参数为最大等待时间,该参数在部分引脚不可用。
从微控制器(主机)发送数据到DHT20模块(从机)上需要调用\(I^2C\)对象的writeto(addr, buf, stop=True, /)函数。其中addr参数为该传感器的7位\(I^2C\)地址,其值为0x38;buf为需要发送的字节(或字节数组)数据;当stop为true时,收到NACK时发送停止位;符号”/”表示该符号左侧的参数为仅位置参数,需要根据形式参数的顺序传递参数。
从DHT20模块(从机)读取数据到微控制器(主机)上需要调用\(I^2C\)对象的readfrom_into(addr, buf, stop=True, /)函数。其中addr为该传感器的7位\(I^2C\)地址,其值仍为0x38;buf为从传感器接收的字节数组数据,数据的大小取决于buf数组的长度;当stop参数为True时,将会在传输结束后生成STOP条件。因此,在DHT20模块文件的前部分,需要定义一个字节数组用于临时存储读取数据。由于整个过程中最多接收7个字节的数据,所以将该字节数组的长度设为7。
2.3 初始化
根据产品官方的相关手册,传感器上电后需要不少于100毫秒的延迟用于系统启动,因此需要在初始化函数中调用time模块的sleep_ms(ms)函数执行至少100毫秒的延迟,其中ms参数为延迟的毫秒数。
之后发送0x71指令来获取一个字节的状态,并将返回的状态字节与0x18进行与运算,根据运算结果是否等于0x18来判断模块是否正常工作。其中0x71指令由0x38和写操作标记位1组成,前者占据高7位,后者占据最低位。其中0x38为DHT20模块的7位\(I^2C\)地址,布尔值1代表写地址操作。
2.4 数据采集
根据产品手册若要触发DHT20模块测量数据需要向其发送测量指令0xAC以及参数DATA0和DATA1,其中DATA0为0x33,DATA1为0x00,总共需要发送3字节数据(不包含地址字节),如图2-2所示。若要通过writeto()函数一次性发送多字节数据,需要先创建一个字节数组对象。然后调用bytearray(b’\xAC\x33\x00′)函数将三个字节的数据存入字节数组中并发送。接着调用sleep_ms()函数延迟至少80毫秒等待测量完成。
在延迟完成后调用\(I^2C\)对象的readfrom_into()函数接收数据。之后同样通过sleep_ms()函数延迟100毫秒左右,等待读取完成。
接收的数据共有7个字节,如图2-3所示。其中第一个字节为状态位,用于判断测量是否完成。第二个字节到第四个字节的高4位为湿度数据,共20位。温度数据则是从第四个字节的低4位到第六个字节,同样是20位。最后一个字节为CRC数据,可以用于CRC校验。若需要CRC校验,则在接收完第六个字节后发送ACK应答,否则发送NACK结束。本课题中不进行CRC校验。此外,发送的0x71由7位地址0x38和读操作标记位0组成。由于MicroPython将读写操作分成readfrom_into()函数和writeto()函数,因此两者的addr参数都仅填写模块的7位\(I^2C\)地址0x38。
在数据接收完成后,需要判断状态字节的第7位是否为0。若结果为0,则表示测量完成,否则继续等待。为了避免由于模块异常导致的无数据(0x00)情况,需要额外判断该状态字节是否等于0x00。最后让该测量程序每隔一定周期循环执行。自此,数据采集过程完成。
2.5 数据处理
在2.4的数据采集过程得到了一个7字节数据,为了将温度和湿度数据从中提取出来,并将其转化为可读数据,需要对其进行数据处理。
首先需要将温度和湿度数据两者从整体中分离出来。该数据中温湿度数据各占20位,因此需要执行一系列位移操作。首先将第二个字节数据向左位移12位,第三个字节数据向左位移4位,第四个字节向右位移4位后与0x0F进行与运算。之后将这三者数据进行或运算即可得到完整的20位湿度数据。同理,将第四个字节数据与0x0F进行与运算后向左位移16位,第五个字节向左位移8位,之后将这两者数据与第六个字节进行或运算即可得到完整的20位温度数据。
但上述过程中得到的仍是不可读数据,需要通过公式运算将其转换为可读数据。在产品手册中,给出了以下几个公式:
(1)相对湿度转换
$$RH[\%]=(\frac{S_{RH}}{2^{20}})*100\%\tag{$2-1$}$$
(2)温度转换
$$T[\%]=(\frac{S_{T}}{2^{20}})*200-50\tag{$2-2$}$$
其中\(S_{RH}\)和\(S_T\)分别为上文中所提取的湿度和温度数据。为了简化运算,可以将20的20次方简化成1048576。通过公式转化后,分别得到了摄氏温度和相对湿度。由于这两个数据是浮点数据,因此需要通过round(n, 2)函数对数据四舍五入保留两位小数。其中第一个参数为需要处理的数据,第二个参数为要保留的小数位。
为了符合Home Assistant OS平台的MQTT通信协议标准,还需要将数据序列化,将其转化为JSON格式。JSON是一个轻量级的数据交换格式,JSON数据由一组键值对构成,每个参数都是一个字符串,而对应的值可以是字符串、布尔值、数字等类型。本课题需要传输温度和湿度数据,JSON格式应为{“temperature”: t, “humidity”: h},其中t和h分别代表浮点类型的温度和湿度数据。最后,为了让该数据能够被主文件调用,使用global将该JSON数据声明为全局变量。
在本章中,介绍了\(I^2C\)的基本概念,并为模块编写了了涵盖初始化、数据测量、数据分析和数据归一化的驱动程序。至此,DHT20的驱动程序设计完成。
第 3 章 SSD1306驱动程序设计
3.1 SSD1306基础工作原理
SSD1306是128*64点阵OLED屏幕的控制芯片,支持1.65V到3.3V的逻辑IC供电和7V到15V的面板驱动供电。该模块支持8080接口、6800接口、4线SPI、3线SPI和通信协议。本课题在此仍采用\(I^2C\)通信。有关\(I^2C\)通信协议的介绍详见2.1。
3.1.1 GDDRAM
GDDRAM的全称为Graphic Display Data RAM(图形显示数据存储器)。GDDRAM是一个位映射静态随机访问存储器(RAM),该存储器的大小为128*64位,并被垂直分为8个页面(Page),每个页面由8个垂直排列的COM(行单元)和128个水平排列的SEG(列单元)组成从而用于点阵显示,如图3-1所示。
当一个字节的数据写入GDDRAM后,同一页中当前地址指针所对应的SEG中所有COM都将被填充(占8位)。数据的D0位写入顶行,数据的D7位写入底行,如图3-2所示。
3.1.2 寻址模式
SSD1306中有3种不同的内存寻址模式:页寻址模式、水平寻址模式和垂直寻址模式,本课题采用页寻址模式。
在页寻址模式下,对RAM进行一次读写操作后,列地址指针将自动加一。当列地址指针到达列结束地址,列地址指针位置将重置为列起始地址,在这一过程中页地址指针不变。若要访问下一页的RAM,则需要用户通过指令设置目标页。
在页寻址模式下,通常需要执行以下几个步骤来定义相关指针的起始位置:通过0xB0到0xB7之间的指令设置页地址指针的位置;通过0x00到0x0F之间的指令设置列地址指针起始位置的低四位;通过0x10到0x1F之间的指令设置列地址指针起始位置的高四位。之所以需要分别设置起始位置的高4位和低4位,是因为半字节数据无法存储128个地址。
3.2 初始化
3.2.1 开始工作
与DHT20驱动程序设计时相同,最开始需要调用I2C()函数为其创建\(I^2C\)对象,配置方法详见2.2。该模块在硬件上支持两个7位\(I^2C\)地址(表3-1),分别为0x3C和0x3D,则写地址分别为0x78和0x7A。由于该模块为一个显示产品,因此绝大部分情况下没有必要进行读地址操作。
位[7] | 位[6] | 位[5] | 位[4] | 位[3] | 位[2] | 地址位 | 读写位 |
---|---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 1 | 0 | SA0 | R/W# |
SSD1306控制芯片主要有两种\(I^2C\)传输模式,指令模式和数据模式。指令模式用于配置OLED显示屏属性,数据模式则是传输要显示的内容。该模块的通信内容又分为控制字节和数据字节。在SSD1306的通信过程中,首先是向模块写入1个控制字节,然后写入1个数据字节,循环往复(如图3-3所示)。
控制字节的第7位为\(C_o\),第6位为D/C#,剩下6位默认为0(表3-2)。\(C_o\)为连续位,值为1时,发送完数据字节后必须再发送一个控制字节;值为0时,后续只发送数据字节。D/C#为数据/控制模式选择位,值为0时,下一个字节发送的是控制字节;值为1时,下一个字节发送的是数据字节,并将其存储在GDDRAM中,每写入一次数据,GDDRAM的指针地址自动加一。因此,在仅发送一次控制字节的情况下,执行指令模式时控制字节的值为0x00,执行数据模式时控制字节的值为0x40。
连续位 | 模式位 | 位[5] | 位[4] | 位[3] | 位[2] | 位[1] | 位[0] |
---|---|---|---|---|---|---|---|
\(C_o\) | D/C# | 0 | 0 | 0 | 0 | 0 | 0 |
由于SSD1306控制芯片涉及的指令众多,首先要编写一个指令发送函数write(cmd),参数cmd为要发送的指令。然后调用bytearray([0x00, cmd])将对应指令模式的控制字节和数据字节组成一个字节数组。最后调用I2C模块中的writeto()函数将其写入模块中。至此,指令发送函数write(cmd)编写完成。
3.2.2 上电操作
若要启动OLED显示屏面板,首先需要通过电荷泵指令为其上电。当A[2]为0时,电荷泵停止,指令为0x14;当A[2]为1时使能电荷泵,指令为0x10。此外,在发送该指令前,需要先发送0x8D指令(表3-3)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | 8D | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
0 | A[7:0] | * | * | 0 | 1 | 0 | \(A_2\) | 0 | 0 |
3.2.3 基本指令
上电后,需要通过基本指令点亮显示屏。在SSD1306中有四个基本指令,分别是对比度设置指令、显示屏填充指令、屏幕反转指令和显示屏开关指令。
在对比度设置指令中,需要通过双字节指令设置显示屏从1到256的对比度值,显示屏的对比度随值的增加而增大,该指令的复位值为0x7F(表3-4)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | 81 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
0 | A[7:0] | \(A_7\) | \(A_6\) | \(A_5\) | \(A_4\) | \(A_3\) | \(A_2\) | \(A_1\) | \(A_0\) |
在显示屏填充指令中,当指令为0xA4时,恢复显示RAM数据;当指令为0xA5时,填充显示屏。该指令的复位值为0xA4(表3-5)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | A4/A5 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | \(X_0\) |
在屏幕反转指令中,当指令为0xA6时,屏幕正常显示;当指令为0xA7时,屏幕反转显示。该指令的复位值为0xA6(表3-6)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | A6/A7 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | \(X_0\) |
在显示屏开关指令中,当指令为0xAE时,显示屏关闭;当指令为0xAF时,显示屏打开。该指令的复位值为0xAE(表3-7)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | AE/AF | 1 | 0 | 1 | 0 | 1 | 1 | 1 | \(X_0\) |
3.2.4 硬件配置指令
在初始化过程中,需要对硬件进行配置,其中包括起始行设置指令、重映射指令、多路复用比指令、扫描方向指令、显示偏移指令、COM引脚配置指令。
起始行设置指令用于设定显示存储器开始行寄存器的值,范围为0x40到0x7F,该指令的复位值为0x40(表3-8)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | 40~7F | 0 | 1 | \(X_5\) | \(X_4\) | \(X_3\) | \(X_2\) | \(X_1\) | \(X_0\) |
在重映射指令中,当指令为0xA0时,将1到127列分别映射到SEG0到SEG127;当指令为0xA1时,将1到127列分别映射到SEG127到SEG0。该指令的复位值为0xA0(表3-9)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | A0/A1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | \(X_0\) |
多路复用比指令需要通过双字节指令将默认的63路复用模式切换为任意的多路复用比。范围(N)从16到63,分别由从0x0F到0x3F的指令决定。输出端子COM0到COM63将被切换到相应的COM信号。该指令的复位值为0x3F(表3-10)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | A8 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
0 | A[5:0] | * | * | \(A_5\) | \(A_4\) | \(A_3\) | \(A_2\) | \(A_1\) | \(A_0\) |
在扫面方向指令中,当指令为0xC0时,COM输出扫描方向为从COM0到COM[N-1];当指令为0xC8时,COM输出扫描方向为从COM[N-1]到COM0,其中N为多路复用指令中的范围N。该指令复位值为0xC0(表3-11)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | C0/C8 | 1 | 1 | 0 | 0 | \(X_3\) | 0 | 0 | 0 |
显示偏移指令需要通过双字节指令设置0到63行的偏移量。分别由从0x00到0x3F的指令决定。该指令的复位值为0x00(表3-12)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | D3 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 |
0 | A[5:0] | * | * | \(A_5\) | \(A_4\) | \(A_3\) | \(A_2\) | \(A_1\) | \(A_0\) |
COM引脚配置指令需要通过双字节指令设置COM信号引脚以匹配OLED面板布局。当\(A_4\)为0时,使用顺序COM引脚配置;当\(A_4\)为1时,使用替代COM引脚配置。\(A_4\)的复位值为1;当\(A_5\)为0时,禁用COM左右重新映射;当\(A_5\)为1时,启用COM左右重新映射。\(A_5\)的复位值为0(表3-13)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | DA | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0 |
0 | A[5:4] | 0 | 0 | \(A_5\) | \(A_4\) | 0 | 0 | 1 | 0 |
3.2.5 计时及驱动设定指令
计时及驱动设定指令主要包括设置显示时钟分频比/振荡器频率指令、设置预充电周期指令、设置\(V_{COMH}\)(COM高电平信号)取消选择电压指令和不执行指令。
设置显示屏时钟分频比/振荡器频率指令需要通过双字节指令设置,A[3:0]用于定义时钟分频比,分频比为A[3:0]+1。该部分复位值为0000b;A[7:4]用于设定时钟振荡器频率FOSC,设定区间为0000b到1111b。振荡器的值随着A[7:4]值的增加而增大,反之亦然。该部分的复位值为1000b(表3-14)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | D5 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
0 | A[7:0] | \(A_7\) | \(A_6\) | \(A_5\) | \(A_4\) | \(A_3\) | \(A_2\) | \(A_1\) | \(A_0\) |
设置预充电周期指令需要通过双字节指令设置,该指令用于设置预充电周期的持续时间,间隔时间以DCLK(显示屏时钟分频比)的个数来计算,复位后相当于两个DLCK。A[3:0]和A[7:4]分别用于设置第一阶段和第二阶段周期,两个周期的最高DCLK均为15,其中0为无效值。两个周期的复位值均为0x02(表3-15)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | D9 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 1 |
0 | A[7:0] | \(A_7\) | \(A_6\) | \(A_5\) | \(A_4\) | \(A_3\) | \(A_2\) | \(A_1\) | \(A_0\) |
设置\(V_{COMH}\)取消选择电压指令需要通过双字节指令设置,当值为0x00时,取消选择电压为0.65V与\(V_{CC}\)的乘积;当值为0x20时,取消选择电压为0.77V与\(V_{CC}\)的乘积;当值为0x30时,取消选择电压为0.83V与\(V_{CC}\)的乘积(表3-16)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | DB | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 1 |
0 | A[6:4] | 0 | \(A_6\) | \(A_5\) | \(A_4\) | 0 | 0 | 0 | 0 |
不执行指令由0xE3组成,没有实际的意义。
3.2.6 页寻址设定指令
在页地址寻址模式中,主要考虑设置内存寻址模式指令、设置页地址指针位置指令、设置列地址指针高四位指令和设置列地址指针低四位指令。
设置内存寻址模式指令需要通过双字节指令设置,当值为0x00时,采用水平寻址模式;当值为0x01时,采用垂直寻址模式;当值为0x10时,采用页地址寻址模式;当值为0x11时无效。该指令的复位值为0x10。本课题采用页地址寻址模式,因此需要先后发送0x20和0x10指令(表3-17)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | 20 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
0 | A[1:0] | * | * | * | * | * | * | \(A_1\) | \(A_0\) |
设置页地址指针位置指令用于设置写入的页,其范围为PAGE0到PAGE7,分别由从0xB0到0xB7的值决定(表3-18)。
D/C# | Hex | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|
0 | B0~B7 | 1 | 0 | 1 | 1 | 0 | \(X_2\) | \(X_1\) | \(X_0\) |
设置列地址指针高四位指令用于设置列地址指针的高四位值,其范围为0x00到0x0F。复位值为0x00;设置列地址指针低四位指令用于设置列地址指针的低四位值,其范围为0x10到0x1F。复位值为0x10。两者共同组成一个列地址指针。
3.3 8*8阵列字体设计软件开发
由于每一页是由1288的点阵单元组成的,且在页地址寻址模式下每执行一次写入操作列地址指针就要进一位,每128列为一个周期,因此使用88的像素字体较为合理。
因为一个8*8字体包含64位数据,所以一个字体占8个字节大小,故一个大小为8的列表可存储一个字体数据。新建一个用于存储字体的字体模块并在其中创建一个名为Font8x8的列表,以每8个字节元素为一组,依次为其分配从32到126所对应的ASCII码字符,为了增强列表可读性,需要进行适当备注和排版。
在完成字体库的创建后,需要开发一个应用程序用于设计字体。由于本课题中Raspberry Pi Pico的MicroPython开发环境Thonny、电路设计软件KiCad和智能家居系统Home Assistant都具有极高的跨平台性,开发的字体设计软件也理应具有良好的跨平台性,因此本课题将使用开源游戏引擎Godot(4.0版本)进行相关开发。目前Godot支持发布的平台有移动平台(iOS、Android)和桌面平台(Windows、 macOS、Linux、UWP、BSD、Haiku),使用HTML5和WebAssembly导出到Web以及VR平台[13]。虽然Godot引擎在3D渲染上仍落后于Unity和虚幻引擎,但在2D性能和渲染上非常优秀,还具有轻量化的优势。
在Godot中首先是创建一个以Control节点为根节点的主场景,Control节点是所有GUI控件的基类,用于绘制程序的主界面。然后添加一个Panel节点作为子节点,用于充当UI的底板。之后继续在根节点添加一个HBoxContainer节点作为子节点,该节点为一个容器,用于将子控件横向排列。
此外在项目中创建一个以VBoxContainer节点为根节点的列场景,并在主场景中的HBoxContainer节点中导入8个相同的该节点作为子节点,导入的节点右侧应有场记板图标。该类节点仍为一个容器,用于将子控件纵向排列。至此,主界面的节点配置完成(图3-4)。
在列场景中,在根节点下添加一个GridContainer节点和一个TextEdit节点作为子节点,其中GridContainer用于将子控件按照网格排列布局,TextEdit用于显示和提取文本。
还需在项目中创建一个以Button为根节点的单元格场景并在该场景中的Button根节点创建脚本。在脚本开头创建一个默认为false的布尔型变量switch,用于标记该按钮否被按下。之后在界面右侧节点选项中选择BaseButton底下的pressed()函数,并关联该脚本。
pressed()函数在关联后会自动添加到该脚本底部,每当按钮执行按压操作时该函数执行一次。当action_mode为ACTION_MODE_BUTTON_PRESS时按钮按下时发出信号,否则在按钮归位时发出信号,本课题采用默认值,即按下后发出信号。
在pressed()函数中,对switch进行取反操作,从而让每次按下按钮后自动切换状态值。然后调用get_parent()获取当前节点的父节点,并执行该父节点的_run()函数。此刻项目中还没有该节点的父节点及其_run()函数,将会在后面配置。最后从脚本编辑页面回到2D界面,启用Button属性中的toggle_mode使按钮工作在切换模式;在theme属性中新建一个theme主题,并进入到主题设置,在StyleBoxFlat中配置按钮在正常、鼠标悬浮和按压时的视觉属性(图3-5)。
回到前面创建的列场景中,在GridContainer节点创建脚本。在脚本开头使用preload()函数预加载上文中创建的单元格场景并赋值到新对象Grid中。然后再创建一个对象text_edit用于绑定TextEdit节点。在函数的初始化函数中,调用instantiate()函数生成继承了Grid的grid对象,然后调用add_child(grid)函数将其添加到子节点中,并通过循环函数执行8次,最终在垂直方向生成了8个单元格,对应SSD1306页地址寻址中列地址指针的各个COM。之后给text_edit的text属性赋值”0”用于初始化显示数据。
之后还需创建一个_run()函数用于鼠标每点击一次后计算新数据。首先创建一个int类型变量byte,并赋值0x00。然后通过调用get_child_count()获取当前子字节数量i,并使用for循环执行i次循环。在每次循环中调用get_child(i)从而获取当前子节点所对应的行数,之后通过if语句判断该行是否被点亮,即判断switch变量是否为true。为true时,先将0x01向左位移当前的行数i,然后与byte进行或运算并将值返回到byte中;为false时,不执行操作。最后将得到的byte赋值到text_edit的text属性中用于在UI上显示(如图3-6)。
至此,字体设计软件的逻辑部分设计完毕,此外还需要对UI布局和节点属性进行一系列调整,使其在视觉上合理。最后,每一列底部显示的十六进制数即为SSD1306控制芯片中列地址指针要写入的数据。
3.4 显示算法
本课题将编写一个用于在指定页显示字符的函数write_text(text, line)。其中text为要显示的数据,line为目标页。首先使用for语句执行8次循环,这8次循环分别对应SSD1306中的8个页地址,并在每次循环中都会计算对应的页地址指针指令。
在计算完页地址指令后,判断当前页是否符合目标页。若不符合,进入下一个循环;若符合,设置页指针地址和获取要发送数据的长度。紧接着使用for语句遍历发送数据的每个字符,获取各个字符的字体库坐标。
在获取各个字符的字体库坐标时,还需要使用for语句进一步遍历该字符对应的8*8点阵的列数,并在遍历过程中一共发送8次列数据,从而使列地址指针完成一个字符图像数据的写入。
完成数据发送后,需要将空数据写入剩余列使列地址指针返回到该页首列。用显示宽度(128列)减去发送的列数即可得到剩余列数,之后通过write_text()函数发送相应的空数据,即发送0x00。
最后还需要编写页刷新函数,只需要对所有列写入0x00即可实现。至此,显示算法的编写工作完成。
在本章中,介绍了SSD1306的基本工作原理以及常用的指令集;使用跨平台游戏引擎编写字体设计软件;并在最后设计了基于该控制芯片的显示算法(如图3-7)。
第 4 章 电路设计
本章将讲述室内温湿度检测系统的电路设计,包括\(I^2C\)电路、蜂鸣器驱动电路和总体设计三部分。该部分使用开源电路设计软件KiCad完成。
4.1 \(I^2C\)电路
由于\(I^2C\)通信中的SCL和SDA都采用开漏输出结构,在接地时被看作是低电平,而在悬空时呈高阻态没有确定的电平,因此需要接入上拉电阻将电平拉高。又因为Raspberry Pi Pico的\(I^2C\)电路没有内部上拉电阻,所以需要在SCL和SDA线上各接4.7K(经验值)的外部上拉电阻。
4.2 蜂鸣器驱动电路
蜂鸣器分为有源蜂鸣器和无源蜂鸣器,两者的主要区别在于前者内部有震荡源,在其两端加上合适的直流电压即可工作,而后者需要通过方波信号进行控制。有源蜂鸣器的优点在于控制方便,而无源蜂鸣器的优点在于价格相对便宜、能够控制声音频率。本课题采用有源蜂鸣器,只需在其两端加上5伏直流电压即可工作。由于引脚的输出电压无法达到5V,需要通过三极管开关电路进行控制。
开关三极管是一种功能特殊的三极管,它的外观和一般三极管一样,但是普通三极管工作在放大区对信号进行放大,而开关三极管对电路实现开关功能是通过三极管工作在饱和区和截止区来实现的[11]。
电路由蜂鸣器、续流二极管、NPN三极管、470欧和250欧电阻、0.1μF滤波电容和220μF电解电容组成。为了防止开关电路时在蜂鸣器两端产生尖峰电压并使其损坏,需要在蜂鸣器两端接上续流二极管。为了过滤掉交流信号,需要在电路中接入一个滤波电容。目前,通常将多个不同种类和容值的电容器并联成一个频段滤波模块用于滤波处理[12]。考虑到噪声频率超出电容自谐振频率的情况,还可以并联一个200μF的电解电容。电阻R1为限流电阻,防止电流过大对三极管造成损坏,同时防止三极管损坏造成的短路。电阻R4也为限流电阻,防止电流过大对蜂鸣器造成损坏。NPN三极管用于充当控制蜂鸣器的开关,当基极为低电平时,三极管处于截止状态,此刻相当于电路断开,蜂鸣器处于关闭状态。而当基极为高电平时,三极管处于饱和状态,此刻失去放大功能,相当于电路导通。在选择三极管时要注意电气属性,确保不会因为超出规定电压而导致三极管击穿或当基极处于高电平状态时,三极管仍工作在放大区的意外情况。
4.3 总体设计
总体设计包含电路和蜂鸣器驱动电路连两个外部电路,两个电路均由Raspberry Pi Pico供电。其中VBUS引脚的5V输出需要通过Raspberry Pi Pico自身的USB供电提供。电路原理图如图4-1所示。
在本章中,设计了外接模块的\(I^2C\)通信电路和基于三极管开关的蜂鸣器驱动电路,最后经验证,本电路能够长时间稳定运行。
第 5 章 Home Assistant
5.1 在Raspberry Pi 4上安装Home Assistant OS
在安装之前,需要准备以下几点:Raspberry Pi 4(树莓派4)、32GB及以上的微型SD卡、USB读卡器、以太网电缆和家用路由器。其中树莓派是一款目前为止最受欢迎的基于 ARM(Advanced RISC Machines)的单板计算机,树莓派具有标准计算机的所有功能,以 MicroSD 卡为内存硬盘,无需任何配置即可连接鼠标、键盘和屏幕[14]。
在准备完以上内容后,首先是在树莓派基金会官网下载并安装Raspberry Pi Imager。安装后打开并在Raspberry Pi Device(树莓派设备)选择Raspberry Pi 4。在Operating System(操作系统)选择RPi4版本的Home Assistant OS。之后将微型SD卡通过USB读卡器插入电脑,在Storage(存储)选择该SD卡。一切就绪后点击Next(下一步)按钮,等待Home Assistant OS写入存储卡中。(如图5-1所示)
成功将Home Assistant OS系统写入微型SD卡后,将其插入到Raspberry Pi 4当中,同时通过网线与路由器建立网络连接,并确保其与计算机连接到相同网络。然后打开Raspberry Pi 4的电源,等待系统启动。系统成功启动后,在计算机浏览器输入homeassistant.local:8123或http://X.X.X.X:8123(X.X.X.X为设备的ip地址,可通过路由器查看)即可访问该智能家居系统的前端页面。之后根据网页指引创建账号。
5.2 建立MQTT通信
5.2.1 MQTT通信基本原理
MQTT 通信协议是以Publish/Subscribe(发布/订阅)的消息传递模式为主的物联网通信协议,具有简单易实现、支持可调 Qos(服务质量)以及跨平台使用的优点[15]。每条发布的消息都有一个主题,客户端可以使用该主题来订阅代理[16]。MQTT通信中有MQTT Broker(MQTT服务端)充当中转站,一方面从各接入点订阅客户端发布的Topic(主题),另一方面将相关数据分发给订阅了该主题的客户端。
5.2.2 在Home Assistant上配置MQTT Broker
进入到Home Assistant OS主页,点击Settings(配置)>Add-ons(加载项)>Add-on store(加载项商店),找到Mosquitto broker插件并安装(如图5-2所示)。然后在Settings(配置)> Devices & Services(设备与服务)> Integrations(添加集成)中添加MQTT,也可通过页面底部已发现的集成设备一栏进行添加,在添加的过程中需要配置用户名和登录密码。
在成功添加MQTT集成后,进入集成界面,有一个名为core-mosquitto的实体,点击右边的选项,进入到MQTT设置页面(如图5-3所示)。截至该插件的6.4.0版本,该页面包含重新配置MQTT、发送数据包和监听主题三项内容。通过发送数据包和监听主题,可以测试与设备的MQTT通信是否正常工作。接下将配置设备端的MQTT通信。
5.2.3 在Raspberry Pi Pico上配置MQTT
首先新建一个后缀为py的文件用于编写通信模块代码。在文件的开头从umqtt.simple导入MQTTClient模块用于MQTT通信;导入network模块用于配置WLAN属性;导入time用于通信延时。
在导入以上模块后,创建两个字符串型变量:ssid和password。ssid用于存储需要连接的无线网络名称,password用于存储该无线网络的密码。
创建client对象,并调用MQTTClient()函数为其赋值。该函数从先到后包含5个形式参数:CLIENT_ID、HOST、PORT、USER和PASSWORD。分别代表客户端唯一标识符、服务器地址、端口号、MQTT Broker用户名和密码。其中客户端唯一标识符往往由客户端自身决定;服务器地址为homeassistant.local;MQTT用户名及密码为先前安装MQTT Broker时创建的账号及密码;端口号默认采用1883。上述参数中端口号为整数类型,其余都为字符串类型。此外还需创建一个TOPIC对象用于存储通信数据。
接着创建网络连接函数connect_wlan(),调用network.WLAN(interface_id)函数创建网络接口,其参数可为network.STA_IF和network.AP_IF。其中前者为STA(站点),是网络中的各个终端;后者为AP(接入点),是网络的中心节点。在此处采用STA接口,即创建一个wlan对象并为其赋值network.WLAN(network.STA_IF)。
创建STA站点后,调用该对象的active(True)函数使其开始工作。开始工作后,需要连接到现有的无线网络,因此需要调用该对象的connect(ssid, password)函数使其连接到特定的无线网络,其中ssid和password分别为前文中创建的无线网络名称和密码。之后需要一个循环函数判断网络连接是否成功,若成功,进入到下一步;若失败,调用time.sleep()函数,在一定时间后重新连接,循环往复。
判定网络连接是否成功,需要调用网络接口对象的isconnected()函数,其返回布尔值结果。在连接成功后,可以调用wlan.ifconfig()[0]函数获取接入点的ip地址。
除了网络连接函数,还需创建connect_mqtt_broker()和publish(message)函数,前者用于连接到Home Assistant平台上的MQTT Broker;后者用于发布话题,其中参数message是包含温度和湿度的JSON数据。考虑到数据传输失败的情况,需要采用try-except结构进行意外处理。在try中调用client.connect(),在except中写入异常时需要执行的操作或输出的调式日志。这样当连接MQTT Broker失败时就会执行except内的操作。
同理,也需要考虑到数据发布失败的情况,因此在publish(message)函数中仍采用try-except结构进行意外处理。在try中调用client.publish(TOPIC, message)函数,其中TOPIC为前文创建的MQTT话题,message则为话题传输的JSON数据(图5-4)。在except中先后调用先前创建的connect_wlan()和connect_mqtt_brokerr(),当发布话题失败时该系统会尝试重新连接到无线网络,从而解决了WLAN通信中偶尔存在的掉线问题。
最后在主文件中调用该模块文件,在系统初始化中先后调用connect_wlan()函数和connect_mqtt_broker()函数,用于将系统连接到无线网络中,然后在主循环中调用publish()函数用于定时发布话题。
至此Raspberry Pi Pico与Home Assistant平台的通信建立完成,可在Home Assistant平台进入MQTT集成,通过其core-mosquitto实体里的监听主题一栏中订阅前文创建的TOPIC话题对象进行监听,若有检测数据显示则代表通信成功建立。
5.3 前端UI
此刻Home Assistant虽然能接收到来自室内温湿度检测系统的JSON格式数据,但还需通过配置homeassistant目录下的configuration.yaml文件来使Home Assistant能够识别其中各键值对对应的数据类型。由于Home Assistant没有内置文件编辑器,因此需要通过加载项商店安装File editor后才能访问该目录下的配置文件。
在安装完文件编辑器后,首先是在defalut_config键值对后面适当的位置创建一个mqtt键值对,然后在该键值对中创建sensor键值对,并通过”-”符号创建两个数组。数据包含以下几个参数:name、unique_id、state_topic、value_template和unit_of_measurement,其分别为属性名、唯一标识符、客户端话题、数据模板和数值单位(图5-5)。
将第一个数组设置为温度数据,其中name为JSON数据中的Temperature; unique_id为唯一标识符,本课题采用dht20_0_temperature;state_topic为在Raspberry Pi Pico 网络配置文件中定义的TOPIC话题sensor/dht20;value_template为{{ value_json.temperature }},该模板专门用于提取温度数据;unit_of_measurement为摄氏度单位符号”℃”。
同理,将第二个数组设置为湿度数据,name为JSON数据中的Humidity,unique_id为唯一标识符,本课题采用dht20_0_humidity;state_topic为sensor/dht20;value_template为{{ value_json.humidity }},该模板专门用于提取湿度数据;unit_of_measurement为相对湿度单位”%”。
成功配置configuration.yaml文件后,需要在开发者工具中检查更改的配置内容,并点击重新启动选项进行快速重载。重载完后,应当能够在Home Assistant默认主页看到名为Temperature和Humidity的测量数据。通过配置>仪表盘进入到仪表盘选项后,选择添加仪表盘>从头开始的新仪表盘即可在系统列表中添加自定义仪表盘。通过列表进入自定义仪表盘后,选择编辑仪表盘,即可选择各种样式用于显示测量数据。至此,室内温湿度检测系统的前端UI工作完成(图5-6)。
5.4 外部访问
若要从外部访问安装在本地的Home Assistant服务器,主要有两种方法,一是购买Home Assistant Cloud,二是通过动态域名解析技术将家中的动态ip地址绑定到特定域名,从而实现外部访问。但这两者方案都很难在国内实现,前者一方面需要支持较高的订阅费,另一方面由于Assistant Cloud服务由国外商提供,对网络有一定的要求;后者需要Internet Service Provider(互联网服务提供商,简称ISP)开放家中网络的443、80和8123端口,其中443端口主要用于HTTPS服务、80端口主要用于HTTP服务、8123端口主要用于Home Assistant服务。
在本章中,建立了微控制器和服务器之间的MQTT通信,通过配置Home Assistant的配置文件,实现了在网页或手机应用上的前端访问。
第 6 章 结论
6.1 工作总结
从模块驱动程序的编写、电路的设计,再到设备间的通信、服务器的配置、工具的开发,本课题一方面深入底层原理,从硬件到软件层面较为全面地阐述了室内温湿度检测系统的设计流程及工作机制,另一方面本课题成功开发了温湿度传感器DHT20和OLED控制芯片SSD1306的驱动程序,以及简易的8*8点阵字体设计软件,能够在本课题以外的同类项目中广泛运用。最终成功实现课题目标,建立了Raspberry Pi Pico与Home Assistant的MQTT通信。不仅为该行业在硬件的选择上注入了新的活力,还以广大消费者的角度,为国内较为封闭的智能家居生态提供了一个新的发展思路。
6.2 研究展望
由于篇幅限制、个人精力以及时间问题制约,部分设想的扩展功能未能实现。此外,本课题仍有诸多不足之处,需要进一步完善:
- SSD1306控制芯片驱动所采用的字体大小为8*8,因此不适用于显示笔画较多的汉字,需要进一步编写更复杂的算法来支持汉字显示。此外,还可以设计图标以及简易的UI系统使当前状态清晰可见,例如当没有网络连接时显示无网图标并持续闪烁。
- 支持的通信协议过于单一,可以添加对蓝牙协议和串口通信的支持。
- 可以引进深度学习模型分析检测场景的环境特征。通过热成像传感器获取室内环境的分布特征,然后通过摄像头或激光雷达建立室内场景数据,最后通过模型分析将两者结合,得出影响环境的因素,并在一定程度上预测未来的室内环境变化趋势。
参考文献
[1] 王林. 美的集团数字化转型中的财务战略研究[D]. 武汉纺织大学,2023.
[2] 刘继林. 基于中间件的iOS系统多设备协作机制研究[D]. 四川:电子科技大学,2022.
[3] 何月. 北方地区建筑内环境温度场分布特性及影响因素分析[D]. 吉林:东北电力大学,2022.
[4] 吴纯. ZigBee和WiFi的双向跨协议通信技术研究[D]. 安徽:合肥工业大学,2022.
[5] 余胜贤. 基于蓝牙Mesh和WiFi的智能家居控制系统设计与实现[D]. 杭州电子科技大学,2023.
[6] 刘涛. 分布式测试系统中无线适配终端服务器软件设计[D]. 四川:电子科技大学,2023.
[7] 魏筝. JSON数据模型概念设计及逆向工程方法研究[D]. 江苏:南京航空航天大学,2022.
[8] 蒋志伟. 基于ARM嵌入式智能家居系统的设计与实现[D]. 河北:河北工业大学,2022.
[9] 李凯. 基于I2C通信协议的数模转换器的设计与研究[D]. 四川:电子科技大学,2012.
[10] LEENS F.. An introduction to I2C and SPI protocols[J]. IEEE instrumentation & measurement magazine,2009,12(1):8-13.
[11] 赵欣龙. 开关三极管抗过电损伤能力的提高与实现[D]. 四川:电子科技大学,2017.
[12] 宋国兵,靳幸福,冉孟兵,等. 基于并联电容参数识别的VSC-HVDC输电线路纵联保护[J]. 电力系统自动化,2013,37(15):76-82,102.
[13] 韩佳庚. 基于Godot引擎的设备管理可视化系统研究[J]. 现代信息科技,2023,7(16):130-133.
[14] 苏旺. 基于Home Assistant室内空气监测与摔倒识别的智能家居系统设计[D]. 杭州电子科技大学,2023.
[15] 韩康. MQTT物联网协议与接入技术研究与实现[D]. 山西:太原科技大学,2023.
[16] Kawaguchi R, Bandai M. Edge based MQTT broker architecture for geographical IoT applications[C]//2020 International Conference on Information Networking (ICOIN). IEEE, 2020: 232-235.