基于stm32的智能家居安防系统设计实物分享
摘 要
随着智能家居市场的不断拓展,人们对于安防系统的需求日益增长。如今,家庭安全已成为人们重视的事项之一,因此,智能家居安防系统的研究和推广具有重要的实际意义。本文设计的智能家居安防系统采用STM32F103c8t6作为主控芯片,电路设计有电源模块电路、火焰传感器检测电路、热释电红外传感器电路、MQ-5传感器检测电路、DHT11温湿度传感器电路、继电器控制电路、水泵灭火电路、蜂鸣器报警电路、OLED显示电路、LED警示灯电路。其中系统通过ESP8266+WiFi的无线通讯将传感器采集到的数据发送到云端,用户能够通过网页远程查看室内的情况。
该系统通过多种传感器采集家庭室内的各项数据后通过判断采取相应的处理,如开启水泵灭火,开启空调调节室内温度等,同时通过app发送警告消息给用户。
关键词: 物联网,智能家居,传感器
目 录
基于stm32的智能家居安防系统设计
1 绪论
1.1 选题背景及研究意义
得益于物联网和人工智能等技术的快速发展,智能家居安防系统已成为人们日常生活的重要组成部分。该系统可以实现智能化的家居安全防护,如监测家庭环境温湿度、煤气泄漏、火灾等安全隐患,并及时向用户发送预警信息;同时还可以实现智能家居控制,如远程开关灯、空调、窗帘等,极大地提高了人们的生活品质和安全保障。本文旨在设计一款基于STM32的智能家居安防系统,以提高家居的安全性和智能程度来满足人们对于智能家居安全防护的需求[1]。
1.2 国内外的研究现状
1.2.1 国内的现状
智能家居安防系统作为智能家居的一部分,在国内得到了广泛的关注和研究。目前国内主要在以下几个方面进行研究[2]:
1.硬件设备的研发和改进:智能家居安防系统需要各种传感器和控制设备,如智能门锁、红外传感器、烟雾报警器等[2]。国内的厂商和学者都在研究如何优化这些硬件设备,提高性能和可靠性。
2.算法开发和优化:人脸识别、动作检测等算法在智能家居安防系统中发挥着重要作用。国内的研究者们致力于开发更加精准和高效的算法,并优化现有算法的性能。
3.标准化和可信度问题:智能家居安防系统的标准化和可信度问题也是目前国内研究的热点之一。如何保证智能家居安防系统的标准化和可信度成为了研究者们需要解决的问题。
4.智能家居安防系统的应用场景:国内研究者也在探索智能家居安防系统的应用场景,包括家庭、社区、商业等。如何将智能家居安防系统应用到实际场景中,也是一个需要探索的方向。
总的来说,我国在智能家居安防系统的研究和应用方面取得了一些成果。未来,还需要进一步探索和研究,以实现更加高效、可靠和智能的智能家居安防系统应用。接下来就智能门锁、视频监控、传感器技术、智能报警等方面的技术现状进行简要介绍:
1.智能门锁
智能门锁在中国市场的应用和普及度也越来越高。目前市场上涌现出多家智能门锁厂商,提供了多种开锁方式,如密码、指纹、人脸识别等。同时,智能门锁还支持远程控制和分时段授权,增加了安全性和便捷性。
2.视频监控
智能视频监控在中国市场同样得到了广泛应用。除了远程查看和监控外,利用人工智能技术,智能视频监控还可以进行活动检测、人员计数、异常检测等功能。此外,智能视频监控市场上产品多样化,不仅提供摄像头、摄像机、视频管理平台等设备,也提供云端储存和大数据分析等一站式解决方案。
3.传感器技术
中国在传感器领域的研究与应用也有了较大的进展。智能家居安防系统中的传感器技术,不仅可以采集室内外环境中的温度、湿度、光线等信息,还可以通过云端智能算法进行数据分析和控制,例如智能空气净化器等。
4.智能报警
随着人工智能技术的发展,智能报警技术在中国智能家居安防系统中也有所应用。具有人脸识别、行为检测、语音识别等技术的智能报警系统能够自动化地识别和预测安全风险,并及时发送警报信息或发起自动安全保护措施。
总体来看,中国智能家居安防系统在技术研究和应用方面取得了显著成效,但同时也存在数据隐私和信息安全等问题。未来社会将会加强对于智能家居安防系统的规范和标准,推动智能家居安防系统的发展,确保其在便利性、安全性等方面得到更好的保障。
1.2.2 国外的现状
相较于国内,国外在智能家居方面也有着广泛的研究,下面通过以下方面介绍智能家居安防系统在国外的研究现状。
1.声学信号在智能家居安防系统中的应用
Vlaj(2022)发表一篇论文。该论文旨在探讨声学信号在智能家居安防系统中的应用,具体实现了对用户的性别和年龄进行自动分类的功能。研究使用了支持向量机、决策树和朴素贝叶斯等机器学习方法分析用户的声学信号,并取得了很好的分类效果[3]。该研究表明,声学信号可以很好地用于智能家居的人机交互,为智能家居安防系统的进一步研究和应用提供了新的思路和方法。
2.智能家居安防系统市场状况分析
《Telecomworldwire》在2022年发布的一篇文章指出,尽管智能家居市场的需求不断增长,但是出货量在2022年出现了2.6%的下降[4]。这表明,虽然技术的发展和市场需求的增加都在推动智能家居行业的增长,但是市场竞争激烈,产品质量和价格等因素仍然需要考虑。因此,制定合理的市场方案是进行智能家居安防系统应用推广和发展的关键。
3.社交媒体对用户购买决策的影响
Nilashi[5]等人(2022)在《Technology in Society》期刊上发表了一篇题为《Factors impacting customer purchase intention of smart home security systems:Social data analysis using machine learning techniques》的论文。该研究采用机器学习和社交媒体分析方法,对影响用户购买智能家居安防系统的因素进行了研究。该研究发现,用户的需求、技术成熟度、安全性、价格、品牌知名度等因素均对用户购买决策产生影响。研究的结论为智能家居安防系统的设计和市场推广提供了有价值的参考意见。
4.基于STM32的智能家居安防系统
Su等人(2022)在人工生命和机器人国际会议上发表了一篇题为《An intelligent home security system based on STM32》的论文[6],介绍了一种基于STM32单片机的智能家居安防系统。该系统采用了多种传感器,包括红外传感器、温湿度传感器、烟雾传感器等,以检测家庭内部的安全问题。此外,论文还提出了一种基于检测算法的图片识别技术,实现了对宠物、婴儿等的监护和检测功能,该系统具有实用性和可扩展性,为智能家居安防系统的开发提供了新思路。
5.基于物联网和计算机视觉技术的智能家居安防系统
Nandhini等人(2020)在《International Journal of Innovative Technology and Exploring Engineering》期刊上发表了一篇论文,题为《IoT Based Smart Home Security System with Face Recognition and Weapon Detection Using Computer Vision》,提出了一种基于物联网和计算机视觉技术的智能家居安防系统[7]。该系统通过使用计算机视觉技术,结合物联网通信技术,实现了对家庭内部安全问题的检测和报警功能。该系统具有高精度的人脸识别和武器检测功能,可广泛应用于家庭、商业和公共场所等领域。
综上所述,国外的研究者们在智能家居安防系统上也取得了不错的成果。机器学习、计算机视觉等领域的前沿技术已经成为智能家居安防系统领域的研究热点,这种技术革新有望进一步促进智能家居的普及和应用。然而,面对标准化、隐私保护、等问题,智能家居安防系统仍然需要继续研究与探索。
1.3 论文章节安排
第一章介绍了智能家居的背景及研究意义,并对通过举例分析了国内外智能家居安防系统的发展现状。
第二章分析系统实现的功能,然后设计出系统的总体方案,并对主控芯片和传感器进行选型。
第三章介绍了STM32的最小系统,然后对各种传感器模块的电路进行设计,包括温湿度采集模块、火焰检测模块、煤气检测模块、室内防盗模块、ESP8266无线传输电路,摄像头和OLED显示电路等。
第四章介绍使用的编程软件、系统的主程序流程图以及子程序流程的设计,包括温湿度采集程序设计、OLED显示程序设计、无线通讯程序设计等。
第五章介绍了搭出来的简易实物和仿真,然后对系统进行调试,并对结果进行分析与总结。
2 系统方案设计
2.1 系统功能分析
在进行系统的方案设计之前,需要对系统所需要实现的功能进行分析,综合当前市场常见的智能家居安防系统的功能,同时为了降低系统成本,可以将系统需要实现的功能分为以下几点:
实现实时监控火警、煤气泄漏以及实时监控入室盗窃,在异常时报警并启动水泵、排气风扇,然后通过GSM/WIFI等无线通信方式发送给用户;要求系统对室内温湿度实时检测,并通过控制空调等家具调节室内温湿度。
2.2 总体方案设计
完成系统总体功能分析后,对系统的整体功能实现方案进行设计,系统使用单片机作为主控芯片,通过温湿度传感器获取室内的温湿度,并通过无线传输将数据发送到云端平台,通过显示器显示相关数据;通过火焰传感器检测室内的火警值,并显示在显示屏上;通过红外线传感器检测是否有人入侵,并通过单片机触发蜂鸣器报警,警示灯报警,继电器控制水泵灭火;通过烟雾传感器检测是否煤气泄漏,并通过单片机控制蜂鸣器、警示灯报警,并开启排风扇,据此分析系统的整体设计方案如图2.1所示。

图2.1 系统结构框图
单片机模块:控制整个下位机系统;
DHT11传感器:检测室内的温湿度;
MQ-5传感器:检测煤气泄漏;
HY-A1火焰传感器:检测室内火警值;
人体红外传感器:检测是否有人入侵;
OLED显示屏:循环显示室内温湿度和火警值,同时为功能选择提供显示窗口;
ESP8266+WIFI模块:连接单片机和云端平台,将采集到的数据发送到云平台,再通过手机app查看。
2.3 主控芯片的选型
STM32F103c8是一款集成Cortex-M3内核的微控制器单片机,由意法半导体(STMicroelectronics)公司研发,属于STM32F1系列。STM32F103c8内部集成了CPU、存储器、时钟、高性能ADC、DAC等多种外设,最高主频可达72MHz,容量大小为32KB-64KB Flash和10KB SRAM[9]。在通信方面,它支持多种标准接口,如USART、SPI、I2C和CAN,能够方便地与外部设备进行数据交换和通信;在安全方面, STM32F103c8具有硬件加密加速器、支持安全启动的Bootloader和按位可重写的FLASH等,有助于提高系统的安全性和稳定性。
综上所述,STM32F103c8是一款功能强大的微控制器单片机,性能优异,抗干扰性好,支持多种通信接口和安全特性,适用于各种应用场景和设计需求。
2.4 传感器的选型
2.4.1 温湿度传感器方案的选择
DHT11是一种数字信号输出的温湿度传感器,采用了数字模块采集技术和温湿度感知技术,确保了可靠性和稳定性[10]。传感器在湿度校验室中进行校准,并将校准系数储存在OTP内存中,以实现超快响应、高精度检测。DHT11为3针单排引脚封装,连接方便,适用于各种场合。鉴于以上考虑,本设计采用DHT11作为温湿度传感采集器件。
2.4.2 火焰传感器方案的选择
HY-A1火焰传感器是一款用于检测火焰的传感器,具有高灵敏度、快速响应和低功耗等特点。传感器包括一个光敏元件和一个信号处理电路,能够检测宽波段范围内的火焰辐射信号,并将其转换为模拟信号输出。HY-A1火焰传感器具有单线制串行接口,可以方便地集成到系统中。其小型化设计、低功耗和远传输距离的特点,使其适用于各种应用场合,如火灾报警、工业生产等领域。总之HY-A1火焰传感器是一款灵敏度高、响应快和功耗低的传感器,适用于各种检测火焰的应用场合。
综合考虑,本设计采用HY-A1火焰传感器。
2.4.3 红外线传感器方案的选择
HC-SR501传感器是一种被广泛应用于安防系统、智能家居和自动化控制等领域的传感器。该传感器内部采用了高灵敏度的热释电感应器件,能够对人体的红外辐射进行高效检测,当检测到人体移动时,传感器会输出一个高电平信号,以触发后续的动作或报警[11]。
HC-SR501传感器还具有灵活的设置选项,可以通过调整感应距离、延时时间和触发方式等参数,实现对传感器的功能和响应速度的定制化设置。同时传感器采用三针式封装,安装和使用也非常方便。
综合考虑,本设计采用HC-SR501人体红外传感器。
2.4.4 气体传感器方案的选择
MQ-5传感器是一种气敏传感器,用于检测空气中的天然气、液化石油气(LPG)和可燃气体等。传感器采用半导体敏感元件,能够对空气中的可燃气体进行快速检测,并将检测结果转换为模拟信号输出。
MQ-5传感器的工作电压为5V,功耗仅为0.75W。该传感器还具有高精度的温度补偿功能,可以在不同的环境温度下保持稳定的检测性能。
MQ-5传感器还可以与微控制器等数字电路直接连接,具有方便快捷的集成性。由于其小型化设计、功耗低和灵敏度高的特点,使其适用于各种气体检测应用,如燃气检测、工业生产、安防等领域。
综上考虑,本设计采用MQ-5传感器来检测室内煤气泄漏。
2.5 无线通讯模块的选择
ESP8266是中国乐鑫科技有限公司生产的Wi-Fi芯片,属于ESP系列。该芯片是一种高集成度、低功耗的无线网络芯片,常被应用于物联网设备的连接和控制[12]。ESP8266主芯片采用了Tensilica的L106 32位RISC处理器,内置有SPI通信接口、I2C接口等多种接口。
ESP8266小巧可靠的特点使其在智能家居、智能电子芯片、传感器等各种物联网产品中得以广泛应用。
综合考虑,本设计采用ESP8266+WIFI作为系统的无线通信模块。
2.6 液晶显示方案的选择
OLED显示屏是一种具有自发光的显示技术,可以用于制作高对比度、高亮度和高清晰度的显示屏。它与传统的LCD显示屏相比,具有更广的可视角度、更快的响应速度、更低的能耗和更轻薄的体积。当前市面上的OLED模块均采用IIC或SPI总线方式驱动,能够很方便的与单片机直接相连进行驱动。本品采用OLED显示屏来实现显示。
3 硬件电路的设计
本系统的硬件原理图如图3.1所示,其中包括系统主控电路、DHT11传感器电路、MQ-5传感器电路、人体红外传感器HC-SR501电路、HY-A1火焰传感器电路、ESP8266模块、OLED显示模块、水泵灭火电路、蜂鸣器报警电路、警示灯电路、继电器控制输出模块。

图3.1 系统硬件原理图
3.1 单片机最小系统
本设计采用的STM32F103c8芯片,具有高性能ARM Cortex-M3™ 32位RISC内核,工作频率为72MHz,支持4MHz~16MHz外部晶振,内置256KB flash和48KB SRAM。配备单精度浮点计算单元、CRC校验单元和高速ADC/DAC等功能模块,支持多种外设接口和通信协议,例如USART、SPI、I2C、CAN、USB等。
控制器具有较多的GPIO口,可与多种外部设备连接,例如LED、蜂鸣器、温湿度传感器、气体传感器等。同时,STM32F103C8控制器也具有丰富的定时器和计数器,可应用于PWM信号产生、时钟计数和捕获等应用场合。
STM32F103C8芯片具有较低的功耗和较小的封装体积,适用于多种嵌入式应用场合,例如智能家居、工业自动化、机器人控制、医疗设备等。STM32F103C8芯片原理图如图3.2所示。

图3.2 STM32F103C8芯片原理图
3.1.1 复位电路
单片机主控电路一个重要组成部分就是复位电路,该电路可以在单片机程序运行时实现复位功能,使程序从头开始运行,在项目的调试以及维护系统稳定性方面有重要作用。STM32的复位引脚为NRST,当该引脚出现一个低电平时,单片机进行复位,根据此原理设计的复位电路如图3.3所示。

图3.3 复位电路
3.1.2 时钟电路
STM32F103C8芯片的正常工作需要时钟电路提供时钟源,本系统使用石英晶振作为时钟电路的设计,当外加交变电压的频率与晶体本身的固有频率相同时,就会产生压电谐振效应,产生的振动频率也会急剧增加,从而为芯片提供时钟频率。时钟电路如图3.4所示。

图3.4 时钟电路
3.1.3 电源电路
根据使用手册可知,单片机的供电电压必须维持在3.3V,一般情况下选择降压电路,把5V转换为3.3V供电电压,电源电路如图3.5所示。

图3.5 电源电路
3.2 温湿度采集模块
3.2.1 DHT11传感器的工作原理
DHT11采用专用数字模块采集技术和温湿度传感技术,可以准确地测量周围环境的温度和湿度,内部包含电阻式湿度传感器和NTC热敏电阻温度传感器[10]。当DHT11传感器被供电后,电路会进行初始化,并将总线拉低18ms作为开始信号。传感器在收到开始信号后,会开始发送一个40位的数据包,其中包括16位湿度值、16位温度值和8位校验和。
主控芯片接收到数据后,进行校验和计算,如果校验和正确,则表示数据无误。主控芯片将接收到的数据解码,并将湿度和温度值转换成人们能够理解的形式,例如百分比和摄氏度等。需要注意的是,DHT11传感器的数据输出是数字信号,不需要进行模拟信号的采集和转换,这种设计使得DHT11传感器的测量结果更加准确可靠,同时也方便了传感器与数字系统的集成。
3.2.2 电路设计
DHT11传感器有3个引脚,其中VCC连接3.3V电源,DATA连接PA5引脚,GND接地,具体的DHT11传感器电路设计如图3.6所示。

图3.6 DHT11传感器电路图
DHT11的引脚功能如表3.1所示。
表3.1 DHT11引脚功能表
| 引脚 | 功能 |
|---|---|
| VCC | 电源正极,供电电压为3V~5.5V; |
| DATA | 数字输出信号,连接到单片机的GPIO口; |
| NC | 未使用,不连接; |
| GND | 电源负极,连接到电源的地线。 |
3.3 火焰检测电路
3.3.1 火焰传感器 HY-A1的工作原理
火焰传感器HY-A1是一种具有高灵敏度和高可靠性的光电火焰传感器。传感器内部采用红外光电二极管和电路控制元件,当传感器检测到火焰时,红外光电二极管会受到火焰辐射的红外线,产生电信号并传递到电路控制元件。电路控制元件接收到信号后,会进行信号放大、滤波和比较处理,如果检测到的火焰信号达到了设定阈值,则会输出高电平信号,表示传感器检测到了火焰。
3.3.2 电路设计
HY-A1火焰传感器的电路图如图3.7所示。

图3.7 HY-A1火焰传感器电路图
其中PA1接单片机的PA1端,电路中所使用的LM393是一个电压比较器,它可以将3口的电压与2口的电压作比较。当3口的电压大于2口的电压时,电压比较器的输出端输出高电平;反之,输出低电平。同时火焰探测器电路中的红外接收管被用于接收火焰发出的红外线信号,当传感器检测到的红外波长达到电位器设置的阀值时,LED指示灯就会亮起,DO数字开关量输出高电平。反之,指示灯不会亮。其中AO端口输出的模拟量可以反映出室内火警的水平。
3.4 煤气检测电路设计
3.4.1 MQ-5传感器的工作原理
MQ-5传感器是一种气敏传感器,主要用于检测可燃气体,如甲烷、丙烷、天然气等。MQ-5传感器内部包含一根加热丝和一种敏感元件,通常是一种可燃气体敏感材料。当加热丝加热后,敏感元件会吸附周围空气中的可燃气体分子,并发生化学反应。这个化学反应会改变敏感元件的电阻值,使得其电阻值与周围空气中的可燃气体浓度呈正比关系。MQ-5传感器通过测量敏感元件的电阻值来计算可燃气体的浓度。当加热器加热到一定温度时,MQ-5传感器可以开始检测周围的气体浓度。气敏元件会将检测到的气体浓度转换成电阻值,这个电阻值通过一个运放电路被放大,并转化为模拟电压信号输出。
3.4.2 电路设计
MQ-5传感器的内部电路图如图3.8所示。

图3.8 MQ-5传感器电路图
其中PA2接单片机的PA2端,2-5端加加热电压, 本设计采用stm32单片机的内置ADC通道,当检测气体浓度增加时,电压VR5增加,模拟量增大。
3.5 室内防盗模块
3.5.1 人体红外传感器HC-SR501的工作原理
HC-SR501人体红外传感器是一种基于红外线技术的传感器,用于检测周围是否有人的存在。它通过探测周围的红外辐射信号来检测是否有人存在,当有人进入传感器的探测范围时,人体会发射红外线辐射。HC-SR501传感器内部的红外线接收器会接收到这些辐射,并转化成电信号,然后将其送入传感器的信号处理电路中。信号处理电路会对接收到的电信号进行放大和滤波,并进行信号处理和比较,以确定是否有人经过。如果检测到有人存在,则传感器会输出一个高电平信号,否则输出一个低电平信号。
3.5.2 人体红外传感器电路设计
人体红外传感器HC-SR501的电路图如图3.9所示。

图3.9 人体红外传感器HC-SR501
其中PB6接单片机的PB6端,电路中红外传感器通过将红外辐射信号转换为电信号输入到LM393比较器中,当输入的电信号大于预设的阈值时,OUT 1输出高电平,检测到有人入侵,反之低电平。
3.5.3 摄像头OPENMV设计
本设计采用OPENMV摄像头实现人物抓拍,Open MV设备是高性能的摄像头,拥有400万像素,可以实现人脸抓拍,高速抓拍,且拍照延迟很小,可以在有人进入房间时进行抓拍取证并存到内存卡中。

图3.10 OpenMv Cam
3.5.4语音警报设计
语音警报部分采用了tdk的压点扬声器,安装方便快捷,并且可以贴到任何物体的表面,利用共振原理发出声音。同时,音质清晰,可以清楚地播报报警和提示信息,更好地驱离入侵者

图3.11 TDK的压电扬声器
3.6 ESP8266无线传输电路的设计
3.6.1 ESP8266的工作原理
ESP8266WiFi模块可以通过arduino编程,从而与单片机进行通信。Arduino是一个开源的电子原型平台,主要用于快速构建各种互动物理项目。它包含硬件和软件两部分。硬件部分是一系列基于微控制器的开发板,通过连接各种传感器和执行器来与外部世界进行交互。软件部分则是开发环境,使用Arduino编程语言进行编译和上传控制代码到开发板上。
它的易用性和丰富的软硬件库使得电子创客能够通过简单的编程和电路连接来控制各种设备和传感器,实现自己的创意项目。无论是简单的LED闪烁,还是复杂的机器人控制系统,都可以使用Arduino来实现。
3.6.2 电路设计
ESP8266模块的电路图如图3.11所示。
其中RXD和TXD分别接单片机的PA9和PA10端。VCC和CH_PD接3.3电源正极,GND接地。由于esp8266自带ch340串口下载,所以只需要用数据线连接电脑并打开arduino的串口监视器就可以调试和配置esp8266了
如图3.12所示。

图3.12 ESP8266+WIFI电路图
3.7 OLED显示电路设计
3.7.1 OLED的工作原理
OLED是一种常用的字符型液晶显示器,它的显示区域包含128x64个像素点。其工作原理是每个像素点可以独立发光,通过逐行扫描来显示文字和数字。单片机通过iic总线将数据发送到SSD 1306驱动,SSD 1306控制像素点逐行显示在液晶上。再刷新完一行之后,控制器将指针移动到下一行进行二次刷新,直到全屏都刷新完毕,SSD1306开始准备下一次接收数据刷新
3.7.2 电路设计
OLED显示屏的电路图如图3.13所示。

图3.13 OLED显示屏电路图
SCL(Serial Clock Line)是串行时钟线,用于同步数据传输。在I2C通信中,主设备通过SCL引脚发送时钟信号来控制数据传输的时序。
SDA(Serial Data Line)是串行数据线,用于传输实际的数据。通过SDA引脚,主设备可以发送数据到从设备,或者从从设备读取数据。
在使用OLED显示屏时,需要将SCL和SDA引脚连接到stm32单片机上。通过I2C通信协议向OLED显示屏发送命令和数据,控制显示内容和操作。
3.8 蜂鸣器报警电路设计
报警电路由压电式蜂鸣器和Q49012三极管组成,蜂鸣器通电后可直接发出声响,需要使用三极管控制电路通断,三极管Q49012基极连接主控制器PB0引脚,集电极与蜂鸣器之间存在一颗1K电阻,起限流作用,报警电路如图3.14所示。

图3.14 警报电路原理图
3.9 继电器电路设计
本设计中系统的继电器电路如图3.15所示,采用三极管方式来实现,图中二极管Q1,Q2采用二极管IN4007,用于对继电器的线圈进行续流,因为在继电器线圈由通电到断开的时候,电感电流不能突变,需要一个电流的泄放回路。R1,R2为限流电阻,为三极管提供合适的基极电流。当温度高于阈值时,单片机PC9输出高电平,三极管导通,继电器线圈工作,吸合JK1,M1电机工作产生冷风,反之PA9输出低电平,三极管截止,M1电机不工作;同理,当温度低于设定阈值时,单片机PC10输出高电平,M2电机工作产生热风。

图3.15 继电器电路
3.11 电机驱动L298
L298是一种常用的双路H桥电机驱动器,它通过控制输出引脚的高低电平来控制电机的运动方向和速度。
L298电机驱动器由四个开关管组成的电路,称为H桥。一般情况下,每个电机都需要至少两路控制信号——一个用于控制正向旋转,一个用于控制反向旋转。而由于L298电机驱动模块支持控制两个电机,因此我们需要四个引脚分别控制两个电机。
当L298电机驱动器的输入信号为全高电平时,电机停止运转。当一个输入信号为低电平,另一个输入信号为高电平时,电机将以相应的方向旋转。而当两个输入信号交替高低切换的频率越快,电机则会旋转得越快。
L298的引脚功能如表3.6所示。
L298的电路图如图3.16所示。
表3.6 L298功能引脚
| 引脚 | 功能 |
|---|---|
| SENSING A | 电流传感器A,在该引脚与地之间接小阻值电阻可检测电流 |
| SENSING B | 电流传感器B,在该引脚与地之间接小阻值电阻可检测电流 |
| OUT 1 | A电机输出信号1,与IN1相对应,用于使A电机正转。 |
| OUT 2 | A电机输出信号2,与IN2相对应,用于使A电机反转。 |
| IN1 | A电机的输入信号1,可以控制A电机运转的方向。 |
| IN2 | A电机的输入信号2,也可以控制A电机运转的方向。 |
| VCC | 逻辑控制部分的电源输入端。 |
| GND | 接地,芯片本身的热散片与8脚连接 |
| ENABLE A | 使能A电机信号输入。当ENA为高电平时,A电机可以被控制。当ENA为低电平时,A电机将被禁止。 |
| ENABLE B | 使能B电机信号输入。当ENB为高电平时,B电机可以被控制。当ENB为低电平时,B电机将被禁止。 |
| OUT3 | B电机输出信号1,与IN3相对应,用于使B电机正转。 |
| OUT4 | B电机输出信号2,与IN4相对应,用于使B电机反转。 |
| IN3 | B电机的输入信号1,可以控制B电机运转的方向。 |
| IN4 | B电机的输入信号2,也可以控制B电机运转的方向。 |
| VS | 电机驱动电源输入端,此脚与地连接 |

图3.16 L298驱动电路
L298通过二极管接电源的方式来稳压,其中IN1、IN2为输入端,IN1和IN2通过芯片输入0、1来控制电机1的转动,ENA为电机1的使能端,当输入高电平时电机启动,输入低电平时电机停止。
4 系统软件设计
4.1 编程软件介绍
本设计采用keil uVision5[15]软件进行编程设计,Keil uVision5是一个集成开发环境(IDE),用于对嵌入式系统中的微控制器进行编程。它是一个软件套件,包括源代码编辑器、调试器以及微控制器开发、调试和编程所需的其他工具。Keil uVision5 IDE主要用于对基于ARM架构的微控制器进行编程。
Keil uVision5是一款面向ARM处理器编程的集成开发环境(IDE),以下是其主要特点:
1.易于使用:Keil uVision5提供了用户友好的图形用户界面(GUI),可帮助用户快速建立和组织项目、编写和调试代码。
2.支持多种编程语言:Keil uVision5支持多种编程语言,包括C、C++、汇编语言等,可为不同类型的应用程序提供编程支持。
3.强大的代码编辑和调试功能:Keil uVision5提供了强大的代码编辑和调试功能,包括语法高亮、智能代码提示、集成调试器、覆盖率分析等,为开发者提供全面的开发环境。
4.支持多种目标设备:Keil uVision5支持多种目标设备,包括ARM Cortex-A、Cortex-M和Cortex-R系列处理器,可满足不同设备的开发需求。
4.2 系统主程序流程框图
系统在上电后首先初始化各个模块,然后读取室内温湿度,并通过ESP8266将数据传输到服务器上,同时判断温度并作出相应的处理;检测红外线入侵,判断是否有人入侵并作出相应处理;读取气体传感器,判断煤气是否泄漏;检测火警值,判断是否起火,并进行相应处理,最后在显示屏上显示温湿度,火警值。系统主程序流程图如图4.1所示。

图4.1 主程序流程图
4.3 系统子功能程序设计
系统内置了多个子功能,每个功能块都包含了该功能需要的驱动和数据处理算法,以下为三个主要的功能驱动。
4.3.1 温湿度采集程序设计
DHT11采用单总线协议与单片机通信。在每次通信开始前,单片机需要发送一个复位信号,使DHT11从低功耗模式转换到高速模式。当DHT11接收到复位信号并准备好传输数据后,它会发送一个响应信号,并拉高总线(至少18ms)。在一次完整的通信中,DHT11会传输40位数据,先传输高位,后传输低位。
DHT11的数据格式由五个字节(40位)组成,分别是:8位湿度整数数据、8位湿度小数数据、8位温度整数数据、8位温度小数数据和8位校验和。由于DHT11分辨率只能精确到个位,因此小数部分的数据均为0。在数据传输结束后,DHT11会通过将前四个字节的数据相加然后和数据的校验和作对比,以确保数据传输的准确性。由此可知DHT11温湿度传感器的工作流程图如图4.2所示。

图4.2 DHT11工作流程图
4.3.2 OLED显示程序设计
在进行显示程序设计时,首先需要对OLED的工作时序图进行分析,根据芯片手册可知IIC的工作时序图如图4.3所示。
初始化:IIC的初始化为SDA和SCL均为高。
开始信号:处理器让SCL时钟保持高电平,然后让SDA数据信号由高变低就表示一个开始信号。同时IIC总线上的设备检测到这个开始信号它就知道处理器要发送数据了。
停止信号:处理器让SCL时钟保持高电平,然后让SDA数据信号由低变高就表示一个停止信号。同时IIC总线上的设备检测到这个停止信号它就知道处理器已经结束了数据传输,就可以各忙各个的了,如休眠等。
数据传输:SDA上的数据只能在SCL为低电平期间翻转变化,在SCL为高电平期间必须保持稳定,IIC设备只在SCL为高电平期间采集SDA数据。
响应信号(ACK):单片机发完8bit数据后就不再驱动总线了(SDA引脚变输入),而SDA和SDL硬件设计时都有上拉电阻,所以这时候SDA变成高电平。那么在第8个数据位,如果外接IIC设备能收到信号的话接着在第9个周期把SDA拉低,那么处理器检测到SDA拉低就能知道外接IIC设备数据已经收到。IIC数据从最高位开始传输(小端传输)。
4.3.3 无线通讯程序设计
ESP8266是一款Wi-Fi模块,它内置一个强大的TCP/IP协议栈,可以通过串口或者SPI接口与微控制器进行通信,从而实现网络通信。编程ESP8266需要使用C/C++编程语言,通常使用Arduino IDE或ESP-IDF开发环境进行开发[16]。本设计采用Arduino IDE开发环境进行开发。
首先我们需要从下载最新版的Arduino软件并安装,安装完成后在首选项中将下列信息添加进去:http://arduino.esp8266.com/stable/package_ esp8266com index.json

图4.3 首选项面板
之后进入开发板管理界面搜索ESP8266并下载和安装。

图4.4 开发板管理面板
安装完成后重启Arduino,然后在开发板的下拉菜单中即可看到ESP8266开发板相关选项,然后选择相应的ESP8266。

图4.5 开发板选择面板
这样一来Arduino中的ESP8266开发环境就配置好了。接下来就可以通过Arduino编写程序让单片机采集到的数据通过ESP8266+Wifi的模式发送到blinker软件中,并在软件界面上显示当前室内的温湿度。ESP8266+WIFI的流程图如图4.8所示。

图4.6 ESP8266+WiFi流程图
5 系统调试与结果分析
5.1 PROTUES软件的介绍
Protues是一款广泛应用的电子设计仿真软件,由英国公司开发和发布。它不仅可以进行协同仿真,还能用于设计和仿真各种单片机及外围电路器件。Protues软件具有以下主要特点:
- 强大的原理图绘制功能。
- 融合了单片机仿真和电路仿真。
- 支持主流单片机系统的仿真。
- 提供软件调试功能。
5.2 实物结果
由于仿真效果不好,本作品采用了简易实物搭建的方法,仿真如图5.1所示。

图5.1 系统仿真电路图
其中显示屏显示室内温度、湿度。
(1)煤气检测报警
实际使用过程中使用一个按钮来代替煤气检测系统(实际测试过程中无法真正放出煤气来激发传感器),当按下煤气感应的按钮时,煤气风扇和煤气警报的灯亮起,蜂鸣器发出报警声。
如图5.2所示。

图5.2 煤气报警结果
(2)火警检测
首先通过菜单开启火警检测功能,通过按键选择启动火警报警功能,如图5.3所示。
当调节滑动变阻器时,电压超过1.2v时,蜂鸣器BUZ1报警,火警指示灯LEDY亮起并且开启水泵灭火。如图5.4所示。

图5.3 火警启动

图5.4 火警检测
(3)防盗检测
通过菜单功能将防盗功能启动,当检测到有人进入房间时,指示灯亮起,蜂鸣器发出声音,如图5.5所示。摄像头抓拍入侵者图像。如图5.6所示。
Tdk的超薄压电扬声器可以安装在很多的场景下,利用共振的原理可以发出很大的声音,对入侵者进行警告和驱离,如图5.7所示

图5.5防盗提示

图5.6抓拍提示

图5.7语音播报提示,警报
(4)手动通风控制
可以通过菜单选择手动通风功能来实现抽风和换气,并且有三档可以调节。如图5.6所示。

图5.8 抽风换气
- 室内湿度控制(窗户控制)
可以通过菜单选择最高温度阈值和最低温度阈值,如图5.7所示。

图5.9 温度调节菜单
当室内温度为32(大于阈值30)时,控制冷风风扇旋转,排出热空气如图5.7所示。

图5.10 冷风风扇
当室内温度小于20度时(由于夏天原因且没有空调无法进行低温测试),热风风扇会启动,实现恒温效果。
室内的温度和湿度也会随时同步到服务器上,通过外网穿透等方式发到公网上,用户可以通过访问物联网来实时查看温湿度,如图5.8所示

图5.11 物联网显示
结 论
本设计为基于单片机智能家居安防系统设计,该系统是基于stm32和各种传感器来完成总体整体设计的,该系统具有火焰检测、煤气检测、室内温湿度检测、室内防盗的功能,同时具备将传感器采集到的数据发送到自己搭建的服务器,并通过网络向用户展示室内情况的功能。
该系统通过火焰传感器检测室内是否有火焰产生来判断是否发送火灾,同时具备发生火灾时的水泵灭火功能。煤气检测是通过气体传感器检测室内气体浓度是否超标,
同时具备排风扇等安全防护功能。室内温湿度检测是通过DHT11传感器检测室内的温湿度,并根据室内的温湿度启动相应的措施来进行调节,保证室内保持一个适宜的环境。而室内防盗是通过红外线传感器加摄像头来实现的,通过红外线加云台的模式,保证能够准确的判断是否有人入侵,然后在进行报警处理。最后的ESP8266+wifi的模式是通过ESP8266将主控系统收集到的各个传感器的数据发送到云端,然后再通过云端将信息实时传送给用户。
附 录
主程序:
/* USER CODE BEGIN Header */
/**
*******************************************************************************
* @file : main.c
* @brief : 主程序入口
*******************************************************************************
* @attention
*******************************************************************************
*/
/* USER CODE END Header */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "i2c.h"
#include "rtc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "dht11.h"
#include <stdio.h>
#include <oled.h>
/**
* @brief 重定向c库函数printf到DEBUG_USARTx
* @param ch 字符
* @param f 文件指针
* @retval 返回写入的字符
* @note 用于串口调试输出
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* @brief 重定向c库函数getchar,scanf到DEBUG_USARTx
* @param f 文件指针
* @retval 返回读取的字符
* @note 用于串口调试输入
*/
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#include <string.h>
#define RXBUFFERSIZE 256 // 串口接收缓冲区大小
char RxBuffer[RXBUFFERSIZE]; // 串口接收缓冲区
uint8_t aRxBuffer; // 串口接收中断接收变量
uint8_t Uart1_Rx_Cnt = 0; // 串口接收计数
unsigned int temp, humi; // 温度、湿度变量
double adcDATA; // ADC采集数据
unsigned int menu = 0, k = 0, l = 0, m = 1, n = 0, pwmnum = 200, tempseth = 45, tempsetl = 22;
// menu:菜单选择变量,k:防盗检测使能,l:火警检测使能,m:高低温调节选择,n:风扇模式选择,pwmnum:风扇PWM占空比,tempseth:高温设定值,tempsetl:低温设定值
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief 应用程序入口点
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
uint16_t AD_Value; // ADC转换值变量
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* 复位所有外设,初始化Flash接口和Systick定时器 */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* 配置系统时钟 */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* 初始化所有配置的外设 */
MX_GPIO_Init(); // GPIO初始化
MX_RTC_Init(); // RTC初始化
MX_USART1_UART_Init(); // USART1初始化
MX_TIM2_Init(); // TIM2初始化
MX_TIM1_Init(); // TIM1初始化
MX_I2C1_Init(); // I2C1初始化
MX_ADC1_Init(); // ADC1初始化
/* USER CODE BEGIN 2 */
OLED_Init(); // OLED初始化
OLED_Clear(); // 清屏
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1); // 开启串口接收中断
/* USER CODE END 2 */
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // 启动TIM1的PWM输出
/* 无限循环 */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
DH11_Task(); // 执行DHT11温湿度传感器任务
/* ADC采集数据 */
HAL_ADC_Start(&hadc1); // 启动ADC
HAL_ADC_PollForConversion(&hadc1, 50); // 等待ADC转换完成,超时50ms
if (HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
{
AD_Value = HAL_ADC_GetValue(&hadc1); // 获取ADC转换值(12位)
adcDATA = (AD_Value * 3300.0 / 4096); // 转换为电压值(mV)
}
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pwmnum); // 设置PWM占空比
/* 读取温湿度数据 */
temp = DH11_data.temp; // 获取温度
humi = DH11_data.humidity; // 获取湿度
// 测试防止温度为0
if (temp < 1) temp = 1;
/* 自动控制部分 */
// 防盗检测
if ((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10) == 1) && (k == 1)) // 人体检测触发且使能
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET); // 关闭灯
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // 打开蜂鸣器
}
else {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET); // 打开灯
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // 关闭蜂鸣器
}
// 煤气检测
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11) == 1) // 煤气检测触发
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); // 关闭灯
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // 打开蜂鸣器
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // 关闭风扇
}
else {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); // 打开灯
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // 关闭蜂鸣器
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // 打开风扇
}
// 火警检测(3.3V电压高于1.2V)
if (adcDATA > 1200 && l == 1) // 火警检测触发且使能
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET); // 打开灯
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); // 打开蜂鸣器
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET); // 打开水泵
}
else {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET); // 关闭灯
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // 关闭蜂鸣器
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_SET); // 关闭水泵
}
// 温度控制风扇(高温开冷风,低温开热风)
if (temp > tempseth) // 高于高温设定
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET); // 打开冷风
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET); // 关闭热风
}
else if ((temp <= tempseth) && (temp >= tempsetl)) // 在设定范围内
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET); // 关闭冷风
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET); // 关闭热风
}
else if (temp < tempsetl) // 低于低温设定
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET); // 关闭冷风
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET); // 打开热风
}
/* 按键菜单部分 */
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 1) // 菜单选择按键
{
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 1); // 等待按键释放
menu++; // 菜单索引递增
OLED_Clear(); // 清屏
}
if (menu == 0) // 主页
{
OLED_ShowCHinese(0, 0, 10); // 显示温度
OLED_ShowCHinese(0, 16, 11); // 显示度
OLED_ShowNum(33, 1, temp / 10, 1, 2); // 显示温度十位
OLED_ShowNum(41, 1, temp % 10, 1, 2); // 显示温度个位
OLED_ShowCHinese(0, 48, 20); // 显示湿度
OLED_ShowCHinese(0, 66, 11); // 显示度
OLED_ShowNum(82, 1, humi / 10, 1, 2); // 显示湿度十位
OLED_ShowNum(90, 1, humi % 10, 1, 2); // 显示湿度个位
// 显示其他中文字符
OLED_ShowCHinese(2, 0, 21);
OLED_ShowCHinese(2, 16, 22);
OLED_ShowCHinese(2, 32, 23);
OLED_ShowCHinese(2, 48, 24);
OLED_ShowCHinese(2, 64, 25);
OLED_ShowCHinese(2, 80, 26);
OLED_ShowCHinese(4, 0, 27);
OLED_ShowCHinese(4, 16, 28);
OLED_ShowCHinese(4, 32, 29);
OLED_ShowCHinese(4, 48, 30);
OLED_ShowCHinese(6, 0, 31);
OLED_ShowCHinese(6, 16, 31);
OLED_ShowCHinese(6, 32, 32);
OLED_ShowCHinese(6, 48, 33);
OLED_ShowCHinese(6, 64, 34);
OLED_ShowCHinese(6, 80, 35);
OLED_ShowCHinese(6, 96, 36);
}
else if (menu == 1) // 防盗检测
{
OLED_ShowCHinese(0, 0, 52); // 防盗
OLED_ShowCHinese(0, 16, 53); // 检
OLED_ShowCHinese(0, 32, 12); // 测
OLED_ShowCHinese(0, 48, 13); // 控
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15) == 1) // 使能按键
{
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15) == 1);
k++; // 使能变量递增
}
if (k == 1) // 检测使能
{
OLED_ShowCHinese(2, 0, 37); // 使
OLED_ShowCHinese(2, 16, 38); // 能
}
else if (k == 0) // 检测关闭
{
OLED_ShowCHinese(2, 0, 39); // 关
OLED_ShowCHinese(2, 16, 40); // 闭
}
else if (k > 1) // 归零
k = 0;
}
else if (menu == 2) // 火警检测
{
OLED_ShowCHinese(0, 0, 8); // 火
OLED_ShowCHinese(0, 16, 9); // 警
OLED_ShowCHinese(0, 32, 12); // 测
OLED_ShowCHinese(0, 48, 13); // 控
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15) == 1) // 使能按键
{
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15) == 1);
l++; // 使能变量递增
}
if (l == 1) // 火警使能
{
OLED_ShowCHinese(2, 0, 37); // 使
OLED_ShowCHinese(2, 16, 38); // 能
}
else if (l == 0) // 火警关闭
{
OLED_ShowCHinese(2, 0, 39); // 关
OLED_ShowCHinese(2, 16, 40); // 闭
}
else if (l > 1) // 选择归零
l = 0;
}
else if (menu == 3) // 温度风扇调节
{
OLED_ShowCHinese(0, 0, 10); // 温
OLED_ShowCHinese(0, 16, 20); // 湿
OLED_ShowCHinese(0, 32, 11); // 度
OLED_ShowCHinese(0, 48, 12); // 控
OLED_ShowCHinese(0, 64, 13); // 制
OLED_ShowNum(0, 3, tempseth / 10, 1, 2); // 高温十位
OLED_ShowNum(0, 5, tempsetl / 10, 1, 2); // 低温十位
OLED_ShowNum(8, 3, tempseth % 10, 1, 2); // 高温个位
OLED_ShowNum(8, 5, tempsetl % 10, 1, 2); // 低温个位
OLED_ShowCHinese(2, 16, 41); // 高
OLED_ShowCHinese(2, 32, 10); // 温
OLED_ShowCHinese(4, 16, 42); // 低
OLED_ShowCHinese(4, 32, 10); // 温
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15) == 1) // 高低温设置切换
{
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15) == 1);
m++; // 选择变量递增
}
if (m == 1) // 高温调节
{
OLED_ShowCHinese(2, 48, 12); // 控
OLED_ShowCHinese(4, 48, 43); // 制
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13) == 1) // 增加
{
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13) == 1);
tempseth++; // 高温增加
}
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_14) == 1) // 减少
{
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_14) == 1);
tempseth--; // 高温减少
}
if (tempseth == 99 || tempseth == 0) // 防越位
tempseth = 0;
if (tempseth < tempsetl) tempseth = tempsetl; // 确保高温高于低温
}
else if (m == 0) // 低温调节
{
OLED_ShowCHinese(4, 48, 12); // 控
OLED_ShowCHinese(2, 48, 43); // 制
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13) == 1) // 增加
{
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13) == 1);
tempsetl++; // 低温增加
}
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_14) == 1) // 减少
{
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_14) == 1);
tempsetl--; // 低温减少
}
if (tempsetl == 99 || tempsetl == 0) // 防越位
tempsetl = 0;
if (tempsetl > tempseth) tempsetl = tempseth; // 确保低温低于高温
}
else if (m > 1) // 选择归零
m = 0;
}
else if (menu == 4) // 手动排风
{
OLED_ShowCHinese(0, 0, 14); // 手
OLED_ShowCHinese(0, 16, 15); // 动
OLED_ShowCHinese(0, 32, 16); // 排
OLED_ShowCHinese(0, 48, 17); // 风
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15) == 1) // 功能选择
{
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15) == 1);
pwmnum = 200; // 重置PWM
n++; // 模式递增
}
if (n == 0) // 全速关闭
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET); // 电机控制引脚
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
OLED_ShowCHinese(2, 0, 16); // 排
OLED_ShowCHinese(2, 16, 17); // 风
OLED_ShowCHinese(2, 32, 39); // 关
OLED_ShowCHinese(4, 0, 43); // 闭
OLED_ShowCHinese(4, 16, 43); // 闭
OLED_ShowCHinese(4, 32, 43); // 闭
OLED_ShowCHinese(4, 48, 43); // 闭
}
else if (n == 1) // 正转
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET); // 正转
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
OLED_ShowCHinese(2, 0, 16); // 排
OLED_ShowCHinese(2, 16, 17); // 风
OLED_ShowCHinese(2, 32, 44); // 正
OLED_ShowCHinese(4, 0, 46); // 转
OLED_ShowCHinese(4, 16, 47); // 速
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13) == 1) // 调速增加
{
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13) == 1);
pwmnum += 300; // PWM增加
}
if (pwmnum == 200) // 低速
{
OLED_ShowCHinese(4, 32, 48); // 低
OLED_ShowCHinese(4, 48, 51); // 速
}
else if (pwmnum == 500) // 中速
{
OLED_ShowCHinese(4, 32, 49); // 中
OLED_ShowCHinese(4, 48, 51); // 速
}
else if (pwmnum == 800) // 高速
{
OLED_ShowCHinese(4, 32, 50); // 高
OLED_ShowCHinese(4, 48, 51); // 速
}
else if (pwmnum > 800) pwmnum = 200; // 高速归零为低速
}
else if (n == 2) // 反转
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET); // 反转
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
OLED_ShowCHinese(2, 0, 16); // 排
OLED_ShowCHinese(2, 16, 17); // 风
OLED_ShowCHinese(2, 32, 45); // 反
OLED_ShowCHinese(4, 0, 46); // 转
OLED_ShowCHinese(4, 16, 47); // 速
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13) == 1) // 调速增加
{
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13) == 1);
pwmnum += 300; // PWM增加
}
if (pwmnum == 200) // 低速
{
OLED_ShowCHinese(4, 32, 48); // 低
OLED_ShowCHinese(4, 48, 51); // 速
}
else if (pwmnum == 500) // 中速
{
OLED_ShowCHinese(4, 32, 49); // 中
OLED_ShowCHinese(4, 48, 51); // 速
}
else if (pwmnum == 800) // 高速
{
OLED_ShowCHinese(4, 32, 50); // 高
OLED_ShowCHinese(4, 48, 51); // 速
}
else if (pwmnum > 800) pwmnum = 200; // 高速归零为低速
}
else if (n > 2) n = 0; // 防越位
}
else if (menu > 4) menu = 0; // 菜单归零
/* 按键菜单部分结束 */
printf("%d\r\n", temp * 10000 + humi); // 后续串口调试都在这里写
// 编码:温度*10000+湿度。解码:数值/10000==温度,数值%100=湿度。转换
HAL_Delay(100); // 延时100ms
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief 系统时钟配置
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** 根据RCC_OscInitTypeDef结构中的指定参数初始化RCC振荡器 */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** 初始化CPU、AHB和APB总线时钟 */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC | RCC_PERIPHCLK_ADC;
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/**
* @brief UART接收完成回调函数
* @param huart UART句柄
* @note 用于处理串口接收数据
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
UNUSED(huart); // 防止未使用参数编译警告
/* 注意:当需要回调时,可以在用户文件中实现HAL_UART_TxCpltCallback */
if (Uart1_Rx_Cnt >= 255) // 接收数据溢出,清空缓冲区
{
Uart1_Rx_Cnt = 0;
memset(RxBuffer, 0x00, sizeof(RxBuffer));
HAL_UART_Transmit(&huart1, (uint8_t *)"数据溢出", Uart1_Rx_Cnt, 0xFFFF);
}
else
{
RxBuffer[Uart1_Rx_Cnt++] = aRxBuffer; // 保存接收到的数据
if ((RxBuffer[Uart1_Rx_Cnt - 1] == 0x0A) && (RxBuffer[Uart1_Rx_Cnt - 2] == 0x0D)) // 收到回车换行
{
HAL_UART_Transmit(&huart1, (uint8_t *)&RxBuffer, Uart1_Rx_Cnt, 0xFFFF); // 回显接收到的数据
while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX) // 等待UART发送完成
Uart1_Rx_Cnt = 0;
memset(RxBuffer, 0x00, sizeof(RxBuffer)); // 清空缓冲区
}
}
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1); // 重新开启接收中断
}
/* USER CODE END 4 */
/**
* @brief 发生错误时执行的函数
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* 用户可在此添加错误处理代码 */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief 报告assert_param错误发生的文件名和行号
* @param file: 源文件名指针
* @param line: 错误发生的行号
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* 用户可在此添加错误报告代码,例如:
printf("Wrong parameters value: file %s on line %d\r\n", file, line); */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
1万+

被折叠的 条评论
为什么被折叠?



