基于物联网设计的疫苗冷链物流监测系统

一、前言

1.1 项目开发背景

随着全球经济的发展和物流行业的不断创新,疫苗和生物制品的运输要求变得越来越高。尤其是疫苗的冷链物流,温度、湿度等环境因素的控制直接关系到疫苗的质量和效力,因此高效、可靠的冷链监控系统显得尤为重要。冷链物流系统通常用于保持药品、食品等易腐物品的稳定运输环境,对于疫苗的运输尤为关键,因为不当的温湿度变化可能导致疫苗失效,从而影响公众健康。

传统的冷链物流监测方法主要依赖人工记录和定期检查,这不仅增加了人工成本,还存在检测盲区和延时问题。为了应对这一挑战,物联网技术为冷链物流提供了更加精准、实时的数据监控手段。通过传感器技术和无线通信,物流过程中每一环节的环境数据都能够实时采集并上传至云平台,进行远程监控和控制。这种高效的信息化管理方式,不仅能够提高疫苗运输过程中的安全性,还能提升物流管理效率,减少人为疏忽和延误。

本项目设计一个基于物联网的疫苗冷链物流监测系统,采用温湿度传感器、震动传感器、GPS定位模块等硬件设备,结合STM32F103RCT6主控芯片、4G通信模块、云平台等技术,打造一个实时监测、自动控制和远程管理的系统。该系统能够自动监测和调节运输过程中的温度、湿度,并及时报警提醒驾驶员,确保疫苗在运输过程中的质量和安全。同时,系统支持通过手机APP和后端服务器进行数据查看和历史数据分析,进一步增强了系统的可靠性和智能化水平。

随着全球冷链物流需求的日益增加,尤其是在疫苗运输领域,创新的物联网冷链监测解决方案成为了保障公共健康的重要工具。通过将物联网技术与传统冷链物流管理相结合,可以实现实时数据采集、远程控制和智能化管理,为疫苗冷链物流提供全方位、无死角的保障。这对于提升疫苗运输的可靠性和效率,降低疫苗浪费和风险,具有重要的现实意义和广泛的应用前景。

1.2 设计实现的功能

(1)温度监测与控制

通过温度传感器实时采集运输环境中的温度数据。当检测到温度超过预设的安全阈值时,系统自动启动制冷风机进行降温,确保运输环境保持在疫苗所需的适宜温度范围内。

(2)湿度监测与控制

通过湿度传感器实时采集运输环境中的湿度数据。当湿度值低于设定的正常范围时,系统自动启用加湿器进行加湿,保证运输环境的湿度符合疫苗运输要求。

(3)震动监测与警报

系统集成震动传感器,实时监测运输过程中可能出现的震动情况。当震动强度超出设定值时,系统会通过蜂鸣器发出警报,提醒驾驶员注意行驶中的震动情况,并采取必要的减速或避免剧烈颠簸。

(4)温湿度值设置与调节

通过硬件按键,用户可以手动设置温度和湿度的安全阈值。当运输过程中温度或湿度变化超过设定范围时,系统会启动自动调节机制。

(5)环境数据实时显示

系统配备小尺寸的1.44寸显示屏,实时显示当前运输环境的温度、湿度和震动等重要数据。驾驶员可以直观地了解运输环境的当前状态。

(6)无线数据传输与远程监控

采用4G模块将传感器采集的实时数据无线传输到云平台,并通过手机APP进行远程监控。用户可以在APP端查看当前温湿度数据,及时获取运输环境的状态信息,确保运输过程中的数据透明和可控。

(7)历史数据存储与查询

通过云平台保存传感器采集的历史数据。用户可以通过手机APP或后端服务器查询历史数据,进行数据分析和趋势预测,从而优化运输过程中的环境管理。

(8)GPS定位与实时跟踪

系统集成GPS模块,实时跟踪运输车辆的位置,获取车辆的经纬度信息,并将位置数据上传至云平台。用户通过手机APP可以实时查看车辆的当前位置,确保运输过程的可追溯性。

(9)数据上云与平台管理

系统支持将采集的数据通过4G模块上传到华为云物联网平台,实现数据存储和管理。云平台可以展示实时数据,并支持历史数据分析与可视化展示,帮助管理人员全面监控冷链运输过程。

(10)后端服务器与可视化网页

系统搭建Python后端服务器,接收来自云平台的数据,并设计HTML前端页面进行展示。用户可以通过电脑或手机浏览器查看环境数据,进行实时控制和历史数据查询,支持局域网和公网访问。

(11)系统报警与异常处理

当温度、湿度或震动等环境指标异常时,系统会自动触发报警机制,通过蜂鸣器、APP通知等方式提醒驾驶员或管理人员采取适当的处理措施,防止疫苗运输过程中发生质量问题。

(12)自动化控制与人工干预

在正常运输过程中,系统会根据实时数据自动调节温湿度和震动状态。如果出现无法自动解决的问题,驾驶员或管理人员可通过APP手动控制设备(如风机、加湿器等)进行调整,确保运输环境始终符合要求。

1.3 项目硬件模块组成

(1)主控芯片(STM32F103RCT6)

STM32F103RCT6作为项目的核心控制单元,负责所有传感器数据的采集、处理和控制命令的执行。它通过与各个外部模块的通信,协调各个子系统的工作,确保整个系统的正常运行。

(2)温湿度传感器(SHT30)

SHT30传感器用于实时采集运输环境中的温度和湿度数据,并将其传输至主控芯片。该传感器具有高精度和稳定性,适用于需要精确环境监控的冷链物流系统。

(3)震动传感器

震动传感器用于监测运输过程中的震动情况,当震动超过设定阈值时,系统会发出警报,提醒驾驶员注意行驶状态。它能有效避免运输中的剧烈颠簸对疫苗质量造成影响。

(4)4G通信模块(Air724UG)

Air724UG 4G模块用于实现数据的无线传输,将传感器采集的数据上传至云平台。通过4G模块,系统能够随时进行远程监控和控制,确保冷链运输的实时数据不间断传输。

(5)GPS定位模块(中科微ATGM336H-GPS模块)

GPS模块用于实时获取运输车辆的位置数据,并将经纬度信息上传至云平台。通过GPS定位,用户可以随时查看车辆的实时位置,确保运输过程的可追溯性。

(6)显示屏(1.44寸显示屏)

1.44寸小尺寸显示屏用于实时显示运输环境的关键数据,如温度、湿度、震动状态等。它为驾驶员提供了一个直观的界面,便于在驾驶过程中随时查看运输环境的状态。

(7)蜂鸣器

蜂鸣器用于在发生异常情况时发出声音警报。通过蜂鸣器,系统能够在温度、湿度或震动等环境数据异常时及时提醒驾驶员采取措施,从而确保疫苗运输的安全性。

(8)加湿器

加湿器用于自动调节运输环境的湿度。当湿度值低于设定值时,加湿器会自动启用,确保运输环境始终维持在适宜的湿度范围,避免湿度过低影响疫苗质量。

(9)制冷风机

制冷风机用于自动调节运输环境的温度。当检测到温度超出设定的安全范围时,风机会自动启动进行降温,以确保运输过程中疫苗存储在适宜的低温环境中。

(10)按键模块

按键模块用于手动设置温度、湿度等环境参数的阈值。用户可以通过按键方便地调节和设定监控的标准值,以适应不同类型疫苗的运输需求。

(11)电源模块

电源模块为整个系统提供稳定的电力支持。它需要支持4G模块、传感器、蜂鸣器等各个硬件设备的功耗需求,并确保系统在运输过程中的持续稳定运行。

(12)传感器接口电路

传感器接口电路用于连接各类传感器(温湿度传感器、震动传感器等)与主控芯片。它们提供电气连接和数据传输通道,确保数据从传感器正确、及时地传送至主控芯片进行处理。

(13)云平台通信模块(MQTT协议)

云平台通信模块用于通过MQTT协议将数据上传到华为云物联网平台,实现实时监控、数据存储和历史数据分析。该模块支持与后端服务器的通信,确保数据的远程传输与访问。

1.4 设计思路

本项目的设计思路主要围绕如何实现疫苗运输过程中的环境监控与控制,确保疫苗在运输过程中的温湿度、震动等关键因素始终处于安全范围内,最大程度地保证疫苗的质量和效力。设计思路分为硬件选择、数据采集与处理、控制策略、无线通信与远程监控等几个主要部分。

在硬件选择上,本项目采用了STM32F103RCT6主控芯片作为核心控制单元,具备较强的处理能力和丰富的外设接口,能够高效地完成各类传感器的数据采集和控制指令的执行。为了精准监测运输环境中的温湿度情况,选择了SHT30温湿度传感器,该传感器具有高精度、低功耗、响应速度快等特点,适合用于对冷链物流过程中的环境进行精细监控。对于震动检测,选用了震动传感器,能够实时捕捉到运输中的震动状态,尤其在运输过程中发生剧烈震动时,系统将立即触发报警机制。此外,4G通信模块Air724UG用于实现数据的远程无线传输,而GPS模块则能够为系统提供实时的位置信息,便于追踪车辆的具体位置。

数据采集和处理是系统设计中的核心部分。通过各类传感器采集温度、湿度、震动等环境数据后,主控芯片STM32将负责对这些数据进行实时处理和分析。一旦发现环境数据超出设定的安全范围,系统会根据设定的控制策略做出响应。例如,当温度过高时,系统会自动启动制冷风机进行降温;当湿度过低时,加湿器会自动启用,补充环境湿度;当震动过于剧烈时,蜂鸣器会发出警报,提醒驾驶员注意行驶情况。通过这样的实时控制,系统可以确保疫苗运输过程中的环境始终处于安全状态。

为了实现远程监控和管理,系统采用了4G模块与华为云物联网平台进行数据交互。通过MQTT协议,系统将实时数据上传至云平台,确保用户可以通过手机APP或计算机终端远程查看运输环境的温湿度、震动等数据,并进行实时控制。用户还可以通过云平台查询历史数据,进行趋势分析和数据回溯,以便及时发现潜在的问题并进行调整。与此同时,云平台与本地服务器之间的通信,确保了数据的高效存储与展示。

系统还具备灵活的控制方式。驾驶员可以通过按键模块手动设置和调整温度、湿度等环境参数的阈值,适应不同类型疫苗的运输需求。在自动模式下,系统能够根据实时数据进行自动调节;而在人工干预模式下,驾驶员或管理人员可以通过APP或显示屏直接调整设备的工作状态。

整个系统的设计充分考虑了其稳定性、可靠性和易用性。所有的硬件模块和软件算法均经过优化,确保在复杂的运输环境下能够稳定运行。此外,系统支持在不同的网络环境下进行远程访问和控制,无论是在局域网还是公网环境下,都能够保证数据的准确传输和实时监控。

本项目的设计思路是在物联网技术和嵌入式硬件的支持下,通过高精度传感器和智能控制策略,实现对疫苗运输过程的全面监控与管理,确保疫苗冷链物流的安全、可靠与高效。

1.5 系统功能总结

功能模块 功能描述
温度监测与控制 实时监测运输环境中的温度,当温度超过设定值时,自动启动制冷风机进行降温。
湿度监测与控制 实时监测运输环境中的湿度,当湿度低于设定值时,自动启动加湿器进行加湿,保证环境湿度适宜。
震动监测与报警 实时监测运输中的震动情况,当震动超出设定阈值时,通过蜂鸣器发出警报,提醒驾驶员减少震动。
温湿度设置功能 通过按键模块手动设置温度和湿度的安全阈值,允许用户根据不同需求进行调整。
环境数据实时显示 在显示屏上实时显示温度、湿度、震动等关键环境数据,供驾驶员查看当前运输环境的状态。
无线数据传输 通过4G模块将环境数据实时上传至云平台,支持手机APP和计算机端进行远程监控。
历史数据查询 支持通过云平台保存和查询历史数据,便于数据分析和运输过程中环境趋势的回溯。
GPS定位与追踪 实时获取车辆位置,显示车辆的经纬度信息,确保运输过程的可追溯性,并支持通过云平台实时查看车辆位置。
数据上云 将所有环境数据通过MQTT协议上传至华为云物联网平台,实现数据存储、展示和分析。
后台数据展示 通过Python后端服务器,设计HTML前端页面,将数据通过可视化网页展示,支持电脑和手机浏览器访问。
报警与异常处理 当温度、湿度、震动等环境参数异常时,系统会发出声音或APP通知报警,提醒驾驶员采取必要的处理措施。
手动与自动控制 系统支持自动控制模式,根据实时环境数据进行调整,也支持手动控制,允许驾驶员或管理人员进行干预调整。

1.6 开发工具的选择

STM32的编程语言选择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是有点不适应界面的。

1.7 参考文献

1.8 模块的技术详情介绍

【1】Air724UG-4G模块

Air724UG是一款功能强大且广泛应用于物联网(IoT)领域的4G通信模块。它专为低功耗广域网(LPWAN)应用设计,兼具高性能和稳定性,适用于多种物联网终端设备,包括智能表计、移动支付、智能家居、车载电子等场景。该模块支持4G LTE Cat 1网络制式,是一款具备高性价比的无线通信解决方案。

Air724UG这款模块支持LTE FDD网络,能够提供稳定的语音和数据传输服务,并向下兼容2G GSM网络,使得在4G信号弱或不可用的区域仍可正常通信。由于其双网支持能力,这一模块可以灵活适应不同的网络环境,从而更广泛地满足客户需求。

在数据通信方面,Air724UG模块支持SMS(短消息服务)、TCP/UDP、HTTP/HTTPS、MQTT等协议,为用户开发与应用提供了多种可选方案。其良好的传输能力,能够满足物联网设备对数据可靠性、响应速度等方面的严苛需求。这使其在多种行业和领域中得到了广泛应用,如工业自动化、智能物流、移动支付等。模块具备高效的数据传输和低延迟特性,是许多物联网解决方案中的理想选择。

Air724UG模块在设计上注重低功耗特性,这在许多长期依赖电池供电的IoT设备中显得尤为重要。模块支持深度睡眠模式和待机模式,有效降低功耗,延长设备的使用寿命。此外,Air724UG的尺寸较为紧凑,提供易于集成的设计,能够在有限的空间内实现灵活部署,适应各种复杂应用场景。

在接口和硬件配置方面,Air724UG-4G模块集成了丰富的接口,包括UART、I2C、SPI、ADC、GPIO等,为用户提供了极大的开发灵活性。此外,模块还具备支持多种通信协议和功能的AT指令集,便于用户进行功能扩展和定制。模块的工作温度范围广,能够在严苛的环境下保持稳定性能,使其在工业、户外和其他环境条件变化较大的场景中表现出色。

综合而言,Air724UG模块是一款兼顾高性能与灵活性的4G模块,专注于物联网应用的低功耗和高稳定性需求。它的多网络支持、强大的数据传输能力、低功耗特性以及灵活的硬件接口设计,使其成为物联网设备开发中备受青睐的选择。

【2】MQTT协议

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)是一种轻量级、发布/订阅模式的消息传输协议,专为低带宽、不可靠网络环境设计。它最早由IBM提出,现已成为物联网(IoT)通信的重要协议之一。由于其高效、低功耗和实时性等特点,MQTT在智能家居、工业自动化、远程监控和车联网等领域得到了广泛应用。

MQTT的工作原理基于发布/订阅模型。这种模型有别于传统的客户端-服务器模型,通信方不需要直接建立连接。MQTT由三个核心组件构成:客户端、代理(Broker)和主题(Topic)。客户端可以作为消息的发布者或订阅者,消息通过代理进行路由。代理是一个中间服务端,用于接收和分发来自不同客户端的消息。发布者发送消息到一个特定的主题上,代理负责将这些消息分发给所有订阅了该主题的客户端。通过这种解耦的架构设计,客户端之间可以实现松耦合的通信,降低了复杂性和依赖性。

在MQTT协议中,消息被分为不同的主题(Topic),例如"home/sensor/temperature"可以用来代表温度传感器数据。客户端可以订阅这个主题,当发布者发送新的数据到该主题时,所有订阅该主题的客户端都会收到更新信息。这种灵活的主题结构和层次化的命名规则,使得MQTT在复杂场景下也能快速组织和管理消息流。

MQTT协议支持三种服务质量(QoS)等级,分别为"至多一次"(QoS 0)、"至少一次"(QoS 1)和"仅一次"(QoS 2)。QoS 0表示消息传输尽力而为,可能会丢失或重复;QoS 1确保消息至少送达一次,但可能会有重复;QoS 2则确保消息恰好传输一次,保证消息的严格可靠性。这种设计使MQTT能够适应不同的应用场景,用户可以根据应用需求选择合适的QoS级别。

为了保证通信的安全性,MQTT支持用户名和密码验证,代理可以对连接进行身份认证。此外,许多实现中还支持TLS/SSL加密通信,确保数据在传输过程中不会被窃取或篡改。用户也可以使用不同的认证方式来增强系统的安全性,适应物联网应用中对安全性的高需求。

MQTT非常注重轻量化和低功耗。它的报文头非常小,通信开销很低,这使其特别适合在资源受限的设备或不稳定的网络环境中使用。MQTT支持"保持连接"和"遗嘱消息"功能,客户端可以在连接断开时自动向代理发送遗嘱消息,通知其他客户端连接状态的变化。这种特性有助于提高网络的健壮性和系统的可用性。

MQTT的典型使用场景包括物联网设备数据采集、实时监控、消息推送和控制命令的发布。比如在智能家居中,传感器可以发布环境数据,如温湿度、烟雾浓度等,控制设备根据收到的消息作出响应,实现自动化操作。在工业场景中,MQTT可以帮助收集和管理大规模设备的运行状态,实现集中化和高效的设备监控。

总的来说,MQTT协议凭借其低功耗、高效能、实时性强等优势,已成为物联网通信的主要协议之一。它的发布/订阅模式简化了设备之间的通信,使其特别适合多对多、低延迟、高可靠性的数据传输场景。MQTT易于使用、拓展性强,为开发者提供了灵活的解决方案来构建各种物联网应用。

【3】中科微ATGM336H-GPS模块

中科微ATGM336H-GPS模块是一款高性能、低功耗的全球定位模块,专为卫星定位导航应用设计。该模块集成了GNSS基带处理器和RF接收器,支持GPS、GLONASS、BDS(北斗)等多种卫星系统的定位信号,能够实现快速精准的定位,并提供稳定可靠的位置、速度和时间数据。ATGM336H模块广泛应用于车辆定位、物流跟踪、无人机导航、智能穿戴设备、户外运动设备和物联网等领域。

ATGM336H模块采用小巧的LCC封装,尺寸为16mm x 12.2mm x 2.3mm,便于集成到各种紧凑型设备中。模块内置高灵敏度接收芯片,具有-165dBm的高灵敏度,即使在复杂环境下也能快速捕获和跟踪卫星信号。其冷启动时间在开阔地带一般小于30秒,热启动时间约为1秒,重捕获时间小于1秒,使其在车辆移动和各种快速切换的场景下表现出色,定位精度可达2.5米。

该模块支持多种工作模式,以满足不同应用的功耗要求。它不仅可以在普通模式下连续定位,还支持周期性模式和节电模式,通过关闭部分功能或降低数据输出频率来减少功耗,适合电池供电的便携式设备。其最低功耗在微安级别,能够显著延长电池续航时间,使其成为移动设备的理想选择。

ATGM336H-GPS模块的接口丰富,支持UART、I2C、SPI等多种通信接口,方便与主控MCU进行数据交换。模块提供的标准NMEA协议输出和二进制格式数据能够直接对接多种导航应用程序。此外,模块还具有内置的天线检测功能和动态干扰抑制技术,有助于在有较强电磁干扰的环境中保持定位精度,并能实时检测和报告天线状态,进一步提高定位可靠性。

为了提高用户体验和简化开发过程,中科微为ATGM336H模块提供了完善的开发手册和技术支持,便于开发者快速上手并将其应用到多种设备中。此外,模块还支持多卫星系统协同定位的功能,通过融合GPS、BDS、GLONASS等卫星数据,提高在市区、高山、森林等卫星信号受限环境下的定位精度和稳定性,使其适用于复杂环境的高精度定位需求。

二、硬件选型(搭建模型参考)

如果大家想自己搭建模型,完成这个项目的功能测试。

那么可以看参考下面的部分硬件模块选型。

在本项目中,硬件选型是确保疫苗冷链物流监测系统稳定运行的关键。该系统的硬件组成包括主控芯片、传感器模块、通信模块、显示模块、控制模块以及电源模块等,下面是各个硬件模块的详细选型和描述:

1. 主控芯片(STM32F103RCT6)

STM32F103RCT6是本系统的核心控制单元,基于ARM Cortex-M3架构,提供强大的运算能力和丰富的外设接口,能够支持温湿度传感器、震动传感器、显示屏、4G模块等多个设备的并行工作。其高效的处理能力能够实时处理传感器数据并进行控制输出,适用于嵌入式物联网应用。

2. 温湿度传感器(SHT30)

SHT30温湿度传感器用于实时采集运输环境中的温度和湿度数据。该传感器具有较高的测量精度,响应速度快,适合精确监测冷链运输环境的温湿度,确保疫苗运输过程中环境条件符合标准。

3. 震动传感器

震动传感器用于监测运输过程中的震动情况,尤其是当运输环境发生剧烈震动时,系统能够及时触发警报,提醒驾驶员注意行驶状态。这是冷链物流监控系统中的一个关键安全功能,避免因过度震动影响疫苗的质量。

4. 4G通信模块(Air724UG)

Air724UG 4G模块用于数据的无线传输,支持将采集的温湿度、震动等数据通过4G网络上传至云平台。该模块支持高速数据传输,能够确保系统在任何时间和地点都能实时上传数据,并通过APP进行远程监控和控制。

5. GPS定位模块(中科微ATGM336H-GPS模块)

GPS模块提供实时的车辆位置数据,能够精确地获取车辆的经纬度信息,并上传到云平台。通过GPS定位,系统能够在地图上实时显示运输车辆的位置,确保运输过程的可追溯性和监控。

6. 显示屏(1.44寸OLED显示屏)

1.44寸OLED显示屏用于在驾驶室内实时显示环境数据,包括温度、湿度、震动等关键监控数据。OLED屏具有高亮度和低功耗的优点,适合在车载环境中使用,且显示清晰,驾驶员可以直观地查看运输环境状态。

7. 蜂鸣器

蜂鸣器用于在系统检测到异常情况时发出警报。当温度、湿度或震动等数据超出预设的安全范围时,蜂鸣器将发出声音提醒,警告驾驶员或工作人员采取必要的纠正措施。蜂鸣器是系统的重要警报元件。

8. 加湿器

加湿器用于当运输环境湿度低于设定值时,自动增加环境湿度。它确保冷链运输过程中,尤其是需要特定湿度条件的疫苗能够得到良好的存储环境,从而避免疫苗质量受湿度过低的影响。

9. 制冷风机

制冷风机用于当温度超出设定的安全范围时,自动启动进行降温,确保运输过程中疫苗始终处于适宜的温度环境。制冷风机的选择需要根据实际需求,保证能够在运输过程中快速降低温度,以适应不同环境的要求。

10. 按键模块

按键模块用于手动设置和调整温湿度阈值,允许驾驶员或操作员根据不同的运输需求,快速修改系统的温湿度标准。它为系统提供了人工干预的接口,增加了操作灵活性。

11. 电源模块

电源模块为整个系统提供稳定的电力供应,确保系统在运输过程中持续可靠地工作。电源模块需要支持4G模块、传感器、蜂鸣器等硬件的功耗需求,并具有良好的电源管理能力。

12. 数据存储模块(可选)

为了实现历史数据查询和分析,本系统可以配备数据存储模块,如SD卡模块或EEPROM。数据存储模块用于存储重要的环境数据,便于后期的查阅和分析,尤其是在网络不稳定或无信号的情况下,仍能保证数据的本地记录。

13. 无线通信模块(MQTT协议)

为实现数据上传和远程控制,系统采用了MQTT协议进行无线通信。通过4G模块与华为云物联网平台进行数据交换,确保监控数据能够及时上传至云端,且通过APP实现远程控制和监控。

14. 后端服务器与可视化模块

后端服务器用于接收来自4G模块上传的数据,并将其通过API接口与前端网页进行交互。前端网页采用HTML、CSS和JavaScript等技术进行可视化展示,支持电脑和手机浏览器访问,用户可以在网页上查看实时数据、历史数据以及控制设备。

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

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

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

3.1 物联网平台介绍

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

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

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

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

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

3.2 开通物联网服务

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

开通免费单元。

点击立即创建

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

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

下面框起来的就是端口号域名

点击实例名称,可以查看当前免费单元的配置情况。

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

总结:

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

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

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

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

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

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

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

C:\Users\Lenovo>

MQTT协议接入端口号有两个,1883是非加密端口,8883是证书加密端口,单片机无法加载证书,所以使用1883端口合适

3.3 创建产品

链接:https://console.huaweicloud.com/iotdm/?region=cn-north-4#/dm-dev/all-product?instanceId=03c5c68c-e588-458c-90c3-9e4c640be7af

(1)创建产品

(2)填写产品信息

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

(3)产品创建成功

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

(4)添加自定义模型

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

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

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

比如:

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

先点击自定义模型。

再创建一个服务ID。

接着点击新增属性。

3.4 添加设备

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

(1)注册设备

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

(3)保存设备信息

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

(4)设备创建完成

(5)设备详情

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

业务流程:

(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

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

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

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

cpp 复制代码
以当前设备为例,最终订阅主题的格式如下:
$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

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

cpp 复制代码
发布的主题格式:
$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":{"你的字段名字1":30,"你的字段名字2":10,"你的字段名字3":1,"你的字段名字4":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

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

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

cpp 复制代码
华为云的MQTT服务器地址:117.78.5.125
华为云的MQTT端口号:1883

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

cpp 复制代码
ping  ad635970a1.st1.iotda-device.cn-north-4.myhuaweicloud.com

(2)生成MQTT三元组

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

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

下面是打开的页面:

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

直接得到三元组信息。

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

cpp 复制代码
ClientId  663cb18871d845632a0912e7_dev1_0_0_2024050911
Username  663cb18871d845632a0912e7_dev1
Password  71b82deae83e80f04c4269b5bbce3b2fc7c13f610948fe210ce18650909ac237

3.7 模拟设备登录测试

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

MQTT软件下载地址【免费】: https://download.csdn.net/download/xiaolong1126626497/89928772

(1)填入登录信息

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

(2)打开网页查看

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

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

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

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

cpp 复制代码
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":{"你的字段名字1":30,"你的字段名字2":10,"你的字段名字3":1,"你的字段名字4":0}}]}

3.8 创建IAM账户

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

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

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

项目凭证:

cpp 复制代码
28add376c01e4a61ac8b621c714bf459

【2】创建IAM用户

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

点击左上角创建用户

创建成功:

【3】创建完成

用户信息如下:

cpp 复制代码
主用户名  l19504562721
IAM用户  ds_abc
密码     DS12345678

3.9 获取影子数据

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

设备影子介绍:

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

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

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

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

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

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

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

cpp 复制代码
{
 "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写代码访问此链接,获取影子数据,完成上位机开发。

链接如下:

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

3.10 访问接口的代码实现

(1)配置 Qt 项目

在 Qt 项目的 .pro 文件中,加入对 libcurl 的支持:

pro 复制代码
QT += core
CONFIG += console
CONFIG -= app_bundle

INCLUDEPATH += /usr/include/curl  # 根据你的系统设置 libcurl 的路径
LIBS += -lcurl  # 链接 libcurl 库

SOURCES += main.cpp

(2)代码实现

main.cpp 文件中实现代码如下:

cpp 复制代码
#include <QCoreApplication>
#include <curl/curl.h>
#include <QDebug>
#include <QString>
#include <QByteArray>

// 回调函数,处理libcurl下载数据
size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t totalSize = size * nmemb;
    QByteArray *response = static_cast<QByteArray *>(userp);
    response->append(static_cast<char *>(contents), totalSize);
    return totalSize;
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 初始化libcurl
    CURL *curl;
    CURLcode res;
    QByteArray responseData;  // 用于存储响应数据

    curl_global_init(CURL_GLOBAL_DEFAULT);
    curl = curl_easy_init();
    if (curl) {
        // 设置访问URL
        const QString url = "https://ad635970a1.st1.iotda-app.cn-north-4.myhuaweicloud.com:443/v5/iot/28add376c01e4a61ac8b621c714bf459/devices/663cb18871d845632a0912e7_dev1/shadow";

        // 设置HTTP请求头
        struct curl_slist *headers = NULL;
        headers = curl_slist_append(headers, "Authorization: Bearer <Your_Access_Token>"); // 这里需要替换为你的实际 token

        curl_easy_setopt(curl, CURLOPT_URL, url.toStdString().c_str());
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseData);

        // 发起GET请求
        res = curl_easy_perform(curl);

        if (res != CURLE_OK) {
            qDebug() << "Curl request failed:" << curl_easy_strerror(res);
        } else {
            qDebug() << "Response data:" << responseData;
        }

        // 清理
        curl_easy_cleanup(curl);
        curl_slist_free_all(headers);
    }

    curl_global_cleanup();

    return a.exec();
}

3.11 数据解析代码

在 Qt 中使用 CJSON (一个用于解析 JSON 数据的轻量级 C 库) 来解析返回的 JSON 数据。

(1)配置 Qt 项目

在 Qt 项目的 .pro 文件中,确保包括了 CJSON 的头文件,并链接 CJSON 的源代码。

pro 复制代码
QT += core
CONFIG += console
CONFIG -= app_bundle

SOURCES += main.cpp \
           cJSON.c  # 将 cJSON.c 文件添加到你的项目中

INCLUDEPATH += path/to/cjson/  # 添加 CJSON 头文件的路径

LIBS += -lcurl  # 链接 libcurl 库

(2)解析 JSON 数据的完整代码

main.cpp 中,以下代码展示了如何解析你提供的 JSON 数据。

cpp 复制代码
#include <QCoreApplication>
#include <curl/curl.h>
#include <QDebug>
#include <QString>
#include <QByteArray>
#include "cJSON.h"

// 回调函数,处理libcurl下载数据
size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t totalSize = size * nmemb;
    QByteArray *response = static_cast<QByteArray *>(userp);
    response->append(static_cast<char *>(contents), totalSize);
    return totalSize;
}

// 解析 JSON 数据
void parseJson(const QByteArray &data) {
    // 将 QByteArray 转换为 char*
    const char* jsonData = data.constData();

    // 解析 JSON
    cJSON *root = cJSON_Parse(jsonData);
    if (root == NULL) {
        qDebug() << "Error parsing JSON.";
        return;
    }

    // 解析 "device_id"
    cJSON *deviceId = cJSON_GetObjectItemCaseSensitive(root, "device_id");
    if (cJSON_IsString(deviceId) && (deviceId->valuestring != NULL)) {
        qDebug() << "Device ID:" << deviceId->valuestring;
    }

    // 解析 "shadow" 数组
    cJSON *shadow = cJSON_GetObjectItemCaseSensitive(root, "shadow");
    if (cJSON_IsArray(shadow)) {
        cJSON *shadowItem = NULL;
        cJSON_ArrayForEach(shadowItem, shadow) {
            // 解析每个 shadow 项目
            cJSON *serviceId = cJSON_GetObjectItemCaseSensitive(shadowItem, "service_id");
            if (cJSON_IsString(serviceId) && (serviceId->valuestring != NULL)) {
                qDebug() << "Service ID:" << serviceId->valuestring;
            }

            // 解析 "reported" 对象
            cJSON *reported = cJSON_GetObjectItemCaseSensitive(shadowItem, "reported");
            if (cJSON_IsObject(reported)) {
                // 解析 "properties" 对象
                cJSON *properties = cJSON_GetObjectItemCaseSensitive(reported, "properties");
                if (cJSON_IsObject(properties)) {
                    cJSON *data1 = cJSON_GetObjectItemCaseSensitive(properties, "data1");
                    if (cJSON_IsNumber(data1)) {
                        qDebug() << "data1:" << data1->valueint;
                    }
                    cJSON *data2 = cJSON_GetObjectItemCaseSensitive(properties, "data2");
                    if (cJSON_IsNumber(data2)) {
                        qDebug() << "data2:" << data2->valueint;
                    }
                    cJSON *data3 = cJSON_GetObjectItemCaseSensitive(properties, "data3");
                    if (cJSON_IsNumber(data3)) {
                        qDebug() << "data3:" << data3->valueint;
                    }
                    cJSON *data4 = cJSON_GetObjectItemCaseSensitive(properties, "data4");
                    if (cJSON_IsNumber(data4)) {
                        qDebug() << "data4:" << data4->valueint;
                    }
                }

                // 解析 "event_time"
                cJSON *eventTime = cJSON_GetObjectItemCaseSensitive(reported, "event_time");
                if (cJSON_IsString(eventTime) && (eventTime->valuestring != NULL)) {
                    qDebug() << "Event Time:" << eventTime->valuestring;
                }
            }

            // 解析 version
            cJSON *version = cJSON_GetObjectItemCaseSensitive(shadowItem, "version");
            if (cJSON_IsNumber(version)) {
                qDebug() << "Version:" << version->valueint;
            }
        }
    }

    // 释放 JSON 对象
    cJSON_Delete(root);
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 模拟获取到的 JSON 数据
    QByteArray jsonData = R"(
    {
        "device_id": "663cb18871d845632a0912e7_dev1",
        "shadow": [
            {
                "service_id": "stm32",
                "desired": {
                    "properties": null,
                    "event_time": null
                },
                "reported": {
                    "properties": {
                        "data1": 18,
                        "data2": 90,
                        "data3": 38,
                        "data4": 70
                    },
                    "event_time": "20240509T113448Z"
                },
                "version": 3
            }
        ]
    })";

    // 调用解析函数
    parseJson(jsonData);

    return a.exec();
}

四、STM32设备端代码设计

以下是一个示例的 main.c 代码,将通过 4G 模块与华为云物联网平台进行通信,实现温湿度、震动、GPS 数据的采集与上传。

  • 使用 STM32F103RCT6 作为主控芯片。
  • 温湿度传感器使用 SHT30。
  • GPS 模块使用中科微 ATGM336H-GPS 模块。
  • 震动传感器是一个简单的数字输入传感器。
  • 4G 模块(Air724UG)通过 UART 进行通信。
  • 使用 MQTT 协议将数据上传至华为云物联网平台。

以下是 main.c 代码示例: 这是框架代码-伪代码。

c 复制代码
#include "stm32f1xx_hal.h"
#include "mqtt_client.h"
#include "sht30.h"
#include "gps.h"
#include "vibration_sensor.h"
#include "air724ug.h"
#include "wifi_module.h"

// 定义数据结构
typedef struct {
    float temperature;
    float humidity;
    char gps_latitude[20];
    char gps_longitude[20];
    char vibration_status[20];
} sensor_data_t;

// 全局变量
sensor_data_t current_data;
MQTT_Client mqtt_client;
UART_HandleTypeDef huart1;  // 4G模块的串口配置
UART_HandleTypeDef huart2;  // GPS模块的串口配置
I2C_HandleTypeDef hi2c1;    // SHT30温湿度传感器的I2C配置

// 定义函数原型
void SystemClock_Config(void);
void MX_GPIO_Init(void);
void MX_I2C1_Init(void);
void MX_UART1_Init(void);
void MX_UART2_Init(void);
void MX_WiFi_Init(void);
void MX_MQTT_Init(void);
void get_sensor_data(void);
void send_data_to_cloud(void);

// 主函数
int main(void)
{
    // 初始化硬件抽象层(HAL)
    HAL_Init();
    SystemClock_Config();

    // 初始化外设
    MX_GPIO_Init();
    MX_I2C1_Init();
    MX_UART1_Init();
    MX_UART2_Init();
    MX_WiFi_Init();
    MX_MQTT_Init();

    // 初始化传感器
    SHT30_Init(&hi2c1);
    GPS_Init(&huart2);
    Vibration_Sensor_Init();

    // 连接到WiFi
    WiFi_Connect();

    // MQTT连接到云平台
    if (MQTT_Connect(&mqtt_client) != MQTT_SUCCESS) {
        // 连接失败,进入错误处理流程
        while (1);
    }

    // 主循环
    while (1)
    {
        // 获取传感器数据
        get_sensor_data();

        // 将数据发送到云平台
        send_data_to_cloud();

    }
}

// 获取传感器数据
void get_sensor_data(void)
{
    // 获取温湿度数据
    if (SHT30_ReadData(&hi2c1, &current_data.temperature, &current_data.humidity) != HAL_OK) {
        // 如果读取失败,给默认值
        current_data.temperature = 25.0f;
        current_data.humidity = 50.0f;
    }

    // 获取GPS数据
    GPS_ReadData(&huart2, current_data.gps_latitude, current_data.gps_longitude);

    // 获取震动数据
    if (Vibration_Sensor_Read() == 1) {
        strcpy(current_data.vibration_status, "High");
    } else {
        strcpy(current_data.vibration_status, "Normal");
    }
}

// 发送数据到云平台
void send_data_to_cloud(void)
{
    // 构造上传的数据包
    char payload[256];
    sprintf(payload, "{\"temperature\":%.2f, \"humidity\":%.2f, \"vibration_status\":\"%s\", \"gps_latitude\":\"%s\", \"gps_longitude\":\"%s\"}",
            current_data.temperature, current_data.humidity, current_data.vibration_status, current_data.gps_latitude, current_data.gps_longitude);

    // 使用MQTT协议发送数据
    if (MQTT_Publish(&mqtt_client, "device/data", payload) != MQTT_SUCCESS) {
        // 发送失败,进行错误处理
    }
}

// 系统时钟配置
void SystemClock_Config(void)
{
    // 配置系统时钟为 72 MHz
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL9;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        // 如果配置失败,进入错误处理流程
        while (1);
    }

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | 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) {
        // 如果配置失败,进入错误处理流程
        while (1);
    }
}

// GPIO初始化
void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOH_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    // 在此处添加GPIO配置
}

// I2C1初始化
void MX_I2C1_Init(void)
{
    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 100000;
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c1.Init.OwnAddress1 = 0;
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
        // 初始化失败,进入错误处理流程
        while (1);
    }
}

// UART1初始化 (用于4G模块)
void MX_UART1_Init(void)
{
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    if (HAL_UART_Init(&huart1) != HAL_OK) {
        // 初始化失败,进入错误处理流程
        while (1);
    }
}

// UART2初始化 (用于GPS模块)
void MX_UART2_Init(void)
{
    huart2.Instance = USART2;
    huart2.Init.BaudRate = 9600;
    huart2.Init.WordLength = UART_WORDLENGTH_8B;
    huart2.Init.StopBits = UART_STOPBITS_1;
    huart2.Init.Parity = UART_PARITY_NONE;
    huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart2.Init.Mode = UART_MODE_TX_RX;
    if (HAL_UART_Init(&huart2) != HAL_OK) {
        // 初始化失败,进入错误处理流程
        while (1);
    }
}

// WiFi模块初始化
void MX_WiFi_Init(void)
{
  
}

// MQTT初始化
void MX_MQTT_Init(void)
{
    // 配置MQTT客户端
    mqtt_client.broker = "mqtt://broker.huawei.com";
    mqtt_client.port = 1883;
    mqtt_client.client_id = "device_client_id";
    mqtt_client.username = "device_username";
    mqtt_client.password = "device_password";
    mqtt_client.connect_timeout = 10;  // 超时时间
    mqtt_client.keep_alive_interval = 60; // 保持连接时间
    MQTT_Init(&mqtt_client);
}

代码说明:

初始化外设MX_I2C1_Init():初始化用于与 SHT30 温湿度传感器通信的 I2C 接口。

  • MX_UART1_Init()MX_UART2_Init():初始化 UART 接口,用于与 4G 模块和 GPS 模块通信。
  • MX_GPIO_Init():初始化 GPIO,配置其他硬件接口。
  • MX_WiFi_Init():初始化 WiFi 模块,连接到网络。
  • MX_MQTT_Init():初始化 MQTT 客户端,配置连接到云平台。

传感器数据获取get_sensor_data() 函数获取温湿度、GPS 坐标和震动状态数据。

数据上传send_data_to_cloud() 函数将传感器数据格式化为 JSON 格式,并通过 MQTT 协议上传到云平台。

MQTT通信:通过配置好的 MQTT 客户端与云平台进行通信,发送实时的传感器数据。

五、前端页面设计

这段代码是一个基于 HTML、CSS 和 JavaScript 的智慧大屏页面,用于展示疫苗冷链物流监测的数据。页面的设计目标是通过展示环境数据(如温度、湿度、震动)和 GPS 定位信息,实时监控运输过程中环境状况。

下面是静态页面,模拟数据刷新显示。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>智慧大屏 - 疫苗冷链物流监测</title>
    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
    <style>
        /* 设置全局字体和背景 */
        body {
            font-family: 'Roboto', sans-serif;
            background: linear-gradient(45deg, #121212, #1c1c1c); /* 深色渐变背景 */
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            overflow: hidden;
        }

        /* 中心容器 */
        .container {
            width: 100%;
            height: 100%;
            max-width: 1920px;  /* 限制最大宽度为 1920px */
            display: flex;
            justify-content: space-between;
            padding: 20px;
            box-sizing: border-box;
            flex-wrap: wrap;
        }

        /* 左侧卡片区域 */
        .left-panel {
            display: flex;
            flex-direction: column;
            width: 48%;
            justify-content: flex-start;
            gap: 20px;
        }

        /* 右侧地图区域 */
        .right-panel {
            width: 48%;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
        }

        /* 卡片样式 */
        .card {
            background-color: #232323;
            color: #fff;
            width: 100%;
            margin: 10px 0;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 0 15px rgba(0, 255, 255, 0.2);
            text-align: center;
            transition: transform 0.3s ease, box-shadow 0.3s ease;
            height: 220px;
        }

        .card:hover {
            transform: scale(1.05);
            box-shadow: 0 0 25px rgba(0, 255, 255, 0.4);
        }

        .card h3 {
            font-size: 26px;
            margin-bottom: 10px;
            color: #00FFFF; /* 科技蓝 */
        }

        .card p {
            font-size: 18px;
            margin-bottom: 20px;
            color: #ccc;
        }

        .card .value {
            font-size: 32px;
            font-weight: bold;
            color: #00FF99; /* 科技绿 */
        }

        /* GPS定位样式 */
        .gps-map {
            background-color: #232323;
            color: white;
            width: 100%;
            margin: 10px 0;
            padding: 20px;
            border-radius: 10px;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100%;
            position: relative;
            box-shadow: 0 0 15px rgba(0, 255, 255, 0.2);
        }

        .map-overlay {
            background: rgba(0, 0, 0, 0.7);
            position: absolute;
            width: 100%;
            height: 100%;
            top: 0;
            left: 0;
            text-align: center;
            padding: 50px;
            border-radius: 10px;
        }

        .gps-coordinates {
            font-size: 24px;
            font-weight: 600;
            position: absolute;
            bottom: 10px;
            width: 100%;
            color: #00FFFF;
        }

        /* 页眉样式 */
        .header {
            text-align: center;
            margin-bottom: 30px;
            width: 100%;
        }

        .header h1 {
            color: #00FFFF;
            font-size: 40px;
            margin-bottom: 20px;
        }

        .header p {
            color: #ddd;
            font-size: 18px;
        }

        /* 页脚样式 */
        .footer {
            text-align: center;
            margin-top: 20px;
            color: #aaa;
        }

        /* 控制页面响应式布局 */
        @media screen and (max-width: 768px) {
            .container {
                flex-direction: column;
                align-items: center;
            }

            .left-panel, .right-panel {
                width: 100%;
            }

            .card {
                width: 100%;
            }
        }

    </style>
</head>
<body>

    <div class="container">
        <div class="header">
            <h1>智慧大屏 - 疫苗冷链物流监测</h1>
            <p>实时监控运输过程中的环境数据,确保疫苗运输过程符合标准</p>
        </div>

        <div class="left-panel">
            <!-- 温湿度监控卡片 -->
            <div class="card" id="temp-card">
                <h3>环境温度</h3>
                <p>当前温度</p>
                <div class="value" id="temperature">23°C</div>
            </div>

            <div class="card" id="humidity-card">
                <h3>环境湿度</h3>
                <p>当前湿度</p>
                <div class="value" id="humidity">55%</div>
            </div>

            <div class="card" id="vibration-card">
                <h3>震动监测</h3>
                <p>当前震动强度</p>
                <div class="value" id="vibration">正常</div>
            </div>
        </div>

        <div class="right-panel">
            <!-- GPS定位卡片 -->
            <div class="gps-map">
                <div class="map-overlay">
                    <h3>车辆当前位置</h3>
                    <p>正在运输疫苗至目标地点</p>
                    <div class="gps-coordinates" id="gps-coordinates">经度: 116.38° | 纬度: 39.90°</div>
                </div>
            </div>
        </div>

        <div class="footer">
            <p>© 2024 疫苗冷链监控系统 - 所有权归公司所有</p>
        </div>
    </div>

    <script>
        // 模拟数据更新
        let temperatureElement = document.getElementById("temperature");
        let humidityElement = document.getElementById("humidity");
        let vibrationElement = document.getElementById("vibration");
        let gpsCoordinatesElement = document.getElementById("gps-coordinates");

        function updateData() {
            // 模拟温度变化
            let temperature = Math.random() * 10 + 20;
            temperatureElement.innerText = temperature.toFixed(1) + "°C";

            // 模拟湿度变化
            let humidity = Math.random() * 20 + 50;
            humidityElement.innerText = humidity.toFixed(1) + "%";

            // 模拟震动强度变化
            let vibrationLevels = ["正常", "轻微震动", "剧烈震动"];
            vibrationElement.innerText = vibrationLevels[Math.floor(Math.random() * vibrationLevels.length)];

            // 模拟GPS坐标变化
            let longitude = (Math.random() * 10 + 116).toFixed(2);
            let latitude = (Math.random() * 10 + 39).toFixed(2);
            gpsCoordinatesElement.innerText = `经度: ${longitude}° | 纬度: ${latitude}°`;
        }

        setInterval(updateData, 3000); // 每3秒更新一次数据

    </script>

</body>
</html>

以下是详细的功能说明:


1. HTML 结构

<div class="container">
  • 作用 :是页面的主要容器,内部包含了所有内容。使用 flex 布局将页面内容分为左右两个部分(左侧为环境数据卡片,右侧为 GPS 地图卡片)。
<div class="header">
  • 作用:页面顶部的标题区域,显示页面的标题 "智慧大屏 - 疫苗冷链物流监测" 以及副标题,简要描述该页面的功能。
<div class="left-panel">
  • 作用

    :该区域展示环境数据卡片,包含温度、湿度和震动数据,使用

    flex
    

    布局从上到下排列。

    • 温度卡片:显示当前温度。
    • 湿度卡片:显示当前湿度。
    • 震动卡片:显示当前震动监测状态。
<div class="right-panel">
  • 作用:该区域用于显示 GPS 定位地图,展示当前疫苗运输的经纬度信息。地图下方显示当前的 GPS 坐标(经度和纬度)。
<div class="footer">
  • 作用:页脚部分,提供版权信息或系统归属等简短说明。

2. CSS 样式

**全局样式 **body:
  • 设置了 background 为深色渐变背景,创造出科技感的氛围。
  • font-family 设置为 Roboto 字体,保证页面的简洁和现代感。
  • 使用 display: flexjustify-content: center 来使页面内容居中显示。
容器与布局

.container:

  • 设置了最大宽度 max-width: 1920px,确保页面宽度适应大多数显示器,保证在 1080p 屏幕分辨率下全屏显示。
  • flex-wrap: wrap 使得页面在小屏幕下可以自动换行,适应不同尺寸的设备。
左侧卡片样式

.left-panel:

  • 使用 flex-direction: column 使得环境数据卡片垂直排列。
  • 设置了 gap: 20px 来使卡片之间有一定的间距。
右侧地图样式

.right-panel:

  • 通过 flex-direction: column 保持地图区域的整体布局,确保右侧的地图区域与左侧数据区域并排显示。
  • position: relative 为了定位地图区域上的叠加内容(如 GPS 坐标)。
卡片样式

.card:

  • 设置了卡片的背景色、内边距、圆角和阴影,使其看起来更为现代化和有层次感。
  • transition 用于设置卡片的动画效果,卡片在鼠标悬停时会放大并且增加阴影,增强交互感。
  • 卡片内容的标题、数值和描述有不同的字体大小和颜色,增强信息的可读性和视觉层次感。
地图样式

.gps-map和 .map-overlay:

  • 地图区域使用 flex 居中显示地图内容,并使用半透明的 map-overlay 覆盖在地图上方,显示 GPS 坐标等信息。
响应式设计
  • 在小屏幕设备(如手机、平板)上,通过设置 @media screen and (max-width: 768px),容器变为竖向布局,左右区域都占满整个屏幕宽度。卡片和地图则会依次垂直排列,适配不同尺寸的设备。

3. JavaScript 动态数据更新

模拟数据更新

updateData() 函数:

  • 模拟实时更新环境数据和 GPS 坐标。
  • 温度:通过 Math.random() 随机生成 20°C 到 30°C 之间的温度值。
  • 湿度:随机生成 50% 到 70% 之间的湿度值。
  • 震动:从 ["正常", "轻微震动", "剧烈震动"] 随机选取一个震动状态。
  • GPS 坐标:模拟生成经度和纬度,范围在 116° 到 116.5° 之间,39° 到 39.5° 之间。
数据更新间隔

setInterval(updateData, 3000);

  • 每 3 秒钟调用一次 updateData 函数,动态更新温度、湿度、震动和 GPS 坐标,模拟实时监测数据。

总结

  1. 页面布局
    • 页面通过 flex 布局实现了左侧环境监测数据区域和右侧 GPS 地图区域的并排展示。
    • 使用响应式设计,确保页面能够自适应不同设备和屏幕分辨率,特别是在 1080p 屏幕分辨率下能够全屏显示。
  2. 动态数据展示
    • 使用 JavaScript 定时更新数据,模拟温湿度、震动监测和 GPS 坐标的实时变化。
  3. 科技感设计
    • 通过深色背景、渐变效果、现代化卡片样式和动态交互设计,提升了页面的科技感和现代感,适合展示智慧监控、物联网等科技类内容。
  4. 可扩展性
    • 页面结构和样式简单清晰,易于扩展和定制,未来可以加入更多的监控数据、功能和优化

六、总结

本项目设计并实现了一套基于物联网技术的疫苗冷链物流监测系统,保障疫苗在运输过程中的安全性和有效性。通过结合温度、湿度、震动等环境监测数据的实时采集与反馈,本系统能够及时发现并响应运输过程中可能出现的异常情况,如温湿度波动、剧烈震动等,从而采取相应的措施,例如开启制冷风机、加湿器或蜂鸣器警报,确保疫苗始终处于适宜的环境条件下。

在硬件选型方面,系统采用了STM32F103RCT6作为主控芯片,结合了SHT30温湿度传感器、GPS模块、震动传感器以及4G模块等多种外设,以实现多维度的数据采集和远程监控。4G模块与华为云物联网平台的结合,使得运输过程中的数据能够实时上传至云端,提供了更加可靠的数据存储与管理手段。

在软件部分,系统通过移动端APP和可视化网页平台进行数据展示和远程控制,用户可以随时查看运输环境的温湿度、震动状态和车辆位置,并获取历史数据进行分析。通过精准的GPS定位与实时数据更新,系统能够有效避免运输过程中可能出现的各类问题,确保疫苗冷链物流的稳定性和安全性。

通过本项目的实现,我们不仅增强了物联网在医疗物流领域中的应用,还为疫苗冷链运输提供了智能化、自动化的管理工具。未来,随着技术的发展和系统功能的不断完善,该系统将能够支持更复杂的监控需求,进一步提升疫苗运输过程中的安全性和效率,为全球疫苗供应链的稳定运行提供有力保障。

相关推荐
Anna_Tong5 小时前
HSM能为区块链、IoT等新兴技术提供怎样的保护?
物联网·区块链·iot·数据加密·hsm
云山工作室2 天前
基于物联网的智能环境监测系统(论文+源码)
物联网·毕业设计·毕设
7yewh2 天前
嵌入式知识点总结 Linux驱动 (三)-文件系统
linux·运维·驱动开发·stm32·嵌入式硬件·mcu·物联网
7yewh2 天前
嵌入式知识点总结 Linux驱动 (四)-中断-软硬中断-上下半部-中断响应
linux·驱动开发·stm32·嵌入式硬件·mcu·物联网·硬件工程
HMS工业网络2 天前
通过OPC UA或MQTT协议,安全地将工业设备连接至物联网软件
网络·物联网·安全
明达技术2 天前
网关与云平台携手打造全轮转胶印机远程物联网监控系统
物联网
华普微HOPERF3 天前
BLE透传方案,IoT短距无线通信的“中坚力量”
科技·物联网·射频工程
fly-iot4 天前
【fly-iot飞凡物联】(20):2025年总体规划,把物联网整套技术方案和实现并落地,完成项目开发和课程录制。
物联网
亿坊电商4 天前
可以称之为“yyds”的物联网开源框架有哪几个?
物联网·开源