基于STM32+NBIOT(BC26)设计的物联网观赏鱼缸

文章目录

一、前言

1.1 项目介绍

【1】开发背景

随着智能家居与物联网技术的迅速发展,人们对于生活品质的追求日益提升,家庭宠物养护也逐渐智能化、精细化。观赏鱼作为广受欢迎的宠物之一,其饲养环境的维护成为了众多养鱼爱好者的关注焦点。传统的观赏鱼缸管理依赖人工监测与调节,不仅费时费力,还难以实现精准控制,尤其是在快节奏的现代生活中,忙碌的主人常常难以及时发现并处理水质恶化、水温异常等问题,这直接影响到鱼类的健康与观赏性。

本项目通过集成先进的传感技术和远程控制功能,为观赏鱼提供一个稳定、健康的生态环境,同时让养鱼爱好者能够便捷地监控和管理鱼缸状态。

该项目的核心在于利用高性能的STM32F103RCT6微控制器作为主控单元,结合多种高精度传感器(包括浑浊度、温度、光敏及氨气传感器)实时监测水质、水温和光照条件,实现对鱼缸环境的全方位监控。通过智能化算法判断各项指标是否处于适宜范围,并据此自动调整增氧泵、加热设备及照明系统的运行,保证鱼缸环境的最优化。

项目采用了BC26 NBIOT模块,借助低功耗广域网技术,将鱼缸的实时数据上传至腾讯云IoT物联网平台。这一设计使得用户可以通过定制的微信小程序远程监控鱼缸状态,随时随地查看水质、水温、光照强度等关键参数,并根据需要远程调控设备工作模式与参数设定,如调整增氧泵的工作周期、设定水温阈值等,真正实现了观赏鱼缸管理的智能化与远程化。

本项目的开发满足现代家庭及商业场所对高效、智能宠物养护的需求,通过技术创新推动宠物养护方式的变革,提升养鱼体验。

【2】项目实现的功能

(1)水质监测与警示:通过搭载的水质浑浊度传感器,系统能够实时监测鱼缸中的水质情况。一旦检测到水质浑浊度超过预设的最大安全值,系统将自动触发LED灯显示红色,提示用户需要更换或净化水质。若水质良好,则LED灯呈现绿色,给予安心指示。

(2)智能温控系统:集成的防水式DS18B20温度传感器持续监控水温变化。当水温降至预设的最低温度限制以下时,系统自动激活加热棒,维持鱼缸内水温恒定,确保鱼类生活在适宜的温度环境中。

(3)光照自动调节:光敏传感器BH1750监测环境光线强度,当自然光线不足,低于设定阈值时,系统自动开启内置的LED照明系统,为鱼缸内的生物提供必要的光照,促进其健康成长并增强观赏效果。

(4)氨气监测与环境优化:MQ137氨气传感器负责监测鱼缸内的氨气浓度,氨气是影响鱼类健康的主要有害物质之一。一旦检测到氨气超标,系统同样会亮起红色警示灯,提示用户需要采取措施改善硝化环境,保持水质清洁。

(5)自动增氧功能:系统支持用户通过微信小程序设定增氧泵的开启时间间隔,确保鱼缸内氧气充足,维持良好的水体含氧量,促进鱼类活跃度和生长。

(6)远程监控与控制:所有监测数据(水质、水温、光照强度)通过NBIOT模块实时传输至腾讯云IoT平台,用户可通过专属的微信小程序远程查看这些数据,实时了解鱼缸环境状态,并能远程调整各项设备的工作参数,如调整水温设定值、增氧泵工作计划等,实现远程智能管理。

(7)灵活的控制模式:微信小程序提供多种控制模式,包括自动模式、手动模式等,用户可根据实际情况自由切换,既可享受全自动化管理带来的便利,也能在需要时手动介入调整。

【3】项目模块组成

(1)主控模块

  • 核心MCU:采用STM32F103RCT6微控制器,作为整个系统的控制中心,负责处理传感器数据、执行逻辑判断、控制外围设备等工作。
  • 电源管理:5V 2A外部稳压电源为整个系统供电,主控板上集成电源管理模块,确保各部分电路的稳定供电。

(2)传感器模块

  • 水质浑浊度传感器:模拟量输出,用于实时检测水质状况。
  • 防水式温度传感器(DS18B20):精确测量水温,支持单总线通信协议。
  • 光敏传感器(BH1750):检测环境光照强度,为自动调节灯光提供依据。
  • 氨气传感器(MQ137):监测鱼缸内氨气浓度,保障鱼类健康。

(2)执行器模块

  • RGB LED灯:根据水质、氨气检测结果改变颜色,红绿灯直观显示当前鱼缸状态。
  • 继电器控制模块:用于控制增氧泵、加热棒等设备的通断电,实现自动化操作。

(3)通信模块

  • NBIOT模块(BC26):通过NBIOT网络将鱼缸的实时监测数据上传至腾讯云IoT平台,实现远程数据交互。

(4)用户交互模块

  • 微信小程序:用户界面层,提供远程监控界面,展示水质、水温、光照等实时数据,支持远程控制增氧泵开启时间、调整水温阈值等设置,以及控制模式的切换。

(5)云服务与数据分析模块

  • 腾讯云IoT平台:接收并存储来自鱼缸的数据,提供数据分析、报警通知等功能,支撑微信小程序的数据展示与指令下发。

1.2 设计思路

(1)感知层

  • 硬件传感器:包括水质浑浊度传感器、DS18B20温度传感器、MQ137氨气传感器、BH1750光敏传感器等,负责实时收集鱼缸环境的物理参数。
  • 数据采集:各传感器通过模拟/数字信号输出,由STM32F103RCT6微控制器读取并初步处理,转换为可处理的数据格式。

(2)控制层

  • 主控制器:STM32F103RCT6作为核心处理器,根据感知层传来的数据,执行预设的逻辑判断和控制算法,决定各执行器的下一步动作。
  • 执行器控制:通过继电器模块控制增氧泵、加热棒和RGB LED灯的开关,实现对鱼缸环境的自动调节。

(3)通信层

  • NBIOT通信:BC26模块将控制层处理后的数据通过NBIOT网络发送至云端,实现远程数据传输。
  • 数据封装与协议:数据在传输前经过加密处理,并按照NBIOT通信协议封装,确保数据的安全与高效传输。

(4)云服务层

  • 腾讯云IoT平台:接收并处理从鱼缸设备传来的数据,提供数据存储、分析、报警服务。
  • API接口:为微信小程序提供数据接口,实现数据的双向交互,即数据上传与指令下达。

(5)应用层

  • 微信小程序:用户界面,展示鱼缸的实时状态信息(水质、水温、光强等),提供远程控制界面,允许用户设置参数(如温度阈值、增氧泵工作周期)、切换控制模式等。
  • 用户交互与反馈:用户通过小程序与系统互动,系统根据用户指令调整鱼缸管理策略,同时向用户推送重要通知或报警信息。

二、(硬件控制端)硬件选型

2.1 STM32开发板

链接:https://detail.tmall.com/item.htm?id=540109077095\&skuId=4456080806080\&spm=a1z0d.6639537.1997196601.4.69157484Ospeps

主控CPU采用STM32F103RCT6,这颗芯片包括48 KB SRAM、256 KB Flash、2个基本定时器、4个通用定时器、2个高级定时器、51个通用IO口、5个串口、2个DMA控制器、3个SPI、2个I2C、1个USB、1个CAN、3个12位ADC、1个12位DAC、1个SDIO接口,芯片属于大容量类型,配置较高,整体符合硬件选型设计。当前选择的这款开发板自带了一个1.4寸的TFT-LCD彩屏,可以显示当前传感器数据以及一些运行状态信息。

2.2 PCB板

链接:https://detail.tmall.com/item.htm?spm=a230r.1.14.34.16b221829wBwAI\&id=525489414251\&ns=1\&abbucket=9\&skuId=3929211749440

2.3 USB下载线

链接:https://detail.tmall.com/item.htm?areaId=500100\&cat_id=2\&id=36635861113\&is_b=1\&rn=b29713f11d07002439272415bce5c7e1\&skuId=3762719825529\&spm=a220m.1000858.1000725.31.46e677b4qLTl6B\&user_id=1695056989

2.4 NBIOT模块

链接:https://item.taobao.com/item.htm?abbucket=3\&id=583282366803\&ns=1\&skuId=4749833023376\&spm=a21n57.1.item.3.1ed9523cnUBQwb

2.5 杜邦线(2排)

链接:https://detail.tmall.com/item.htm?ali_refid=a3_430582_1006:1104520036:N:MsF9mE9KLTC2IibWJh K1A==:0395c662ef512f1b59b31b906608d3\&id=14466195609\&skuId=3108214440215

2.6 稳压模块

链接:https://item.taobao.com/item.htm?spm=a21n57.1.0.0.2921523cQeodt2\&id=16606969730\&ns=1\&abbucket=7#detail

2.7 电源插头

链接:https://item.taobao.com/item.htm?id=616513772095\&price=12.5-28\&sourceType=item\&sourceType=item\&suid=28568653-f37a-44d9-ba7f-79370acc2a9e\&ut_sk=1.Y%2BSje8BXEHwDAAzffoCNOQAM_21646297_1700218130362.TaoPassword-WeiXin.ShareGlobalNavigation_1\&un=6f62cf65130082c7143b731291a8a715\&share_crt_v=1\&un_site=0\&spm=a2159r.13376460.0.0\&sp_abtk=gray_ShareGlobalNavigation_1_code_simpleAndroid2\&sp_tk=cTJPQVczdDRwNFI%3D\&cpp=1\&shareurl=true\&short_name=h.5kwQOCl\&bxsign=scd4p22mFtBbwnGM_SWdgwgZ27RN8IEynH4PqvQihq_j_z9InPF1g10n1NbTKmLx8KZRz6HVuBpo_O9axHjCBbsVlVvTKl9u7l4CGsrBWq6-xf26Zvx5y-ND4YT_gNAlrvG\&tk=q2OAW3t4p4R\&app=chrome

2.8 水温检测传感器

链接:https://item.taobao.com/item.htm?spm=a230r.1.14.16.e600187bHLivKO\&id=637832887998\&ns=1\&abbucket=10#detail

测温采用DS18B20,DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。

DS18B20数字温度传感器接线方便,封装成后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式,型号多种多样,有LTM8877,LTM8874等等。

主要根据应用场合的不同而改变其外观。封装后的DS18B20可用于电缆沟测温,高炉水循环测温,锅炉测温,机房测温,农业大棚测温,洁净室测温,弹药库测温等各种非极限温度场合。耐磨耐碰,体积小,使用方便,封装形式多样,适用于各种狭小空间设备数字测温和控制领域。

2.9 水质检测传感器

链接:https://detail.tmall.com/item.htm?spm=a230r.1.14.59.2c30381do91idH\&id=656324337911\&ns=1\&abbucket=14

TDS (Total Dissolved Solids)、中文名总溶解固体、又称溶解性固体、又称溶解性固体总量、表明1升水肿容有多少毫克溶解性固体、一般来说、TDS值越高、表示水中含有溶解物越多、水就越不洁净、虽然在特定情况下TDS并不能有效反映水质的情况、但作为一种可快速检测的参数、TDS目前还可以作为有效的在水质情况反映参数来作为参考。常用的TDS检测设备为TDS笔、虽然价格低廉、简单易用、但不能把数据传给控制系统、做长时间的在线监测、并做水质状况分析、使用专门的仪器、虽然能传数据、精度也高、但价格很贵、为此这款TDS传感器模块、即插即用、使用简单方便、测量用的激励源采用交流信号、可有效防止探头极化、延长探头寿命的同时、也增加了输出信号的稳定性、TDS探头为防水探头、可长期侵入水中测量、该产品可以应用于生活用水、水培等领域的水质检测、有了这个传感器、可轻松DIY--套TDS检测仪了、轻松检测水的洁净程度。

2.10 继电器(3个)

用来控制鱼缸加热。

链接:https://detail.tmall.com/item.htm?id=15909056050\&ali_refid=a3_430582_1006:1104520036:N:sGzbt9RI84M4qtD4oBlF3Q==:94221238ccf10c5aeb7c31df1a993981\&ali_trackid=1_94221238ccf10c5aeb7c31df1a993981\&spm=a230r.1.14.1\&skuId=3931798090624

2.11 增氧泵

链接:https://item.taobao.com/item.htm?id=613985790640\&ali_refid=a3_430582_1006:1226360064:N:2BeiTZ6q9YYxgXM%2BVERvrA%2FFUJg%2FXa1Y:1cfd93a70ad4f25752bf8ced2f95c95f\&ali_trackid=1_1cfd93a70ad4f25752bf8ced2f95c95f\&spm=a230r.1.14.1#detail

2.12 鱼缸加热棒

链接:https://item.taobao.com/item.htm?spm=a230r.1.14.45.2bc91fca135EYb\&id=645146758133\&ns=1\&abbucket=10#detail

2.13 多色灯

链接:https://item.taobao.com/item.htm?spm=a230r.1.14.16.3711441eUUO7Vh\&id=612186142933\&ns=1\&abbucket=10#detail

2.14 BH1750光敏传感器

链接:https://detail.tmall.com/item.htm?abbucket=3\&id=543135220776\&ns=1\&spm=a230r.1.14.16.d7597d40XRn0Ec

2.15 MQ135空气质量传感器

链接:https://detail.tmall.com/item.htm?abbucket=5\&id=17949567819\&ns=1\&skuId=4078848750998\&spm=a21n57.1.0.0.242b523cwrRqcB

三、腾讯云平台与微信小程序设计

3.1 登录云平台

地址:https://cloud.tencent.com/

【1】选择物联网平台

微信扫描即可快速登录,然后选择产品,物联网,选择物联网开发平台。

【2】进入产品控制台

链接: https://console.cloud.tencent.com/iotexplorer

第一次进去需要实名认证,认证成功就可以进去了。

3.2 新建项目

【1】新建项目

【2】填写项目名称

【3】项目创建完成

3.3 产品开发

【1】进入产品页

点击项目名称,进入产品开发页面。

【2】新建产品

【3】填写产品信息

产品品类选择自定义产品品类

【4】产品创建完成

3.4 设备开发

【1】进入设备配置页

点击产品名称,进入设备配置页面。

【2】配置物模型

选择自定义品类。

cpp 复制代码
上传腾讯云-微信小程序通信数据的属性值:
ds18b20_max  温度阀值   读写权限  整型
adc_hp_max   水质阀值   读写权限  整型
time_food    增氧间隔   读写权限  整型
auto_mode    控制模式   读写权限  布尔类型
water_hp     水质       只读权限  整型
temp_data    水温		只读权限  浮点数类型
BH1750       光强		只读权限  整型
MQ135        氨气  		只读权限  整型
oxygen_sw    增氧控制   读写权限  布尔类型
heat_sw      加热控制   读写权限  布尔类型
led_sw       照明灯控制 读写权限  布尔类型
(1)进行添加

下面就继续添加(按照),前面的流程。

(2)添加完成

然后翻到最下面,点击下一步。

【3】设备开发-主题列表

设备开发页面有一个主题列表。可以了解到当前的主题信息。

当前项目需要用到的就是下面的两个主题。

cpp 复制代码
$thing/up/property/2ZYN8YF7CM/${deviceName}	   发布	属性上报
$thing/up/property/2ZYN8YF7CM/${deviceName}	订阅	属性下发与属性上报响应

这个页面不需要做什么,直接点击下一步即可。

【4】交互开发-配置小程序

(1)产品展示页

设置信息: 根据自己设备情况自己设置即可。

(2)快捷入口配置

根据需要配置。

(3)编辑面板

根据自己的样式进行调整。

可以根据自己喜欢的图标进行设置。

(4)产品页面

【5】设备调试-新建设备

创建完成。

设备的二维码: (打开微信小程序,搜索 腾讯连连,打开腾讯连连,扫描下面的二维码就可以绑定设备了---这个是有有效时间范围的,过期了需要登录重新获取二维码)

设备信息:

cpp 复制代码
产品密匙:WCk1aGDvGyg34+KolnKMqw==
产品ID:2ZYN8YF7CM

下面也有MQTT三元组的信息。

【6】配置手机APP

如果除了小程序之外,还想使用手机APP,可以配置手机APP页面。

配置步骤和上面的微信程序一样。

3.5 设备登录

【1】MQTT协议

MQTT协议介绍:https://mcxiaoke.gitbooks.io/mqtt-cn/content/mqtt/01-Introduction.html

cpp 复制代码
目前物联网通信支持 MQTT 标准协议接入(兼容3.1.1版本协议),具体的协议请参见 MQTT 3.1.1 协议文档。
和标准 MQTT 区别

1. 支持 MQTT 的 PUB、SUB、PING、PONG、CONNECT、DISCONNECT、UNSUB 等报文。
2. 支持 cleanSession。
3. 不支持 will、retain msg。
4. 不支持 QOS2。

【2】获取MQTT登录参数

就像我们登录QQ、登录微信需要账号密码一样,设备登录物联网平台也需要类似的东西。

官方文档地址: https://cloud.tencent.com/document/product/634/32546

生成密匙直接使用python代码获取:

cpp 复制代码
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import base64
import hashlib
import hmac
import random
import string
import time
import sys
# 生成指定长度的随机字符串
def RandomConnid(length):
    return  ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(length))
# 生成接入物联网通信平台需要的各参数
def IotHmac(productID, devicename, devicePsk):
     # 1. 生成 connid 为一个随机字符串,方便后台定位问题
     connid   = RandomConnid(5)
     # 2. 生成过期时间,表示签名的过期时间,从纪元1970年1月1日 00:00:00 UTC 时间至今秒数的 UTF8 字符串
     #  将当前时间往后推迟5年
     expiry   = int(time.time()) + 5 * 365 * 24 * 60 * 60
     # 3. 生成 MQTT 的 clientid 部分, 格式为 ${productid}${devicename}
     clientid = "{}{}".format(productID, devicename)
     # 4. 生成 MQTT 的 username 部分, 格式为 ${clientid};${sdkappid};${connid};${expiry}
     username = "{};12010126;{};{}".format(clientid, connid, expiry)
     # 5. 对 username 进行签名,生成token
     secret_key = devicePsk.encode('utf-8')  # convert to bytes
     data_to_sign = username.encode('utf-8')  # convert to bytes
     secret_key = base64.b64decode(secret_key)  # this is still bytes
     token = hmac.new(secret_key, data_to_sign, digestmod=hashlib.sha256).hexdigest()
     # 6. 根据物联网通信平台规则生成 password 字段
     password = "{};{}".format(token, "hmacsha256")
     return {
        "clientid" : clientid,
        "username" : username,
        "password" : password
     }
if __name__ == '__main__':
    # 参数分别填入: 产品ID,设备名称,设备密匙
    print(IotHmac("2ZYN8YF7CM","dev1","WCk1aGDvGyg34+KolnKMqw=="))
	

上面python的代码需要填入的参数从下面截图里获取:

运行得到的结果:

安装Python,设置好环境变量,打开控制台终端,在命令行上运行代码:python get_pass.py

得到一下结果。

cpp 复制代码
{'clientid': '2ZYN8YF7CMdev1', 'username': '2ZYN8YF7CMdev1;12010126;HULWJ;1705853339', 'password': '26725d9cf937e3d054cc51fa91338d81ddebc072ae1fa65c564a068d8bb3e0c7;hmacsha256'}

总结:

复制代码
clientid: 2ZYN8YF7CMdev1
username: 2ZYN8YF7CMdev1;12010126;HULWJ;1705853339
password: 26725d9cf937e3d054cc51fa91338d81ddebc072ae1fa65c564a068d8bb3e0c7;hmacsha256

【3】MQTT主题订阅与发布

如果设备端想要得到APP页面的按钮状态就需要订阅属性下发和属性上报的响应,主题格式就是这样的:

主题订阅:

cpp 复制代码
$thing/up/property/2ZYN8YF7CM/dev1

主题发布:

cpp 复制代码
$thing/down/property/2ZYN8YF7CM/dev1

设备端向APP页面上报属性时,需要上传具体的数据,数据流的格式如下:

官方文档: https://cloud.tencent.com/document/product/1081/34916

上传的格式就是自己创建产品时,添加的功能属性。

按下面的JSON格式进行组合:

cpp 复制代码
{"method":"report","clientToken":"123","params":{"ds18b20_max":20,"adc_hp_max":20,"time_food":5,"auto_mode":1,"water_hp":80,"temp_data":12.5,"BH1750":300,"MQ135":20,"oxygen_sw":1,"heat_sw":0,"led_sw":0}}

【4】物联网平台端口号与IP

官方文档: https://cloud.tencent.com/document/product/634/32546

域名格式:<产品ID>.iotcloud.tencentdevices.com

cpp 复制代码
2ZYN8YF7CM.iotcloud.tencentdevices.com

**得到域名对应的IP地址: ** 175.178.30.200

【5】模拟设备登录

为了方便测试,先使用MQTT客户端软件模拟硬件设备登录服务器。

cpp 复制代码
IP地址:175.178.30.200
端口号:1883
客户端ID: 2ZYN8YF7CMdev1
用户名: 2ZYN8YF7CMdev1;12010126;HULWJ;1705853339
密码:  26725d9cf937e3d054cc51fa91338d81ddebc072ae1fa65c564a068d8bb3e0c7;hmacsha256
订阅主题: $thing/down/property/2ZYN8YF7CM/dev1
发布主题: $thing/up/property/2ZYN8YF7CM/dev1
发布数据格式:
{"method":"report","clientToken":"123","params":{"ds18b20_max":20,"adc_hp_max":20,"time_food":5,"auto_mode":1,"water_hp":80,"temp_data":12.5,"BH1750":300,"MQ135":20,"oxygen_sw":1,"heat_sw":0,"led_sw":0}}

依次填入参数之后,点击订阅主题、发布主题。

发布主题之后,会收到服务器下发的回应消息,表示消息已经上传成功。

在设备调试页面,可以看到设备已经在线了:

打开设备页面,就能看到设备上传的数据:

还能看历史数据: 可以看最近3天的数据。

【6】腾讯连连微信小程序

打开腾讯连连微信小程序绑定设备,就可以看到设备的数据了。

步骤如下:

打开微信,找到小程序。

右上角搜索,腾讯连接。

然后打开腾讯连连,添加设备,扫描设备的二维码。

打开设备二维码页面。

添加成功。 点击左下角关注公众号,可以第一时间收到设备的动态消息。

到此,腾讯物联网云平台部署完成。

【7】下发的数据

点击微信小程序里面的按钮可以看到设备端收到对应的控制信息。

cpp 复制代码
len:129,Data:$$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530389322mbXir::5NMCGSjgp","params":{"ds18b20_max":21}}
len:125,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530388538MKtZG::67Y#YRmFN","params":{"time_food":6}}
len:128,Data:$$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530389322sDtoc::EnQpzyukd","params":{"adc_hp_max":22}}
len:125,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530388538PaAHn::@KgWjdE1V","params":{"auto_mode":0}}
len:125,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530388538XYQqA::WsGV4K0uo","params":{"auto_mode":1}}
len:127,Data:$$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2529763559fdKIy::addUie4XDm","params":{"oxygen_sw":0}}
len:125,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2529763559OmPZY::vkCb-o5o%","params":{"oxygen_sw":1}}
len:124,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2529763559GCZHF::o3Zg6m9sEq","params":{"heat_sw":1}}
len:123,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530389322DuDjB::CgY5$Gx8Z","params":{"heat_sw":0}}
len:123,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2529763559opcLp::MdJWtA8ai7","params":{"led_sw":1}}
len:122,Data:$thing/down/property/2ZYN8YF7CM/dev1{"method":"control","clientToken":"v2530389322SZvJM::GYX7QT$T#","params":{"led_sw":0}}

四、STM32设备端代码设计

4.1 硬件接线

cpp 复制代码
硬件连接方式:

【1】 TFT 1.44 寸彩屏接线
GND   电源地
VCC   接5V或3.3v电源
SCL   接PC8(SCL)
SDA   接PC9(SDA)
RST   接PC10
DC    接PB7
CS    接PB8
BL	  接PB11

【2】BC26-NBIOT模块
PA2(TX)--RXD 模块接收脚
PA3(RX)--TXD 模块发送脚
GND---GND 地
VCC---VCC 电源(5.0V)

【3】DS18B20温度传感器
VCC--VCC
GND---GND
DAT---PB3 

【4】鱼缸加热棒--继电器控制
GND----GND
VCC---3.3V
OUT---PB4

【5】增氧泵--继电器控制
GND----GND
VCC---3.3V
OUT---PC11

【6】水质传感器(ADC通道1)
VCC--->5V
GND--->GND
DAT--->PA1

【7】氨气采集传感器(ADC通道4)
VCC--->5V
GND--->GND
DAT--->PA4


【8】板载LED灯接线
LED1---PA8
LED2---PD2 (被串口占用)


【9】板载按键接线
K0---PA0 
K1---PC5 
K2---PA15

【10】LED指示灯
LED1--PA5  红色灯--表示报警异常
LED2--PA6  绿色灯--表示系统正常
LED3--PA7  白色灯--照明


【11】环境光检测检测:BH1750数字传感器
SDA-----PB5
SCL-----PB6
GND---GND 地
VCC---VCC 电源(3.3V~5.0V)

4.2 串口配置代码

cpp 复制代码
#include "hal_uart.h"
#include "stm32f0xx_usart.h"

//接收串口数据的回调函数
static void (*halUartOnIRQ)(unsigned char byte) = 0;

static void halUartGpioInit(void);
static void halUartParamInit(unsigned long baudrate);
static void halUartIRQInit(void);

/*
 * 串口通信初始化
 *
 * @param baudrate - 串口通信波特率
 */
void halUartInit(unsigned long baudrate)
{
    halUartGpioInit();

    halUartParamInit(baudrate);

    halUartIRQInit();
}

/*
 * 注册接收串口数据的回调函数
 *
 * @param onIRQ - 回调函数,接收到串口数据时自动调用此函数
 */
void halUartSetIRQCallback(void (*onIRQ)(unsigned char byte))
{
    halUartOnIRQ = onIRQ;
}

/*
 * 向串口发送信息
 *
 * @param buf - 待发送的信息的存储地址
 * @param len - 待发送的信息的数据长度
 */
void halUartWrite(const unsigned char *buf, unsigned int len)
{
    for (unsigned int i = 0; i < len; i++) {
        USART_SendData(USART1, buf[i]);
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    }
}

/*
 * 初始化串口通信相关的GPIO
 */
void halUartGpioInit()
{
	  //配置结构体
    GPIO_InitTypeDef uart1Tx;
    GPIO_InitTypeDef uart1Rx;

    /* TX */
    uart1Tx.GPIO_Pin = GPIO_Pin_9,//PA9作为TX
    uart1Tx.GPIO_Speed = GPIO_Speed_10MHz,//通信频率
    uart1Tx.GPIO_Mode = GPIO_Mode_AF,
    uart1Tx.GPIO_PuPd = GPIO_PuPd_NOPULL,

    /* RX */
    uart1Rx.GPIO_Pin = GPIO_Pin_10,//PA10作为RX
    uart1Rx.GPIO_Speed = GPIO_Speed_10MHz,//通信频率
    uart1Rx.GPIO_Mode = GPIO_Mode_AF,
    uart1Rx.GPIO_PuPd = GPIO_PuPd_NOPULL,

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
	  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);

    GPIO_Init(GPIOA, &uart1Tx);
    GPIO_Init(GPIOA, &uart1Rx);
}

/*
 * 初始化串口通信配置
 * @param baudrate - 串口通信波特率
 */
void halUartParamInit(unsigned long baudrate)
{
    USART_InitTypeDef uartConfig;

    uartConfig.USART_BaudRate = baudrate;
    uartConfig.USART_WordLength = USART_WordLength_8b;
    uartConfig.USART_Parity = USART_Parity_No;
    uartConfig.USART_StopBits = USART_StopBits_1;
    uartConfig.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    uartConfig.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    USART_Init(USART1, &uartConfig);
    USART_Cmd(USART1, ENABLE);
}

/* 
 * 初始化串口通信的中断请求
 */
void halUartIRQInit()
{
    NVIC_InitTypeDef uartNVIC;

    uartNVIC.NVIC_IRQChannel = USART1_IRQn;
    uartNVIC.NVIC_IRQChannelPriority = 0;
    uartNVIC.NVIC_IRQChannelCmd = ENABLE;

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	  USART_ITConfig(USART1, USART_IT_TC, ENABLE);

    NVIC_Init(&uartNVIC);
}

/*
* 串口通信中断处理函数。当串口接收到数据时,便会自动产生中断并执行此函数
*/
void USART1_IRQHandler(void)
{
	unsigned char byte = 0;

	if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        byte = USART_ReceiveData(USART1); // Auto to clear RXNE flag when read!

        if (halUartOnIRQ != 0) halUartOnIRQ(byte);
    }
	else USART_ClearFlag(USART1,USART_FLAG_TC);
}

4.3 adc采集配置代码

cpp 复制代码
#include "hal_adc.h"

#include "stm32f0xx_adc.h"

/*
* ADC初始化
*/
void halAdcInit()
{
    GPIO_InitTypeDef gpioCfg;
    ADC_InitTypeDef adcCfg;

    /* PA0 */
    gpioCfg.GPIO_Pin  = GPIO_Pin_1;
    gpioCfg.GPIO_Mode = GPIO_Mode_AN;
    gpioCfg.GPIO_PuPd = GPIO_PuPd_NOPULL;

    ADC_StructInit(&adcCfg);
    adcCfg.ADC_Resolution = ADC_Resolution_8b;
    adcCfg.ADC_ContinuousConvMode = DISABLE;
    adcCfg.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    adcCfg.ADC_DataAlign = ADC_DataAlign_Right;
    adcCfg.ADC_ScanDirection = ADC_ScanDirection_Backward;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

    RCC_ADCCLKConfig(RCC_ADCCLK_PCLK_Div4);

    ADC_DeInit(ADC1);

    GPIO_Init(GPIOA, &gpioCfg);

    ADC_Init(ADC1, &adcCfg);

    /* Convert the ADC1 Vref  with 55.5 Cycles as sampling time */
    ADC_ChannelConfig(ADC1, ADC_Channel_1, ADC_SampleTime_55_5Cycles);

    ADC_GetCalibrationFactor(ADC1);
    ADC_DMACmd(ADC1, ENABLE);

    ADC_Cmd(ADC1, ENABLE);

    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN));

    ADC_StartOfConversion(ADC1);
}

/*
 *读取ADC值
 *
 *@return ADC值
 */
unsigned int halAdcRead()
{
    ADC_StartOfConversion(ADC1);

    while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);

    return ADC_GetConversionValue(ADC1);
}

4.4 LCD显示屏配置代码

cpp 复制代码
#include "hal_oled12864.h"
#include "font_v_8x16.h"
#include "hal_lcd_spi.h"

#include "hal_system.h"

#include "stm32f0xx_gpio.h"

typedef unsigned char uint8;
typedef unsigned short uint16;

static void halOLED12864Reset(void);
static void halOLED12864ChipInit(void);
static void halOLED12864SetPosition(uint8 page, uint8 x);

static void halOLEDShowChar8x16(uint16 x, uint16 page, uint8 ch);

void halOLED12864Init(void)
{    
    /* Init SPI-GPIO */
    halLcdSpiInit();

    /* Init Chip */
    halOLED12864ChipInit();

    /* Setting */
    halOLED12864ClearScreen();
    halOLED12864SetPosition(0,0);
}

void halOLED12864ClearScreen(void)
{
    uint8 page, x;
    
    for (page = 0; page < HAL_OLED12864_PAGE; page++) {
        halLcdSpiTxCmd(0xb0 + page);
        halLcdSpiTxCmd(0x01);
        halLcdSpiTxCmd(0x10);
        
        for (x = 0; x < HAL_OLED12864_X; x++) halLcdSpiTxData(0);
    }
}

void halOLED12864ShowX16(uint8 line, uint8 column, const uint8 *str)
{
    if (!str || line > 3) return;
    
    uint8 page = line * 2;    // 2 page per line
    const uint8 *ptext = str; // text
    
    /* Show text */
    while(*ptext != 0) {
        /* ASCII Code: 0~127 */
        if((*ptext) < 128) {
            /* End of line */
            if((column + 8) > HAL_OLED12864_X) return;
          
            /* Show 8x16 ASCII Char. */
            halOLEDShowChar8x16(column, page, *ptext);
            column += 8;
            
            ptext++;
        }
    } /* while(*ptext != 0) */
}

static void halOLED12864Reset(void)
{
#ifdef STM32F030x8
    /* RST: PA12 */
    GPIO_InitTypeDef  lcdGPIO;

    lcdGPIO.GPIO_Mode = GPIO_Mode_OUT;
    lcdGPIO.GPIO_Speed = GPIO_Speed_2MHz;
    lcdGPIO.GPIO_Pin = GPIO_Pin_12;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    GPIO_Init(GPIOA, &lcdGPIO);

    /* Reset OLED12864 */
    GPIO_ResetBits(GPIOA, GPIO_Pin_12);

    halSystemDelayUs(60000);

    GPIO_SetBits(GPIOA, GPIO_Pin_12);
#else
    /* RST: PA3 */
    GPIO_InitTypeDef  lcdGPIO;

    lcdGPIO.GPIO_Mode = GPIO_Mode_OUT;
    lcdGPIO.GPIO_Speed = GPIO_Speed_2MHz;
    lcdGPIO.GPIO_Pin = GPIO_Pin_3;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    GPIO_Init(GPIOA, &lcdGPIO);
    
    /* Reset OLED12864 */
    GPIO_ResetBits(GPIOA, GPIO_Pin_3);

    halSystemDelayUs(60000);

    GPIO_SetBits(GPIOA, GPIO_Pin_3);
#endif
}

static void halOLED12864ChipInit(void)
{
    halOLED12864Reset();
  
    halLcdSpiTxCmd(0xae);  // --turn off oled panel
    halLcdSpiTxCmd(0x00);  // ---set low column address
    halLcdSpiTxCmd(0x10);  // ---set high column address
    halLcdSpiTxCmd(0x40);  // --set start line address  Set Mapping  
                                    //   RAM Display Start Line (0x00~0x3F)
    halLcdSpiTxCmd(0x81);  // --set contrast control register
    halLcdSpiTxCmd(0xcf);  // --Set SEG Output Current Brightness
    halLcdSpiTxCmd(0xa1);  // --Set SEG/Column Mapping     
    halLcdSpiTxCmd(0xc8);  // --Set COM/Row Scan Direction  
    halLcdSpiTxCmd(0xa6);  // --set normal display
    halLcdSpiTxCmd(0xa8);  // --set multiplex ratio(1 to 64)
    halLcdSpiTxCmd(0x3f);  // --1/64 duty
    halLcdSpiTxCmd(0xd3);  // --set display offset Shift Mapping RAM 
                                    //   Counter(0x00~0x3F)
    halLcdSpiTxCmd(0x00);  // --not offset
    halLcdSpiTxCmd(0xd5);  // --set display clock divide
                                    //   ratio/oscillator oscillator frequency
    halLcdSpiTxCmd(0x80);  // --set divide ratio, Set Clock as 100 
                                    //   Frames/Sec
    halLcdSpiTxCmd(0xd9);  // --set pre-charge period
    halLcdSpiTxCmd(0xf1);  // --Set Pre-Charge as 15 Clocks & Discharge 
                                    //   as 1 Clock
    halLcdSpiTxCmd(0xda);  // --set com pins hardware configuration
    halLcdSpiTxCmd(0x12);
    halLcdSpiTxCmd(0xdb);  // --set vcomh
    halLcdSpiTxCmd(0x40);  // --Set VCOM Deselect Level
    halLcdSpiTxCmd(0x20);  // --Set Page Addressing Mode (0x00/0x01/0x02)
    halLcdSpiTxCmd(0x02);  //
    halLcdSpiTxCmd(0x8d);  // --set Charge Pump enable/disable
    halLcdSpiTxCmd(0x14);  // --set(0x10) disable
    halLcdSpiTxCmd(0xa4);  // --Disable Entire Display On (0xa4/0xa5)
    halLcdSpiTxCmd(0xa6);  // --Disable Inverse Display On (0xa6/a7) 
    halLcdSpiTxCmd(0xaf);  // --turn on oled panel
}

static void halOLED12864SetPosition(uint8 page, uint8 x)
{
    halLcdSpiTxCmd( 0xb0 + page );
    halLcdSpiTxCmd( ((x&0xf0)>>4)|0x10 );
    halLcdSpiTxCmd( (x&0x0f)|0x01 ); 
}

static void halOLEDShowChar8x16(uint16 x, uint16 page, uint8 ch)
{
    uint16 charIndex;
    
    /* index of font table, height: 16 */
    if(ch > 32) charIndex = (ch - 32) * 16;
    else charIndex = 0;
    
    /* Set first page */
    halOLED12864SetPosition(page, x);
    for (uint8 j = 0; j < 8; j++)  halLcdSpiTxData( FONT_TABLE_8x16[charIndex + j] );
    
    /* Set second page */
    halOLED12864SetPosition(page + 1, x);
    for (uint8 j = 0; j < 8; j++) halLcdSpiTxData( FONT_TABLE_8x16[charIndex + j + 8] );
}

五、 BC26-NBIOT模块调试过程

5.1 模块调试接线

5.2 测试模块

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

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

5.3 上电初始化操作

cpp 复制代码
【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天线接好,否则也是没有信号的。

官方文档:

cpp 复制代码
【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

5.5 连接MQTT服务器

下面通过BC26模块的AT指令连接MQTT服务器(OneNet),上传数据测试。

官方文档:

相关推荐
国科安芯6 小时前
航天器多路并联大功率电源系统设计与ASP4644均流特性分析
单片机·嵌入式硬件·fpga开发·安全性测试
茯苓gao8 小时前
嵌入式开发笔记:CANopen相关移位运算与通信协议术语详解
网络·嵌入式硬件·学习·信息与通信
梁朝辉11 小时前
STM32H750VBT6中ADCINP与INN什么区别
stm32·单片机·嵌入式硬件
省四收割者12 小时前
一文详解信号完整性(1)
python·嵌入式硬件·数学建模·信息与通信·信号处理·智能硬件
崇山峻岭之间13 小时前
单片机无感FOC驱动之ADC
单片机·嵌入式硬件
Ligocious13 小时前
1.点亮一颗小小的LED
单片机·嵌入式硬件
KaifuZeng17 小时前
通信与接口协议面试八、CAN通信
单片机·嵌入式硬件·面试·通信与接口协议
智源单片机设计18 小时前
基于单片机的直流电机双闭环调速系统设计
单片机·嵌入式硬件
kebidaixu18 小时前
两轮车换电 BMS 的模拟前端中颖 SH367306 AFE 芯片详解
stm32
kebidaixu19 小时前
两轮车换电 BMS 的模拟前端中颖 SH367306 AFE 芯片调试实录:四个关键问题与解决方案
stm32