基于物联网设计的地下煤矿安全监测与预警

发布于:2024-11-04 ⋅ 阅读:(147) ⋅ 点赞:(0)

文章目录

一、前言

1.1 项目介绍

本项目设计里用到的全部工具软件、模块的源代码都可以在这里下载(放在网盘里了)。

https://pan.quark.cn/s/145a9b3f7f53

【1】项目开发背景

随着全球对能源需求的持续增长,煤炭作为重要的传统能源之一,在许多国家和地区依然扮演着不可或缺的角色。然而,煤矿开采作业由于其特殊的地下环境,常常伴随着较高的安全风险,包括瓦斯爆炸、火灾、透水事故等。这些事故不仅会导致严重的人员伤亡和经济损失,还可能引发长期的环境问题。因此,提高煤矿的安全管理水平,减少事故发生率,成为行业发展中亟待解决的问题。

近年来,物联网(IoT)技术的发展为矿井安全管理提供了新的解决方案。通过部署各种传感器和智能设备,可以实现对矿井内环境参数的实时监测,及时发现潜在的风险因素,并采取有效的预防措施。基于此背景,本项目提出了一种基于物联网设计的地下煤矿安全监测与预警系统。该系统利用先进的传感技术和无线通信技术,构建一个智能化的安全监控网络,以增强矿井作业的安全性,提升应急响应速度,降低事故发生概率。

项目将重点放在以下几个方面:

通过温湿度传感器和气体传感器对矿井内的温度、湿度以及瓦斯浓度进行连续监测;

引入人体检测传感器来监控人员活动情况,确保在紧急情况下能够迅速定位并救援被困人员;

采用OLED显示屏在现场展示关键数据,同时通过NBIoT模块将数据上传至云端,实现远程监控;

开发一套基于Qt的可视化大屏软件界面,方便管理人员随时查看矿井状况,并作出快速决策。

通过上述措施,本项目致力于打造一个高效、可靠且易于操作的安全监测体系,为矿工提供更加安全的工作环境,同时也为企业带来更高的运营效率和经济效益。

img

image-20241010113431709

image-20241010113520568

【2】设计实现的功能

(1)环境温湿度监测

  • 使用DHT11温湿度传感器实时检测矿井内的温度和相对湿度。当检测到的数值超过预设的安全阈值时,系统会触发蜂鸣器报警,提醒工作人员采取相应措施。

(2)瓦斯浓度检测与自动通风控制

  • 通过MQ5气体传感器监测矿井内瓦斯(甲烷)的浓度。一旦瓦斯浓度达到危险水平,控制系统将激活继电器开关模块,自动启动通风风扇以降低有害气体浓度,并可能伴有声音警报。

(3)人员存在检测

  • 利用红外热释电人体感应模块检测矿井内是否有人。如果检测到人员存在,系统将点亮指示灯,以此作为视觉提示,增强对现场人员活动的监控。

(4)数据实时显示

  • 采用OLED显示屏来展示当前采集到的各项环境参数,包括但不限于温湿度、瓦斯浓度等,以便于现场工作人员及时了解矿井内的实际情况。

(5)远程数据上传

  • 通过BC26 NBIOT模块将收集到的所有环境信息上传至华为云物联网平台,允许远程监控和数据分析,提高管理效率和响应速度。

(6)可视化大屏界面

  • 开发了基于Qt框架的可视化大屏软件界面,运行在Windows电脑端。该界面可以接收并展示从设备上传的数据,为管理人员提供一个直观且易于操作的平台来进行数据查看和分析。

【3】项目硬件模块组成

(1)主控芯片 - STM32F103RCT6

  • 作为系统的核心处理器,负责处理来自各个传感器的数据、执行控制逻辑以及管理通信协议。

(2)温湿度传感器 - DHT11

  • 用于实时监测矿井内的温度和相对湿度,并将数据传输给主控芯片。当环境参数超过设定的安全阈值时,触发报警机制。

(3)瓦斯浓度检测模块 - MQ5气体传感器

  • 专门用于检测环境中甲烷等可燃气体的浓度。一旦检测到的瓦斯浓度达到危险水平,会通过控制系统激活通风设备以降低浓度,并触发警报。

(4)人体检测传感器 - 红外热释电模块

  • 通过感应人体发出的红外辐射来判断区域内是否有人存在,增强现场的安全监控能力。

(5)显示模块 - SPI接口OLED显示屏

  • 提供一个直观的用户界面,用来显示当前采集到的温湿度、瓦斯浓度等关键信息。

(6)无线通信模块 - BC26 NBIOT模块

  • 负责将收集到的各种环境数据通过NBIoT网络上传至华为云物联网平台,实现远程监控和数据分析。

(7)蜂鸣器报警

  • 在任何环境参数超出预设的安全范围时,蜂鸣器将被激活,发出声音警报以提醒工作人员采取紧急措施。

(8)继电器开关模块 - 电磁继电器

  • 根据主控芯片发送的指令控制外部设备如通风风扇的工作状态,确保在必要时能够迅速响应。

(9)风扇模块 - 矿用通风风扇

  • 当瓦斯浓度过高时,通过继电器控制自动启动,以快速降低矿井内有害气体的浓度,保障人员安全。

(10)电源管理

  • 包括为控制电路供电的5V 2A稳压电源及为风扇等高功耗设备提供的市电供应,保证整个系统稳定可靠地运行。

(11)指示灯 - LED指示灯

  • 用于视觉上提示系统状态或特定事件的发生,比如当检测到人员存在时点亮指示灯。

1.2 设计思路

本项目的设计思路基于对煤矿安全现状的深入分析,在利用物联网技术构建一个全面、智能且高效的地下煤矿安全监测与预警系统。首先,我们认识到矿井作业环境中存在的多种潜在风险因素,如瓦斯积聚、温湿度异常以及突发事故等,这些都可能直接威胁到矿工的生命安全。因此,设计之初就明确了系统需要具备实时监测环境参数的能力,并能够快速响应以降低风险。

为了实现这一目标,系统集成了多种传感器来收集关键数据。DHT11温湿度传感器用于监测矿井内的温度和湿度变化,这是评估工作环境舒适度及防止因极端条件引发事故的重要指标。MQ5气体传感器则专注于检测瓦斯浓度,因为瓦斯是导致煤矿爆炸的主要原因之一。当这些传感器检测到的数据超过预设的安全阈值时,系统会立即启动报警机制,通过蜂鸣器发出声音警报,同时自动开启通风风扇以稀释有害气体,从而迅速减轻潜在危险。

考虑到矿井内人员的安全管理同样重要,系统还加入了红外热释电人体感应模块,用以监测是否有人员在场。这不仅有助于提高现场的安全意识,还能在紧急情况下帮助救援队伍更快地定位被困人员。此外,OLED显示屏被用来在现场直观展示各种监测数据,确保所有工作人员都能及时了解当前的环境状况。

为了让管理者能够远程监控矿井状态并进行数据分析,系统采用了BC26 NBIoT模块将采集的数据上传至华为云物联网平台。这种做法极大地增强了系统的灵活性和可扩展性,使得即使不在现场也能随时掌握最新情况。最后,为了提供更友好的用户体验,我们使用Qt框架开发了一款可视化大屏软件界面,该界面运行于Windows电脑端,可以清晰地呈现从设备上传来的所有信息,便于管理人员做出及时有效的决策。

本项目通过集成先进的传感技术、无线通信技术和云计算平台,打造了一个多层次的安全监测体系。该体系不仅提升了煤矿作业的安全水平,也为实现智能化矿山管理奠定了坚实的基础。

1.3 系统功能总结

序号 功能模块 描述 实现方式/硬件组件
1 温湿度监测 检测矿井内温湿度情况,并在超过预设阈值时触发报警。 DHT11温湿度传感器,蜂鸣器
2 瓦斯浓度检测 监控环境中的瓦斯浓度,当浓度达到危险水平时自动开启通风设备。 MQ5气体传感器,继电器控制的矿用通风风扇
3 人员存在监测 检测矿井内是否有人员活动,提高安全响应速度。 红外热释电人体感应模块,指示灯
4 数据显示 显示实时采集到的各项环境参数。 OLED显示屏(SPI协议)
5 数据上传 将收集的数据通过无线网络上传至云端平台,支持远程监控和数据分析。 BC26 NBIOT模块,华为云物联网平台
6 可视化界面 在Windows电脑端提供一个用户友好的可视化大屏界面,用于展示和管理数据。 Qt开发的图形用户界面软件
7 电源管理 为系统提供稳定的电力供应,确保所有电子元件正常工作。 5V 2A稳压电源供控制电路使用;市电供电给高功耗设备如风扇等

1.4 开发工具的选择

【1】设备端开发

STM32的编程语言选择C语言,C语言执行效率高,大学里主学的C语言,C语言编译出来的可执行文件最接近于机器码,汇编语言执行效率最高,但是汇编的移植性比较差,目前在一些操作系统内核里还有一些低配的单片机使用的较多,平常的单片机编程还是以C语言为主。C语言的执行效率仅次于汇编,语法理解简单、代码通用性强,也支持跨平台,在嵌入式底层、单片机编程里用的非常多,当前的设计就是采用C语言开发。

开发工具选择Keil,keil是一家世界领先的嵌入式微控制器软件开发商,在2015年,keil被ARM公司收购。因为当前芯片选择的是STM32F103系列,STMF103是属于ARM公司的芯片构架、Cortex-M3内核系列的芯片,所以使用Kile来开发STM32是有先天优势的,而keil在各大高校使用的也非常多,很多教科书里都是以keil来教学,开发51单片机、STM32单片机等等。目前作为MCU芯片开发的软件也不只是keil一家独大,IAR在MCU微处理器开发领域里也使用的非常多,IAR扩展性更强,也支持STM32开发,也支持其他芯片,比如:CC2530,51单片机的开发。从软件的使用上来讲,IAR比keil更加简洁,功能相对少一些。如果之前使用过keil,而且使用频率较多,已经习惯再使用IAR是有点不适应界面的。

【2】上位机开发

上位机的开发选择Qt框架,编程语言采用C++;Qt是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象编译器(Meta Object Compiler, moc))以及一些宏,Qt很容易扩展,并且允许真正地组件编程。Qt能轻松创建具有原生C++性能的连接设备、用户界面(UI)和应用程序。它功能强大且结构紧凑,拥有直观的工具和库。

1.5 模块的技术详情介绍

【1】NBIOT-BC26模块

NBIoT-BC26模块是由Quectel(移远通信)生产的一款低功耗广域网络(LPWAN)模块,专为窄带物联网(Narrowband Internet of Things, NB-IoT)应用设计。这款模块具有体积小、功耗低、覆盖范围广等优点,非常适合用于远程监控、智能计量、资产跟踪、环境监测等多种物联网应用场景。

BC26模块支持NB-IoT标准,这是3GPP定义的一种专门针对物联网应用的蜂窝技术。与传统的2G/3G/4G网络相比,NB-IoT提供了更好的室内覆盖能力、更低的功耗以及更高的连接密度。这使得BC26模块能够在信号较弱或难以到达的地方保持稳定的数据传输。此外,NB-IoT还支持更深的穿透力和更长的电池寿命,这对于部署在偏远地区或需要长时间运行的设备尤为重要。

该模块采用LGA封装,尺寸仅为19.9 x 23.6 x 2.2 mm,便于集成到各种小型化设备中。BC26模块支持多种频段,包括B1/B3/B5/B8/B20/B28等全球主流频段,确保了广泛的地域兼容性。模块内置了多种协议栈,如CoAP、TCP/UDP、MQTT等,简化了数据传输和远程控制的应用开发。通过这些协议栈,开发者可以轻松实现设备与云端服务器之间的通信,进行数据上报和命令下发。

在接口方面,BC26模块提供了丰富的外设接口,包括UART、GPIO、ADC、SIM卡接口等。这些接口使得模块能够方便地与其他传感器、控制器和其他外围设备进行连接。例如,通过UART接口,模块可以直接与微控制器进行通信;通过GPIO接口,可以控制外部设备或读取开关状态;而SIM卡接口则允许使用标准SIM卡或eSIM卡进行网络认证。

为了进一步降低功耗,BC26模块支持多种省电模式,如PSM(Power Saving Mode)和eDRX(Extended Discontinuous Reception)。这些模式可以在不需要持续数据传输时显著降低功耗,延长电池寿命。在PSM模式下,模块可以进入深度睡眠状态,仅在预定的时间间隔内唤醒以检查是否有新的数据传输需求。而在eDRX模式下,模块会定期监听网络消息,但相比于传统DRX模式,其监听间隔更长,从而降低了功耗。

BC26模块还具备强大的安全特性,支持多种加密算法和协议,如TLS/SSL、AES等,确保数据传输的安全性和完整性。此外,模块支持FOTA(Firmware Over-The-Air)更新功能,可以通过无线方式对固件进行升级,提高了系统的可维护性和安全性。

NBIoT-BC26模块以其小巧的体积、低功耗、广泛的网络覆盖以及丰富的接口支持,成为物联网应用中的理想选择。无论是用于智能农业、环境监测、智能城市还是其他需要长期可靠连接的应用场景,BC26都能提供稳定高效的数据传输解决方案。

【2】MQ5传感器

MQ5气体传感器是一种广泛应用于检测多种可燃气体的半导体气体传感器,特别适合于监测甲烷(CH4)、液化石油气(LPG)、丙烷、氢气等。这种传感器因其高灵敏度、快速响应时间和相对低廉的成本而在工业安全监控领域得到了广泛应用,尤其是在需要对易燃易爆气体进行实时监测的环境中。

MQ5的工作原理基于金属氧化物半导体(MOS)技术。当传感器暴露在目标气体中时,其表面会发生化学反应,导致传感器电阻发生变化。这一变化可以通过电路转换为电信号,进而被用来评估气体浓度。通常情况下,MQ5传感器会连接到一个简单的分压电路,并通过测量输出电压来判断气体的存在及其浓度。传感器对不同气体有不同的敏感度,因此在实际应用中需要根据所要检测的具体气体类型进行校准。

该传感器的操作温度范围较宽,一般在-10°C至50°C之间,这使得它能够在大多数矿井环境下正常工作。然而,为了获得最佳性能,建议在使用前进行预热,以确保传感器达到稳定的工作状态。预热时间通常约为20分钟,之后传感器才能提供准确可靠的读数。

MQ5传感器具有良好的稳定性和较长的使用寿命,但需要注意的是,其性能可能会受到环境湿度和温度的影响。因此,在设计系统时,应考虑这些因素并采取适当的补偿措施。此外,由于MQ5传感器主要针对可燃气体设计,对于非可燃性气体如一氧化碳或二氧化碳则不适用,所以在选择传感器时需要明确具体的应用需求。

在本项目中,MQ5气体传感器将被用来监测矿井内的瓦斯(主要是甲烷)浓度。一旦检测到的瓦斯浓度超过设定的安全阈值,系统就会自动启动通风设备,降低矿井内有害气体的浓度,同时触发报警机制,提醒工作人员采取必要的安全措施。这样的设计不仅提高了矿井作业的安全性,也增强了事故预防的能力。

【4】DHT11传感器

DHT11是一种广泛使用的数字温湿度传感器,它能够同时测量环境的温度和相对湿度。这种传感器因其简单易用、成本低廉以及良好的性能而被广泛应用于各种场合,包括家庭自动化、气象站、农业监测以及工业控制等领域。在本项目中,DHT11将用于实时监测地下煤矿内的温湿度条件,确保矿井内保持适宜的工作环境。

DHT11传感器内部集成了一个电阻式湿敏元件和一个NTC(负温度系数)热敏电阻,这两个组件共同作用以实现对环境温湿度的精确测量。湿敏元件通过检测空气中的水分含量来反映湿度水平,而热敏电阻则根据其电阻值随温度变化的特性来测量温度。这两种物理量的变化会被转换成电信号,并通过内置的微处理器进行处理,最终输出数字信号。

DHT11采用单线数字接口进行通信,这意味着只需一根数据线即可完成与微控制器之间的数据传输。这简化了电路设计,减少了布线复杂度。为了获取准确的数据,用户需要遵循特定的时序协议来读取传感器的输出。通常情况下,一次完整的数据采集过程包括发送开始信号、接收响应以及读取温湿度数据等步骤。

该传感器的工作电压范围为3.3V至5.0V,使其能够兼容多种供电系统。在正常工作条件下,DHT11可以提供±2°C的温度精度和±5%的相对湿度精度。尽管这些数值对于某些高精度应用可能不够理想,但对于大多数日常用途来说已经足够。此外,DHT11具有较宽的工作温度范围(0°C至50°C)和湿度范围(20%RH至90%RH),这使得它能够在多种环境中可靠运行。

需要注意的是,DHT11传感器不建议频繁读取数据,因为连续快速的请求可能会导致传感器过载。一般来说,两次读取之间至少应间隔2秒。此外,由于DHT11没有防水功能,在使用时应避免将其直接暴露于水或高湿度环境中,以免影响其使用寿命和准确性。

在本项目中,DHT11传感器将被集成到主控板上,定时采集矿井内的温湿度数据,并通过OLED显示屏显示出来。如果检测到的温湿度超出预设的安全阈值,系统会触发报警机制,提醒工作人员采取措施改善矿井内的环境条件,从而保障矿工的安全和健康。通过这种方式,DHT11传感器为矿井安全监测提供了重要的支持。

【5】红外热释电人体检测传感器

红外热释电人体检测传感器是一种利用人体发出的红外辐射来检测人员存在的装置。这种传感器基于热释电效应工作,当有温度变化时(例如人体移动),传感器中的热释电材料会产生电荷变化,从而生成电信号。这些信号经过放大和处理后,可以用来判断是否有人进入或离开监测区域。

红外热释电传感器通常包含一个菲涅尔透镜,该透镜能够将探测区域分成多个部分,并且每个部分在不同时间点上依次被传感器扫描。这样的设计有助于提高检测范围和灵敏度,同时减少误报率。菲涅尔透镜还能够聚焦红外辐射,使得传感器对较远距离的人体也能做出反应。此外,一些先进的传感器可能还会配备环境温度补偿电路,以适应不同的工作条件,确保在各种温度下都能稳定工作。

这类传感器的一个重要特点是其低功耗特性,非常适合电池供电的应用场景。它们通常只需要很少的能量就能保持工作状态,这在需要长时间无人值守监控的情况下尤为重要。然而,红外热释电传感器也有一些局限性,比如它不能穿透障碍物进行检测,因此安装位置需要避免被物体遮挡;另外,如果环境中有其他热源或温差较大的物体,也可能引起误触发。

在本项目中,红外热释电人体检测传感器将用于监测矿井内是否有人员活动。当检测到人员存在时,系统会点亮指示灯作为视觉提示,这有助于增强现场的安全管理。例如,在紧急情况下,这种信息可以帮助救援队伍更快地定位被困人员的位置。此外,结合其他传感器的数据,如瓦斯浓度和温湿度,可以更全面地评估矿井内的安全状况,为采取进一步的安全措施提供依据。

通过集成红外热释电人体检测传感器,本项目不仅提高了对矿工活动的实时监控能力,也增强了整体系统的智能化水平,有助于构建一个更加安全、高效的地下煤矿作业环境。

1.6 市场可行性调查

img

img

img

基于物联网设计的地下煤矿安全监测与预警系统是一个复杂而全面的系统,通过实时监测、数据分析和预警机制来提高煤矿的安全性。该系统的设计和实施需要综合考虑煤矿环境的特殊性、监测技术的先进性以及预警机制的有效性。

【1】系统架构

根据现有研究,基于物联网的煤矿安全监测与预警系统通常包括感知层、传输层和应用层三个主要部分。感知层负责通过各种传感器收集煤矿环境中的数据,如瓦斯浓度、温度、湿度等。传输层则利用有线和无线通信技术将收集到的数据传输到控制中心。应用层则负责对数据进行处理和分析,并根据分析结果发出预警。

【2】关键技术

  1. 传感器技术:传感器是监测系统的核心,需要能够准确地测量煤矿环境中的各种参数。例如,用于检测瓦斯、一氧化碳等有害气体的传感器,以及用于监测矿工健康状况的生理参数传感器。
  2. 无线通信技术:由于煤矿环境的特殊性,传统的无线通信技术可能无法满足需求。因此,需要开发适合煤矿环境的无线通信技术,如基于RFID和Mesh网络的通信系统。
  3. 数据处理与分析:收集到的数据需要通过高效的数据处理和分析算法进行处理,以识别潜在的安全风险。这包括使用大数据技术和云计算来处理和分析大量数据。
  4. 预警机制:基于数据分析的结果,系统需要能够及时发出预警,通知相关人员采取措施。这可能包括自动化的报警系统和紧急响应机制。

【3】实施挑战

  1. 环境适应性:煤矿环境复杂多变,传感器和通信设备需要能够适应高温、高湿、易爆等恶劣条件。
  2. 数据安全与隐私:在传输和存储过程中保护数据的安全性和矿工的隐私是一个重要挑战。
  3. 系统的可靠性和稳定性:系统需要保证长时间的稳定运行,避免因故障导致的安全事故。

【4】参考文献

1. 孙继平.煤矿物联网特点与关键技术研究[J].煤炭学报,2011. 
2. 马小平,胡延军,缪燕子.物联网、大数据及云计算技术在煤矿安全生产中的应用研究[J].工矿自动化,2014. 
3. B. Jo, Rana Muhammad Asad Khan. “An Event Reporting and Early-Warning Safety System Based on the Internet of Things for Underground Coal Mines: A Case Study.” Applied Sciences(2017). 
4. 孙彦景,钱建生,李世银等.煤矿物联网络系统理论与关键技术[J].煤炭科学技术,2011. 
5. Yufeng Jiang, Wei Chen et al. “Real-Time Monitoring of Underground Miners’ Status Based on Mine IoT System.Sensors (Basel, Switzerland)(2024). 
6. 刘瑞祥.基于物联网的煤矿井下监测网络平台关键技术研究[D].中国矿业大学(北京),2014. 
7. 张静,聂章龙.基于物联网的煤矿安全监测与预警平台设计 附视频[J].煤炭技术,2021. 
8. 付贵祥,周红军,郭继茹.基于物联网的煤矿安全综合智能预警系统[J].工矿自动化,2014. 
9. 田立勤,马亚楠.基于物联网的煤矿实时监测的拓扑可靠性设计与优化分析[J].金属矿山,2017. 
10. 王学琛,郭昕曜,李墨潇等.基于物联网的煤矿安全风险预警平台的研究及应用[J].武汉理工大学学报(信息与管理工程版),2016. 
11. 徐州建筑职业技术学院.煤矿安全检测系统的物联网技术研究[J].煤炭技术,2011. 
12. 国家安全生产监督管理总局通信信息中心.物联网技术在煤矿安全监察中的应用[J].煤矿安全,2014. 
13. 程文岭.基于物联网的数字式煤矿安全监测监控技术研究[J].科技创新与应用,2020. 
14. 国能神东煤炭集团有限责任公司布尔台煤矿.基于物联网技术的煤矿用电安全智能监测研究[J].中国煤炭,2022. 
15. 李瑞华,乔玉峰,刘峰.基于物联网的矿井安全检测系统设计[J].电子设计工程,2016. 
16. 刘香兰,赵旭生,董桂刚.基于物联网的煤矿瓦斯爆炸动态安全预警系统的设计研究[J].煤炭工程,2012. 
17. 淮南联合大学计算机系.基于物联网技术的煤矿人员定位系统及其应用[J].电脑知识与技术,2019. 
18. 黎敏.基于五层物联网架构的煤矿安全监控系统设计[J].煤炭技术,2016. 
19. 徐江陵.基于物联网的智能化煤矿安全监控系统研究[J].煤炭技术,2018. 
20. 粟闯,方思宇,容德春等.基于物联感知技术的地下开采风险管控系统建设及应用 附视频[J].中国矿业,2024. 
21. 刘卫东,张薇,孟晓静.基于物联网的煤矿检测监控系统研究[J].电子器件,2015. 
22. 郭江涛,杨娟.基于物联网感知的煤矿安全监控系统设计[J].自动化与仪器仪表,2015. 
23. 黄成玉,李学哲,张全柱.基于物联网技术的煤矿综合自动化系统[J].煤矿安全,2012. 
24. 西安欧亚学院信息工程学院.基于物联网技术的煤矿智能安全管理系统研究[J].价值工程,2011. 
25. 朱晶.基于物联网技术的煤矿安全监控平台的设计与关键技术[J].机械管理开发,2020. 
26. 黄彩梅,辛乐,黄丹等.基于物联网技术的煤矿定位与监测系统设计[J].传感器与微系统,2013. 
27. 姚逸程.基于物联网的煤矿粉尘在线预警系统[J].绿色科技,2021. 
28. Y. Qi, Wen Ji et al. “Analysis and Design of Monitoring System in Coal Mine Based on Internet of Things.” Applied Mechanics and Materials(2012). 
29. P. Jayarajan, K. V. Gayathri et al. “Improved Cost Effective IoT Based Coal Mining Safety System.” Journal of Physics: Conference Series(2021). 
30. Y. S. Dohare, T. Maity et al. “Design of surveillance and safety system for underground coal mines based on low power WSN.2014 International Conference on Signal Propagation and Computer Technology (ICSPCT 2014)(2014). 

二、硬件选型

1. NBIoT模块 - BC26

BC26是一款支持NB-IoT(窄带物联网)技术的无线通信模块。它具有低功耗、广覆盖的特点,非常适合用于远程数据传输。在这个项目中,BC26模块将负责将采集到的各种环境信息上传至华为云物联网平台,确保数据能够被远端服务器接收并处理。

2. 瓦斯浓度检测模块 - MQ5气体传感器

MQ5是一种半导体气体传感器,专门用于检测可燃气体如甲烷(瓦斯)、液化石油气等。它具有高灵敏度和快速响应时间。在本项目中,MQ5传感器将用来监测矿井内的瓦斯浓度。一旦检测到的浓度达到预设阈值,控制系统会立即启动通风风扇以降低有害气体浓度。

3. 风扇模块 - 矿用通风风扇

为了有效降低矿井内瓦斯等有害气体的浓度,系统采用矿用通风风扇。这些风扇通常设计为能够在恶劣环境下工作,具备防尘、防水等特性。风扇的启停由继电器控制,根据MQ5传感器检测到的瓦斯浓度自动调节。

4. OLED显示屏 - SPI协议OLED显示屏

OLED显示屏以其高对比度、快速响应时间和宽视角而闻名。在本项目中,采用SPI接口的OLED显示屏来显示实时采集的数据,包括温湿度、瓦斯浓度等关键信息。这种显示屏不仅清晰可见,而且功耗较低,适合长时间运行。

5. 温湿度传感器 - DHT11

DHT11是一种经济实惠且易于使用的数字温湿度传感器。它能够同时测量温度和相对湿度,并通过单线数字接口输出数据。在本项目中,DHT11传感器用于监测矿井内的温湿度条件。当检测到的数值超过设定的安全阈值时,系统会触发蜂鸣器报警。

6. 供电电源

  • 控制板系统供电:采用5V 2A外部稳压电源,为微控制器、传感器以及其他低功耗电子元件提供稳定的电力供应。
  • 其他电器供电:对于高功耗设备如风扇,则直接使用市电供电,以保证足够的电力支持其正常工作。

7. 人体检测 - 红外热释电模块

红外热释电传感器利用人体发出的红外辐射来检测人员的存在。在本项目中,该传感器用于监测矿井内是否有人员活动。一旦检测到人员存在,系统会点亮指示灯作为视觉提示,增强现场安全管理。

8. 主控芯片 - STM32F103RCT6

STM32F103RCT6是意法半导体公司推出的一款高性能ARM Cortex-M3微控制器。它具有丰富的外设资源和强大的计算能力,适用于各种嵌入式应用。在本项目中,STM32F103RCT6作为主控芯片,负责处理来自各个传感器的数据、执行控制逻辑以及管理通信协议。

三、部署华为云物联网平台

华为云官网: https://www.huaweicloud.com/

打开官网,搜索物联网,就能快速找到 设备接入IoTDA

image-20221204193824815

3.1 物联网平台介绍

华为云物联网平台(IoT 设备接入云服务)提供海量设备的接入和管理能力,将物理设备联接到云,支撑设备数据采集上云和云端下发命令给设备进行远程控制,配合华为云其他产品,帮助我们快速构筑物联网解决方案。

使用物联网平台构建一个完整的物联网解决方案主要包括3部分:物联网平台、业务应用和设备。

物联网平台作为连接业务应用和设备的中间层,屏蔽了各种复杂的设备接口,实现设备的快速接入;同时提供强大的开放能力,支撑行业用户构建各种物联网解决方案。

设备可以通过固网、2G/3G/4G/5G、NB-IoT、Wifi等多种网络接入物联网平台,并使用LWM2M/CoAP、MQTT、HTTPS协议将业务数据上报到平台,平台也可以将控制命令下发给设备。

业务应用通过调用物联网平台提供的API,实现设备数据采集、命令下发、设备管理等业务场景。

img

3.2 开通物联网服务

地址: https://www.huaweicloud.com/product/iothub.html

image-20221204194233414

点击立即创建

image-20240117134653452

正在创建标准版实例,需要等待片刻。

image-20240117134729401

创建完成之后,点击实例名称。 可以看到标准版实例的设备接入端口和地址。

image-20240425180759670

在上面也能看到 免费单元的限制。

image-20240425180817704

开通之后,点击总览,也能查看接入信息。 我们当前设备准备采用MQTT协议接入华为云平台,这里可以看到MQTT协议的地址和端口号等信息。

image-20240425180845461

总结:

端口号:   MQTT (1883)| MQTTS (8883)	
接入地址:ad635970a1.st1.iotda-device.cn-north-4.myhuaweicloud.com

**根据域名地址得到IP地址信息: **

打开Windows电脑的命令行控制台终端,使用ping 命令。ping一下即可。

Microsoft Windows [版本 10.0.19045.4170]
(c) Microsoft Corporation。保留所有权利。

C:\Users\11266>ping ad635970a1.st1.iotda-device.cn-north-4.myhuaweicloud.com

正在 Ping ad635970a1.st1.iotda-device.cn-north-4.myhuaweicloud.com [117.78.5.125] 具有 32 字节的数据:
来自 117.78.5.125 的回复: 字节=32 时间=35ms TTL=93
来自 117.78.5.125 的回复: 字节=32 时间=36ms TTL=93
来自 117.78.5.125 的回复: 字节=32 时间=36ms TTL=93
来自 117.78.5.125 的回复: 字节=32 时间=39ms TTL=93

117.78.5.125 的 Ping 统计信息:
    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 35ms,最长 = 39ms,平均 = 36ms

C:\Users\11266>

MQTT协议接入端口号有两个,1883是非加密端口,8883是证书加密端口,单片机无法加载证书,所以使用1883端口比较合适。 接下来的ESP8266就采用1883端口连接华为云物联网平台。

3.3 创建产品

(1)创建产品

image-20230109164412041

(2)填写产品信息

根据自己产品名字填写,下面的设备类型选择自定义类型。

image-20240612094809689

(3)产品创建成功

image-20240612095148945

创建完成之后点击查看详情。

image-20240612095134263

(4)添加自定义模型

产品创建完成之后,点击进入产品详情页面,翻到最下面可以看到模型定义。

模型简单来说: 就是存放设备上传到云平台的数据。

你可以根据自己的产品进行创建。

比如:

烟雾可以叫  MQ2
温度可以叫  Temperature
湿度可以叫  humidity
火焰可以叫  flame
其他的传感器自己用单词简写命名即可。 这就是你的单片机设备端上传到服务器的数据名字。

先点击自定义模型。

image-20240612095517900

再创建一个服务ID。

image-20240612095542749

接着点击新增属性。

image-20240612095648815

image-20240612095711898

3.4 添加设备

产品是属于上层的抽象模型,接下来在产品模型下添加实际的设备。添加的设备最终需要与真实的设备关联在一起,完成数据交互。

(1)注册设备

image-20240425181935561

(2)根据自己的设备填写

image-20240612100115167

(3)保存设备信息

创建完毕之后,点击保存并关闭,得到创建的设备密匙信息。该信息在后续生成MQTT三元组的时候需要使用。

image-20240612100128061

(4)设备创建完成

image-20240612100147232

(5)设备详情

image-20240612100202960

image-20240612100217236

3.5 MQTT协议主题订阅与发布

(1)MQTT协议介绍

当前的设备是采用MQTT协议与华为云平台进行通信。

MQTT是一个物联网传输协议,它被设计用于轻量级的发布/订阅式消息传输,旨在为低带宽和不稳定的网络环境中的物联网设备提供可靠的网络服务。MQTT是专门针对物联网开发的轻量级传输协议。MQTT协议针对低带宽网络,低计算能力的设备,做了特殊的优化,使得其能适应各种物联网应用场景。目前MQTT拥有各种平台和设备上的客户端,已经形成了初步的生态系统。

MQTT是一种消息队列协议,使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合,相对于其他协议,开发更简单;MQTT协议是工作在TCP/IP协议上;由TCP/IP协议提供稳定的网络连接;所以,只要具备TCP协议栈的网络设备都可以使用MQTT协议。 本次设备采用的ESP8266就具备TCP协议栈,能够建立TCP连接,所以,配合STM32代码里封装的MQTT协议,就可以与华为云平台完成通信。

华为云的MQTT协议接入帮助文档在这里: https://support.huaweicloud.com/devg-iothub/iot_02_2200.html

img

业务流程:

img

(2)华为云平台MQTT协议使用限制

描述 限制
支持的MQTT协议版本 3.1.1
与标准MQTT协议的区别 支持Qos 0和Qos 1支持Topic自定义不支持QoS2不支持will、retain msg
MQTTS支持的安全等级 采用TCP通道基础 + TLS协议(最高TLSv1.3版本)
单帐号每秒最大MQTT连接请求数 无限制
单个设备每分钟支持的最大MQTT连接数 1
单个MQTT连接每秒的吞吐量,即带宽,包含直连设备和网关 3KB/s
MQTT单个发布消息最大长度,超过此大小的发布请求将被直接拒绝 1MB
MQTT连接心跳时间建议值 心跳时间限定为30至1200秒,推荐设置为120秒
产品是否支持自定义Topic 支持
消息发布与订阅 设备只能对自己的Topic进行消息发布与订阅
每个订阅请求的最大订阅数 无限制

(3)主题订阅格式

帮助文档地址:https://support.huaweicloud.com/devg-iothub/iot_02_2200.html

image-20221207153310037

对于设备而言,一般会订阅平台下发消息给设备 这个主题。

设备想接收平台下发的消息,就需要订阅平台下发消息给设备 的主题,订阅后,平台下发消息给设备,设备就会收到消息。

如果设备想要知道平台下发的消息,需要订阅上面图片里标注的主题。

以当前设备为例,最终订阅主题的格式如下:
$oc/devices/{device_id}/sys/messages/down
    
最终的格式:
$oc/devices/663cb18871d845632a0912e7_dev1/sys/messages/down

(4)主题发布格式

对于设备来说,主题发布表示向云平台上传数据,将最新的传感器数据,设备状态上传到云平台。

这个操作称为:属性上报。

帮助文档地址:https://support.huaweicloud.com/usermanual-iothub/iot_06_v5_3010.html

image-20221207153637391

根据帮助文档的介绍, 当前设备发布主题,上报属性的格式总结如下:

发布的主题格式:
$oc/devices/{device_id}/sys/properties/report
 
最终的格式:
$oc/devices/663cb18871d845632a0912e7_dev1/sys/properties/report
发布主题时,需要上传数据,这个数据格式是JSON格式。

上传的JSON数据格式如下:

{
  "services": [
    {
      "service_id": <填服务ID>,
      "properties": {
        "<填属性名称1>": <填属性值>,
        "<填属性名称2>": <填属性值>,
        ..........
      }
    }
  ]
}
根据JSON格式,一次可以上传多个属性字段。 这个JSON格式里的,服务ID,属性字段名称,属性值类型,在前面创建产品的时候就已经介绍了,不记得可以翻到前面去查看。

根据这个格式,组合一次上传的属性数据:
{"services": [{"service_id": "stm32","properties":{"DHT11_T":30,"DHT11_H":10,"BH1750":1,"MQ135":0}}]}

3.6 MQTT三元组

MQTT协议登录需要填用户ID,设备ID,设备密码等信息,就像我们平时登录QQ,微信一样要输入账号密码才能登录。MQTT协议登录的这3个参数,一般称为MQTT三元组。

接下来介绍,华为云平台的MQTT三元组参数如何得到。

(1)MQTT服务器地址

要登录MQTT服务器,首先记得先知道服务器的地址是多少,端口是多少。

帮助文档地址:https://console.huaweicloud.com/iotdm/?region=cn-north-4#/dm-portal/home

image-20240509193207359

MQTT协议的端口支持1883和8883,它们的区别是:8883 是加密端口更加安全。但是单片机上使用比较困难,所以当前的设备是采用1883端口进连接的。

根据上面的域名和端口号,得到下面的IP地址和端口号信息: 如果设备支持填写域名可以直接填域名,不支持就直接填写IP地址。 (IP地址就是域名解析得到的)

华为云的MQTT服务器地址:117.78.5.125
华为云的MQTT端口号:1883

如何得到IP地址?如何域名转IP? 打开Windows的命令行输入以下命令。

ping  ad635970a1.st1.iotda-device.cn-north-4.myhuaweicloud.com

image-20240425182610048

(2)生成MQTT三元组

华为云提供了一个在线工具,用来生成MQTT鉴权三元组: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/

打开这个工具,填入设备的信息(也就是刚才创建完设备之后保存的信息),点击生成,就可以得到MQTT的登录信息了。

下面是打开的页面:

image-20240425183025893

填入设备的信息: (上面两行就是设备创建完成之后保存得到的)

直接得到三元组信息。

image-20240509193310020

得到三元组之后,设备端通过MQTT协议登录鉴权的时候,填入参数即可。

ClientId  663cb18871d845632a0912e7_dev1_0_0_2024050911
Username  663cb18871d845632a0912e7_dev1
Password  71b82deae83e80f04c4269b5bbce3b2fc7c13f610948fe210ce18650909ac237

3.7 模拟设备登录测试

经过上面的步骤介绍,已经创建了产品,设备,数据模型,得到MQTT登录信息。 接下来就用MQTT客户端软件模拟真实的设备来登录平台。测试与服务器通信是否正常。

(1)填入登录信息

打开MQTT客户端软件,对号填入相关信息(就是上面的文本介绍)。然后,点击登录,订阅主题,发布主题。

image-20240509193457358

(2)打开网页查看

完成上面的操作之后,打开华为云网页后台,可以看到设备已经在线了。

image-20240612100508790

点击详情页面,可以看到上传的数据:

image-20240612100529581

到此,云平台的部署已经完成,设备已经可以正常上传数据了。

(3)MQTT登录测试参数总结

MQTT服务器:  117.78.5.125
MQTT端口号:  183

//物联网服务器的设备信息
#define MQTT_ClientID "663cb18871d845632a0912e7_dev1_0_0_2024050911"
#define MQTT_UserName "663cb18871d845632a0912e7_dev1"
#define MQTT_PassWord "71b82deae83e80f04c4269b5bbce3b2fc7c13f610948fe210ce18650909ac237"

//订阅与发布的主题
#define SET_TOPIC  "$oc/devices/663cb18871d845632a0912e7_dev1/sys/messages/down"  //订阅
#define POST_TOPIC "$oc/devices/663cb18871d845632a0912e7_dev1/sys/properties/report"  //发布


发布的数据:
{"services": [{"service_id": "stm32","properties":{"DHT11_T":30,"DHT11_H":10,"BH1750":1,"MQ135":0}}]}

3.8 创建IAM账户

创建一个IAM账户,因为接下来开发上位机,需要使用云平台的API接口,这些接口都需要token进行鉴权。简单来说,就是身份的认证。 调用接口获取Token时,就需要填写IAM账号信息。所以,接下来演示一下过程。

地址: https://console.huaweicloud.com/iam/?region=cn-north-4#/iam/users

**【1】获取项目凭证 ** 点击左上角用户名,选择下拉菜单里的我的凭证

image-20240509193646253

image-20240509193701262

项目凭证:

28add376c01e4a61ac8b621c714bf459

【2】创建IAM用户

鼠标放在左上角头像上,在下拉菜单里选择统一身份认证

image-20240509193729078

点击左上角创建用户

image-20240509193744287

image-20240314153208692

image-20240314153228359

image-20240314153258229

创建成功:

image-20240314153315444

【3】创建完成

image-20240509193828289

用户信息如下:

主用户名  l19504562721
IAM用户  ds_abc
密码     DS12345678

3.9 获取影子数据

帮助文档:https://support.huaweicloud.com/api-iothub/iot_06_v5_0079.html

设备影子介绍:

设备影子是一个用于存储和检索设备当前状态信息的JSON文档。
每个设备有且只有一个设备影子,由设备ID唯一标识
设备影子仅保存最近一次设备的上报数据和预期数据
无论该设备是否在线,都可以通过该影子获取和设置设备的属性

简单来说:设备影子就是保存,设备最新上传的一次数据。

我们设计的软件里,如果想要获取设备的最新状态信息,就采用设备影子接口。

如果对接口不熟悉,可以先进行在线调试:https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=IoTDA&api=ShowDeviceShadow

在线调试接口,可以请求影子接口,了解请求,与返回的数据格式。

调试完成看右下角的响应体,就是返回的影子数据。

image-20240509194152229

设备影子接口返回的数据如下:

{
 "device_id": "663cb18871d845632a0912e7_dev1",
 "shadow": [
  {
   "service_id": "stm32",
   "desired": {
    "properties": null,
    "event_time": null
   },
   "reported": {
    "properties": {
     "DHT11_T": 18,
     "DHT11_H": 90,
     "BH1750": 38,
     "MQ135": 70
    },
    "event_time": "20240509T113448Z"
   },
   "version": 3
  }
 ]
}

调试成功之后,可以得到访问影子数据的真实链接,接下来的代码开发中,就采用Qt写代码访问此链接,获取影子数据,完成上位机开发。

image-20240509194214716

链接如下:

https://ad635970a1.st1.iotda-app.cn-north-4.myhuaweicloud.com:443/v5/iot/28add376c01e4a61ac8b621c714bf459/devices/663cb18871d845632a0912e7_dev1/shadow

四、上位机开发

为了方便查看设备上传的数据,接下来利用Qt开发一款Android手机APP 和 Windows上位机。

使用华为云平台提供的API接口获取设备上传的数据,进行可视化显示,以及远程控制设备。

4.1 Qt开发环境安装

Qt的中文官网: https://www.qt.io/zh-cn/image-20221207160550486

image-20221207160606892

QT5.12.6的下载地址:https://download.qt.io/archive/qt/5.12/5.12.6

打开下载链接后选择下面的版本进行下载:

qt-opensource-windows-x86-5.12.6.exe 13-Nov-2019 07:28 3.7G Details

软件安装时断网安装,否则会提示输入账户。

安装的时候,第一个复选框里勾选一个mingw 32编译器即可,其他的不管默认就行,直接点击下一步继续安装。

image-20221203151742653

选择MinGW 32-bit 编译器: (一定要看清楚了)

image-20221203151750344

说明: 我这里只是介绍PC端,也就是Windows系统下的Qt环境搭建。 Android的开发环境比较麻烦,如果想学习Android开发,想编译Android程序的APP,需要自己去搭建Android环境。

也可以看下面这篇文章,不过这个文章是在Qt开发专栏里付费的,需要订阅专栏才可以看。 如果不想付费看,也可以自行找其他教程,自己搭建好必须的环境就行了

Android环境搭建的博客链接: https://blog.csdn.net/xiaolong1126626497/article/details/117254453

4.2 新建上位机工程

前面2讲解了需要用的API接口,接下来就使用Qt设计上位机,设计界面,完成整体上位机的逻辑设计。

【1】新建工程

image-20240117144052547

【2】设置项目的名称。

image-20240509195711965

【3】选择编译系统

image-20240117144239681

【4】选择默认继承的类

image-20240117144302275

【5】选择编译器

image-20240314162137170

【6】点击完成

image-20240117144354252

【7】工程创建完成

image-20230421094133333

4.3 设计UI界面与工程配置

【1】打开UI文件

image-20230421094815236

打开默认的界面如下:

image-20240425194845233

【2】开始设计界面

根据自己需求设计界面。

image-20240620151816878

4.4 编译Windows上位机

点击软件左下角的绿色三角形按钮进行编译运行。

image-20240509202031739

编译之后的效果:

image-20240620151858925

4.5 配置Android环境

如果想编译Android手机APP,必须要先自己配置好自己的Android环境。(搭建环境的过程可以自行百度搜索学习)

然后才可以进行下面的步骤。

【1】选择Android编译器

image-20240425232651515

image-20240509202408776

【2】创建Android配置文件

image-20240117144604025

image-20240117144635052

image-20240117144652014

创建完成。

【3】配置Android图标与名称

image-20240612100947190

【3】编译Android上位机

Qt本身是跨平台的,直接选择Android的编译器,就可以将程序编译到Android平台。

然后点击构建。

image-20240509202534407

成功之后,在目录下可以看到生成的apk文件,也就是Android手机的安装包,电脑端使用QQ发送给手机QQ,手机登录QQ接收,就能直接安装。

生成的apk的目录在哪里呢? 编译完成之后,在控制台会输出APK文件的路径。

知道目录在哪里之后,在Windows的文件资源管理器里,找到路径,具体看下图,找到生成的apk文件。

image-20240509202712295

D:/linux-share-dir/QT/build-app_Huawei_Eco_tracking-Android_for_arm64_v8a_Clang_Qt_5_12_6_for_Android_ARM64_v8a-Release/android-build//build/outputs/apk/debug/android-build-debug.apk

五、 BC26-NBIOT模块调试过程

5.1 模块调试接线

image-20240511223245187

image-20240511223256788

image-20240511223308721

5.2 测试模块

第一步接上之后,串口调试助手选择波特率为115200,勾选软件上的发送新行选项。发送AT过去,正常模块会返回OK

只有收到了OK,才表示模块工作正常。

image-20240511204301353

5.3 上电初始化操作

1】查询模块是否正常
AT

OK


【2】获取卡号,查询卡是否插好
AT+CIMI

460041052911195

OK


【3】激活网络
AT+CGATT=1

OK


【4】获取网络激活状态
AT+CGATT?

+CGATT: 1

OK


【5】查询网络质量
AT+CSQ

+CSQ: 26,0

OK
    
【6】 检查网络状态
AT+CEREG=?   //
+CEREG: 0,1 //找网成功
OK

5.4 开启GPS定位

如果需要使用GPS定位就开,不需要使用就不用管。

使用GPS定位还需要将模块上的GPS天线接好,否则也是没有信号的。

官方文档:

image-20220220191400115

1】激活GPS,要等一段时间
AT+QGNSSC=1

OK


【2】查询激活状态,1表示成功激活
AT+QGNSSC?

+QGNSSC: 1

OK


【3】获取一次GPS定位语句
AT+QGNSSRD="NMEA/RMC"
+QGNSSRD: $GNRMC,120715.00,A,3150.78179,N,11711.93433,E,0.000,,310818,,,A,V*19
OK

六、STM32代码开发

6.1 BC26-NBIOT配置代码

#include "ec20.h"
#include "stdlib.h"
#include "string.h"
#include "usart.h"	
#include "iwdg.h"

int errcount = 0;
char atstr[BUFLEN];
char AtStrBuf[BUFLEN];
char *strx,*extstrx,*Readystrx;
extern char AtRxBuffer[512],Rxcouter;


char GPRMCSTR[128]; //转载GPS信息 GPRMC 经纬度存储的字符串
char GPRMCSTRLON[64]; //经度存储字符串 也就是119.20694
char GPRMCSTRLAT[64]; //维度存储字符串,也就是26.06451
char IMEINUMBER[64];//+CGSN: "869523052178994"
//下面是纠正火星坐标的变量定义/
int Get_GPSdata(void);
void Getdata_Change(char status);

    typedef struct 
{
char UtcDate[6];
char longitude[11];//经度原数据
char Latitude[10];//纬度源数据
char longitudess[4];//整数部分
char Latitudess[3];
char longitudedd[8];//小数点部分
char Latitudedd[8];
char Truelongitude[12];//转换过数据
char TrueLatitude[11];//转换过数据
char getstautus;//获取到定位的标志状态	
float gpsdata[2];
}LongLatidata;
LongLatidata latdata;

float tempdata[2];
char latStrAF[64];          //存放数据经纬度用来发送
char lonStrAF[64];   				//存放数据经纬度用来显示
//火星纠偏结束///

只要修改三要素/
#define PRODUCEKEY "6402ac07352830580e48ff7b_dev1_0_0_2023030403"        //设备ID
#define DEVICENAME "6402ac07352830580e48ff7b_dev1"           //用户名
#define DEVICESECRET "517f1c8f18d6b7b2e4c134653dc892edd38c3e86153506df57f7c296d13b37f7" //密码


void Clear_Buffer(void)//清空缓存
{
    u8 i;
		NBIOTSend_RecAccessMode();
    printf(AtRxBuffer);
    for(i=0;i<Rxcouter;i++)
        AtRxBuffer[i]=0;//缓存
    Rxcouter=0;

}


//初始化模块
void  NBIOT_Init(void)
{
    Uart2_SendStr("AT\r\n");
    delay_ms(500);
    strx=strstr((const char*)AtRxBuffer,(const char*)"OK");//返回OK
    errcount = 0;
    while(strx==NULL)
    {
        errcount++;
        printf("\r\n单片机正在连接到模块...\r\n");
        Clear_Buffer();
        Uart2_SendStr("AT\r\n");
        delay_ms(500);
        strx=strstr((const char*)AtRxBuffer,(const char*)"OK");//返回OK
        if(errcount>50)     //防止死循环
        {
            errcount = 0;
            reset_4g();
            __set_FAULTMASK(1); //关闭总中断
            NVIC_SystemReset(); //请求单片机重启
            break;
        }
    }

    Uart2_SendStr("ATE1\r\n"); //回显
    delay_ms(500);
    Clear_Buffer();

    /
    Uart2_SendStr("AT+CPIN?\r\n");//检查SIM卡是否在位
    delay_ms(500);
    strx=strstr((const char*)AtRxBuffer,(const char*)"+CPIN: READY");//查看是否返回ready
    while(strx==NULL)
    {
        Clear_Buffer();
        Uart2_SendStr("AT+CPIN?\r\n");
        delay_ms(500);
        strx=strstr((const char*)AtRxBuffer,(const char*)"+CPIN: READY");//检查SIM卡是否在位,等待卡在位,如果卡识别不到,剩余的工作就没法做了
    }
    Clear_Buffer();
    ///
    Uart2_SendStr("AT+CSQ\r\n"); //检查CSQ
    delay_ms(500);
    Clear_Buffer();
    Uart2_SendStr("ATI\r\n"); //检查模块的版本号
    delay_ms(500);
    Clear_Buffer();


    ///
    Uart2_SendStr("AT+CREG?\r\n");//查看是否注册GSM网络
    delay_ms(500);
    Clear_Buffer();

    Uart2_SendStr("AT+CEREG?\r\n");//查看注册到哪个运营商,支持移动 联通 电信
    delay_ms(500);
    Clear_Buffer();

    Uart2_SendStr("AT+CIMI\r\n");//获取卡号,类似是否存在卡的意思,比较重要。
    delay_ms(1000);
    strx=strstr((const char*)AtRxBuffer,(const char*)"OK");//只要卡不错误 基本就成功
    if(strx)
    {
        printf("============\r\n我的卡号是 : %s \r\n===============\r\n",AtRxBuffer);
        delay_ms(1000);
        Clear_Buffer();

    }
    else
    {
        // printf("卡错误 : %s \r\n",AtRxBuffer);
        delay_ms(300);
        Clear_Buffer();
    }
    Clear_Buffer();

    Uart2_SendStr("AT+CGSN\r\n");//激活网络,PDP
    delay_ms(300);
    strx=strstr((const char*)AtRxBuffer,(const char*)"OK");//返OK
    Clear_Buffer();

    Uart2_SendStr("AT+CGATT?\r\n");//查询激活状态
    delay_ms(300);
    strx=strstr((const char*)AtRxBuffer,(const char*)"+CGATT: 1");//返1 表明激活成功 获取到IP地址了
    Clear_Buffer();
    errcount = 0;
    while(strx==NULL)
    {
        errcount++;
        Clear_Buffer();
        Uart2_SendStr("AT+CGATT?\r\n");//获取激活状态
        delay_ms(300);
        strx=strstr((const char*)AtRxBuffer,(const char*)"+CGATT: 1");//返回1,表明注网成功
        if(errcount>100)     //防止死循环
        {
            errcount = 0;
            reset_4g();
            __set_FAULTMASK(1); //关闭总中断
            NVIC_SystemReset(); //请求单片机重启
            break;
        }
    }

    Uart2_SendStr("AT+QCCID\r\n");//获取当前卡的IP地址
    delay_ms(500);
    Clear_Buffer();
}


void Start_GPS(void)
{
		Clear_Buffer();	
		Uart2_SendStr("AT+QGPS=1\r\n");//查询激活状态
		delay_ms(300);
		strx=strstr((const char*)AtStrBuf,(const char*)"OK");//返1
	
		if(strx==NULL)
		{
				//__set_FAULTMASK(1);
				//NVIC_SystemReset();	//超时重启
				delay_ms(300);
		}
		Clear_Buffer();	
}
//获取定位数据/

/*
AT+QGPSGNMEA="RMC"

+QGPSGNMEA: $GNRMC,035645.00,A,2603.9111,N,11912.4140,E,0.336,,140821,,,A,V*19

OK
AT+QGPSGNMEA="RMC"

+QGPSGNMEA: $GPRMC,145620.00,A,2603.972207,N,11912.411739,E,0.0,0.0,171022,3.5,W,A*2F

*/

char *Get_GPS_RMC(char type)
{
		Clear_Buffer();	
		memset(GPRMCSTR,0,128);
		Uart2_SendStr("AT+QGPSGNMEA=\"RMC\"\r\n");//查询激活状态
		delay_ms(300);
		strx=strstr((const char*)AtRxBuffer,(const char*)"$GPRMC");//返1
		
		while(strx==NULL)
		{
				Clear_Buffer();	
				Uart2_SendStr("AT+QGPSGNMEA=\"RMC\"\r\n");//获取激活状态
				delay_ms(300);
				strx=strstr((const char*)AtRxBuffer,(const char*)"$GPRMC");//返回1,表明注网成功
		}
		sprintf(GPRMCSTR,"%s",strx);

		Clear_Buffer();	//打印收到的GPS信息
		GPRMCSTR[2]=	'P';
		
		//printf("============GETGPRMC==============\r\n%s",GPRMCSTR);		//打印GPRMC
		if(GPRMCSTR[17]=='A')
		{
			memset(latStrAF,0,64);
			memset(lonStrAF,0,64);
			Get_GPSdata();
			
			if(type==1)
				return latStrAF;
			if(type==2)
				return lonStrAF;
		}
		return 0;
}

/*****************************************************
下面是矫正火星坐标的
*****************************************************/


//解GPS析函数
//$GPRMC,134952.00,A,2603.9576,N,11912.4098,E,0.154,,280821,,,A,V*18
int Get_GPSdata()
{
		int i=0;
    strx=strstr((const char*)GPRMCSTR,(const char*)"A,");//获取纬度的位置
       if(strx)
        {
            for(i=0;i<9;i++)
            {
             latdata.Latitude[i]=strx[i+2];//获取纬度值2603.9576
            }
						strx=strstr((const char*)GPRMCSTR,(const char*)"N,");//获取经度值
						if(strx)
						{
								 for(i=0;i<10;i++)	//获取经度 11912.4098
								 {
										latdata.longitude[i]=strx[i+2];
								 }
								 
						}  
						
						printf("latdata.Latitude ,%s \r\n",latdata.Latitude);
						printf("latdata.longitude ,%s \r\n",latdata.longitude);
            latdata.getstautus=1;//                 
	    }
                            
		else
		{
						
				latdata.getstautus=0;
		 }
			Getdata_Change(latdata.getstautus);//数据换算
			Clear_Buffer();
		 return 0;

}





/*************解析出经纬度数据,然后直接提交数据*******************/	

void Getdata_Change(char status)
{
	unsigned char i;	
    	
    if(status)
    {

        for(i=0;i<3;i++)
						latdata.longitudess[i]=latdata.longitude[i];
				for(i=3;i<10;i++)
						latdata.longitudedd[i-3]=latdata.longitude[i];
			
			 latdata.gpsdata[0]=(latdata.longitudess[0]-0x30)*100+(latdata.longitudess[1]-0x30)*10+(latdata.longitudess[2]-0x30)\
		     +((latdata.longitudedd[0]-0x30)*10+(latdata.longitudedd[1]-0x30)+(float)(latdata.longitudedd[3]-0x30)/10+\
		     (float)(latdata.longitudedd[4]-0x30)/100+(float)(latdata.longitudedd[5]-0x30)/1000+(float)(latdata.longitudedd[6]-0x30)/10000)/60.0;//获取完整的数据
       
///
				for(i=0;i<2;i++)
						latdata.Latitudess[i]=latdata.Latitude[i];
				for(i=2;i<9;i++)
						latdata.Latitudedd[i-2]=latdata.Latitude[i];	
				 
			latdata.gpsdata[1]=(float)(latdata.Latitudess[0]-0x30)*10+(latdata.Latitudess[1]-0x30)\
		     +((latdata.Latitudedd[0]-0x30)*10+(latdata.Latitudedd[1]-0x30)+(float)(latdata.Latitudedd[3]-0x30)/10+\
		     (float)(latdata.Latitudedd[4]-0x30)/100+(float)(latdata.Latitudedd[5]-0x30)/1000+(float)(latdata.Latitudedd[6]-0x30)/10000)/60.0;//获取完整的数据b

	
				 sprintf(latStrAF,"%f",latdata.gpsdata[1]);
				 sprintf(lonStrAF,"%f",latdata.gpsdata[0]);
				 
				 			 
				 printf("latStrAF,%s \r\n",latStrAF);
				 printf("lonStrAF,%s \r\n",lonStrAF);
				 
    }
    else
    {
        latdata.gpsdata[0]=0;
        latdata.gpsdata[1]=0;
    }
		
	
}

/*****************************************************
纠偏结束
*****************************************************/

/*********************************************************************************
** 函数名称 : MakeOnenetPayload(char *Str,u8 Temp,u8 Humi)
** 函数功能 : 将温度与湿度封装成Onenet有效载荷包
** 输    入	: *str有效载荷保存的目标字符串, 
** 输    入	: Temp 温度值
** 输    入	: Humi 湿度值
** 输    出	: 有效载荷字符串
** 返    回	: 有效载荷字符串长度
*********************************************************************************/
char JsonBuf[256];//临时数据缓存 
u8 MakeOnenetPayload(u8 *Str,u8 Temp,u8 Humi)//将温度与湿度封装成Onenet有效载荷包
{
  char Payload[] = "{\"datastreams\":[{\"id\":\"Temp\",\"datapoints\":[{\"value\":%d}]},{\"id\":\"Humi\",\"datapoints\":[{\"value\":%d}]}]}";//onenet有效载荷固定格式
	
	unsigned short   StrLen;//有效载荷数据长度
	memset(JsonBuf,0,256);
	sprintf(JsonBuf,Payload,Temp,Humi);//合成数据有效载荷封装
	//printf("\r\n有效载荷(%d):[%s]\r\n",strlen(JsonBuf),(char *)JsonBuf);
	StrLen = strlen(JsonBuf)/sizeof(char);//计算有效载荷的数据长度
	//printf("\r\n有效载荷长度(%d)\r\n",StrLen);
	Str[0] = '\x01';//报文第一个字节的固定显示
	//printf("\r\nStr[0]=0X(%02X)\r\n",Str[0]);
	//报文第2个字节和第三个字节表示有效载荷的长度的固定显示
	Str[1] = (StrLen & 0XFF00) >>8;//高位
	//printf("\r\nStr[1]=0X(%02X)\r\n",Str[1]);
	Str[2] =  StrLen & 0XFF;//低位
	//printf("\r\nStr[2]=0X(%02X)\r\n",Str[2]);
	//拷贝有效载荷数据到Str
	memcpy(Str+3,JsonBuf,StrLen);//从第三个字节开始拷贝
	return (StrLen+3);//返回长度
}

u8 CSTX_4G_MQTT_Senddata(char *data)
{	
	u8 JsonLen;//Json包数据长度
	memset(AtStrBuf,0,BUFLEN);
	Clear_Buffer();
    sprintf(AtStrBuf,"AT+QMTPUB=0,0,0,0,\"$oc/devices/6402ac07352830580e48ff7b_dev1/sys/properties/report\"\r\n");
   // printf("ATSTR = %s \r\n",AtStrBuf);
    Uart2_SendStr(AtStrBuf);//mqtt提交
    delay_ms(300);
		strx=strstr((const char*)AtRxBuffer,(const char*)">");//准备发送数据
		errcount=0;
    while(strx==NULL)
    {
        errcount++;
        strx=strstr((const char*)AtRxBuffer,(const char*)">");//准备发送数据 模块的反馈
				delay_ms(30);
        if(errcount>10)     //超时退出
        {
            errcount = 0;
            break;
        }
    }
		Clear_Buffer();
        
       
		USART2_Send((char *)data,strlen(data));//发送json数据
	
        UART2_send_byte(0x1A);
		delay_ms(300);
		errcount=0;
    strx=strstr((const char*)AtRxBuffer,(const char*)"+QMTPUB: 0,0,0");//返SEND OK +QMTPUB: 0,0,0
    while(strx==NULL)
    {
				errcount++;
        strx=strstr((const char*)AtRxBuffer,(const char*)"+QMTPUB: 0,0,0");//返SEND OK
				delay_ms(30);
        if(errcount>10)     //超时退出
        {
            errcount = 0;
            break;
        }
    }
    Clear_Buffer();
    return 0;
}


u8 MakeOnenetPayloadGPS(u8* Str,char *latstr,char * lonstr)//将温度与湿度封装成Onenet有效载荷包
{
  char Payload[] = "{\"datastreams\":[{\"id\":\"location\",\"datapoints\":[{\"value\":{\"lon\":%s,\"lat\":%s}}]}]}";//onenet有效载荷固定格式

	unsigned short   StrLen;//有效载荷数据长度
	memset(JsonBuf,0,256);
	sprintf(JsonBuf,Payload,lonstr,latstr);//合成数据有效载荷封装
	printf("JSONEND= %s \r\n",JsonBuf);
	//printf("\r\n有效载荷(%d):[%s]\r\n",strlen(JsonBuf),(char *)JsonBuf);
	StrLen = strlen(JsonBuf)/sizeof(char);//计算有效载荷的数据长度
	//printf("\r\n有效载荷长度(%d)\r\n",StrLen);
	Str[0] = '\x01';//报文第一个字节的固定显示
	//printf("\r\nStr[0]=0X(%02X)\r\n",Str[0]);
	//报文第2个字节和第三个字节表示有效载荷的长度的固定显示
	Str[1] = (StrLen & 0XFF00) >>8;//高位
	//printf("\r\nStr[1]=0X(%02X)\r\n",Str[1]);
	Str[2] =  StrLen & 0XFF;//低位
	//printf("\r\nStr[2]=0X(%02X)\r\n",Str[2]);
	//拷贝有效载荷数据到Str
	memcpy(Str+3,JsonBuf,StrLen);//从第三个字节开始拷贝
	return (StrLen+3);//返回长度
}

void CSTX_4G_ONENETIOTSenddataGPS(char *latstr,char *lonstr)//上发数据,上发的数据跟对应的插件有关系,用户需要注意插件然后对应数据即可
{
//		int JsonLen= 0;
//    memset(AtStrBuf,0,BUFLEN);
//	
//		Clear_Buffer();	//发送命令之前清空之前的模块反馈的数据
//    sprintf(AtStrBuf,"AT+QMTPUB=0,0,0,0,\"$dp\"\r\n");	//发送ONENET命令
//    printf("AtStrBuf = %s \r\n",AtStrBuf);
//    Uart2_SendStr(AtStrBuf);//mqtt提交
//    delay_ms(300);
//		strx=strstr((const char*)AtRxBuffer,(const char*)">");//模块反馈可以发送数据了
//		errcount=0;
//    while(strx==NULL)
//    {
//        errcount++;
//        strx=strstr((const char*)AtRxBuffer,(const char*)">");//模块反馈可以发送数据了
//				delay_ms(30);
//        if(errcount>100)     //防止死循环跳出
//        {
//            errcount = 0;
//            break;
//        }
//    }
//		//命令发送成功下面就去发送数据了
//		//Clear_Buffer();

//		JsonLen = MakeOnenetPayloadGPS((u8*)Send_Json,latstr,lonstr);	//组建CJSON数据
//		USART2_Send((char *)Send_Json,JsonLen);//发送json 数据
//		delay_ms(10);
//		UART2_send_byte(0x1A);
//    strx=strstr((const char*)AtRxBuffer,(const char*)"+QMTPUB: 0,0,0");//返发送成功
//		errcount=0;
//    while(strx==NULL)
//    {
//				errcount++;
//				strx=strstr((const char*)AtRxBuffer,(const char*)"+QMTPUB: 0,0,0");//返发送成功
//				delay_ms(10);
//				if(errcount>100)     //超时退出死循环 表示服务器连接失败
//        {
//            errcount = 0;
//            break;
//        }
//    }
//		
//    Clear_Buffer();

}



6.2 主函数里的项目逻辑代码

下面是项目的主函数里的项目逻辑代码(其他子模块的代码太多,文档无法全部贴出)。

可以去网盘里下载传感器模块的代码:https://pan.quark.cn/s/145a9b3f7f53

#include "stm32f10x.h"
#include "sensors.h"  // 传感器驱动
#include "lcd.h"      // LCD显示驱动
#include "nbiot.h"    // NBIoT模块驱动
#include "mqtt.h"     // MQTT协议库
#include "relay.h"    // 继电器控制
#include "delay.h"    // 延时函数
#include <string.h>   // 字符串处理函数

// 初始化所有外设
void Hardware_Init(void) {
    // 初始化GPIO
    GPIO_InitTypeDef GPIO_InitStructure;
    // ... 配置必要的GPIO引脚(如LCD接口、继电器控制等)

    // 初始化定时器(用于周期性任务)
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    // ... 配置定时器

    // 初始化传感器
    Sensors_Init();

    // 初始化LCD
    LCD_Init();

    // 初始化NBIoT模块
    NB_IoT_Init();

    // 初始化MQTT客户端
    MQTT_Init();
}

// 检查并执行灌溉命令
void CheckAndExecuteIrrigationCommands(void) {
    // 从云端获取最新的灌溉命令
    char *irrigation_command = MQTT_Subscribe("irrigation/command");

    if (irrigation_command != NULL) {
        // 解析命令并控制相应的继电器
        Relay_Control(irrigation_command);
    }
}

// 主函数
int main(void) {
    // 初始化硬件
    Hardware_Init();

    // 主循环
    while (1) {
        // 读取传感器数据
        float soil_temp, soil_humidity, air_temp, air_humidity, light_intensity, air_quality;
        Sensors_Read(&soil_temp, &soil_humidity, &air_temp, &air_humidity, &light_intensity, &air_quality);

        // 显示到LCD
        LCD_DisplayData(soil_temp, soil_humidity, air_temp, air_humidity, light_intensity, air_quality);

        // 通过NBIoT上传数据到华为云IoT
        if (NB_IoT_IsConnected()) {
            char data[128];
            snprintf(data, sizeof(data), 
                     "soil_temp=%.2f,soil_humidity=%.2f,air_temp=%.2f,air_humidity=%.2f,light_intensity=%.2f,air_quality=%.2f",
                     soil_temp, soil_humidity, air_temp, air_humidity, light_intensity, air_quality);
            MQTT_Publish("sensor/data", data);
        }

        // 检查并执行灌溉命令
        CheckAndExecuteIrrigationCommands();

        // 延时一段时间
        Delay(5000);  // 例如每5秒更新一次
    }
}

七、总结

本项目设计并实现一套基于物联网技术的地下煤矿安全监测与预警系统,以提高矿工工作环境的安全性。该系统通过集成多种传感器技术,能够实时监控矿井内的温湿度、瓦斯浓度及人员活动情况,并在检测到异常时及时发出警报,采取相应的安全措施。

系统硬件核心采用STM32F103RCT6微控制器,结合DHT11温湿度传感器、MQ5气体传感器以及红外热释电人体感应模块,分别用于环境温湿度、瓦斯浓度和人员存在的监测。当环境参数超过预设的安全阈值时,系统将自动激活蜂鸣器报警,并通过控制继电器启动通风风扇以降低有害气体浓度。此外,OLED显示屏被用作现场显示终端,提供直观的数据展示。为了实现远程数据传输与管理,系统还集成了BC26 NBIOT模块,可以将收集到的信息上传至华为云物联网平台,便于管理者进行数据分析和决策支持。

为提升用户体验,我们使用Qt框架开发了一款运行于Windows平台上的可视化大屏软件界面,能够实时展现来自地下煤矿的各类监测数据,使管理人员能够迅速掌握矿区状况并作出响应。整个系统的供电设计考虑了稳定性和安全性,其中控制电路部分由5V 2A稳压电源供应,而风扇等高功耗设备则直接接入市电,确保长时间可靠运行。

本项目不仅增强了地下煤矿作业场所的安全保障能力,也为未来构建更加智能化、信息化的矿山管理体系奠定了基础。