本文分享自华为云社区《基于STM32+华为云IOT设计的物联网鱼缸【玩转华为云】》,作者: DS 小龙哥 。
1. 前言
为了缓解学习、生活、工作带来的压力,提升生活品质,许多人喜欢在家中、办公室等场所养鱼。为节省鱼友时间、劳力、增加养鱼乐趣;为此,本文基于 STM32 单片机设计了一款基于物联网的智能鱼缸。该鱼缸可以实现水温检测、水质检测、自动或手动换水、氛围灯灯光变换和自动或手动喂食等功能为一体的控制系统,鱼缸通过 ESP8266 连接华为云 IOT 物联网平台,并通过应用侧接口开发了上位机 APP 实现远程对鱼缸参数检测查看,并能远程控制。
从功能上分析,需要用到的硬件如下:
(1)STM32 系统板
(2)水温温度检测传感器: 测量水温
(3)水质检测传感器: 测量水中的溶解性固体含量,反应水质。
(4)步进电机: 作为鱼饲料投食器
(5)RGB 氛围灯: 采用 RGB 3 色灯,给鱼缸照明。
(6)抽水电动马达: 用来给鱼缸充氧,换水,加水等。
(7)ESP8266 WIFI:设置串口协议的 WIFI,内置了 TCP/IP 协议栈,完善的 AT 指令,通过简单的指令就可以联网通信,但是当前采用的 ESP8266 没有烧写第三方固件,采用原本的原滋原味的官方固件,没有内置 MQTT 协议,代码里连接华为云物联网平台需要使用 MQTT 协议,所以在 STM32 代码里通过 MQTT 协议文档的字段结构自己实现了 MQTT 协议,在通过 ESP8266 的 TCP 相关的 AT 指令完成数据发送接收,完成与华为云 IOT 平台交互。
水产养殖水质常规检测的传感器有哪些?水产养殖水质常规检测的传感器有水质 ph 传感器、溶解氧传感器和温度传感器。
(1)水质 ph 传感器:ph 传感器是高智能化在线连续监测仪,由传感器和二次表两部分组成。可配三复合或两复合电极,以满足各种使用场所。配上纯水和超纯水电极,可适用于电导率小于 3μs/cm 的水质(如化学补给水、饱和蒸气、凝结水等)的 pH 值测量。
(2)溶解氧传感器:氧气的消耗量与存在的氧含量成正比,而氧是通过可透膜扩散进来的。传感器与专门设计的监测溶氧的测量电路或电脑数据采集系统相连。 溶解氧传感器能够空气校准,一般校准所需时间较长,在使用后要注意保养。如果在养殖水中工作时间过长,就必须定期地清洗膜,对其进行额外保养。在很多水产养殖中,每天测几次溶氧就可以了解溶氧情况。对池塘和许多水槽养殖系统。溶氧水平不会变化很快,池塘一般每天检测 2~3 次。 对于较高密度养殖系统,增氧泵故障发生可能不到 1h 就会造成鱼虾等大面积死亡。这些密度高的养殖系统要求有足够多的装备或每小时多次自动测量溶氧。
(3)温度传感器:温度传感器有多种结构,包括热电偶、电阻温度传感器和热敏电阻。热电偶技术成熟,应用领域广,货源充足。选择热电偶必须满足温度范围要求,且其材料与环境相容。 电阻温度传感器(RTDs)的原理为金属的电阻随温度的改变而改变。大多电阻温度传感器(RTDs)由铂、镍或镍合金制成,其线性度比热电偶好,热切更加稳定,但容易破碎。 热敏电阻是电阻与温度具有负相关关系的半导体。热敏电阻比 RTD 和热电偶更灵敏,也更容易破碎,不能承受大的温差,但这一点在水产养殖中不成问题。
2. 硬件选型
2.1 STM32 开发板
主控 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 杜邦线
2.3 PCB 板
2.4 步进电机
2.5 抽水马达
2.6 水温检测传感器
测温采用 DS18B20,DS18B20 是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。
DS18B20 数字温度传感器接线方便,封装成后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式,型号多种多样,有 LTM8877,LTM8874 等等。
主要根据应用场合的不同而改变其外观。封装后的 DS18B20 可用于电缆沟测温,高炉水循环测温,锅炉测温,机房测温,农业大棚测温,洁净室测温,弹药库测温等各种非极限温度场合。耐磨耐碰,体积小,使用方便,封装形式多样,适用于各种狭小空间设备数字测温和控制领域。
2.7 水质检测传感器
TDS (Total Dissolved Solids)、中文名总溶解固体、又称溶解性固体、又称溶解性固体总量、表明 1 升水肿容有多少毫克溶解性固体、一般来说、TDS 值越高、表示水中含有溶解物越多、水就越不洁净、虽然在特定情况下 TDS 并不能有效反映水质的情况、但作为一种可快速检测的参数、TDS 目前还可以作为有效的在水质情况反映参数来作为参考。常用的 TDS 检测设备为 TDS 笔、虽然价格低廉、简单易用、但不能把数据传给控制系统、做长时间的在线监测、并做水质状况分析、使用专门的仪器、虽然能传数据、精度也高、但价格很贵、为此这款 TDS 传感器模块、即插即用、使用简单方便、测量用的激励源采用交流信号、可有效防止探头极化、延长探头寿命的同时、也增加了输出信号的稳定性、TDS 探头为防水探头、可长期侵入水中测量、该产品可以应用于生活用水、水培等领域的水质检测、有了这个传感器、可轻松 DIY–套 TDS 检测仪了、轻松检测水的洁净程度。
2.8 ESP8266
■模块采用串口(LVTTL) 与 MCU (或其他串口设备) 通信,内置 TCP/IP 协议栈,能够实现串口与 WIFI 之间的转换■模块支持 LVTTL 串口, 兼容 3…3V 和 5V 单片机系统■模块支持串 口转 WIFI STA、串口转 AP 和 WIFI STA+WIFI AP 的模式,从而快速构建串口-WIFI 数据传输方案■模块小巧(19mm*29mm), 通过 6 个 2.54mm 间距排针与外部连接
3. 华为云 IOT 产品与设备创建
3.1 创建产品
链接:https://www.huaweicloud.com/product/iothub.html
点击右上角窗口创建产品。
填入产品信息。
接下来创建模型文件:创建服务。
创建属性。根据鱼缸设备的传感器属性来添加属性。
(1)LED 氛围灯(2)抽水电机(3)水质传感器(4)水温温度计
3.2 创建设备
地址: https://console.huaweicloud.com/iotdm/?region=cn-north-4#/dm-portal/device/all-device
点击右上角创建设备。
按照设备的情况进行填写信息。
设备创建后保存信息:
{
"device_id": "62cd6da66b9813541d510f64_dev1",
"secret": "12345678"
}
复制代码
创建成功。
3.3 设备模拟调试
为了测试设备通信的过程,在设备页面点击调试。
选择设备调试:
3.4 MQTT 三元组
为了方便能够以真实的设备登陆服务器进行测试,接下来需要先了解 MQTT 协议登录需要的参数如何获取,得到这些参数才可以接着进行下一步。
MQTT(Message Queuing Telemetry Transport)是一个基于客户端-服务器的消息发布/订阅传输协议,主要应用于计算能力有限,且工作在低带宽、不可靠的网络的远程传感器和控制设备,适合长连接的场景,如智能路灯等。
MQTTS 是 MQTT 使用 TLS 加密的协议。采用 MQTTS 协议接入平台的设备,设备与物联网平台之间的通信过程,数据都是加密的,具有一定的安全性。
采用 MQTT 协议接入物联网平台的设备,设备与物联网平台之间的通信过程,数据没有加密,如果要保证数据的私密性可以使用 MQTTS 协议。
在这里可以使用华为云提供的工具快速得到 MQTT 三元组进行登录。https://support.huaweicloud.com/devg-iothub/iot_01_2127.html#ZH-CN_TOPIC_0240834853__zh-cn_topic_0251997880_li365284516112
工具的页面地址:https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/
根据提示填入信息,然后生成三元组信息即可。 这里填入的信息就是在创建设备的时候生成的信息。
DeviceId 62cd6da66b9813541d510f64_dev1
DeviceSecret 12345678
ClientId 62cd6da66b9813541d510f64_dev1_0_0_2022071609
Username 62cd6da66b9813541d510f64_dev1
Password a23fb6db6b5bc428971d5ccf64cc8f7767d15ca63bd5e6ac137ef75d175c77bf
复制代码
3.5 平台接入地址
华为云的物联网服务器地址在这里可以获取:https://console.huaweicloud.com/iotdm/?region=cn-north-4#/dm-portal/home
MQTT (1883) a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com
对应的IP地址是: 121.36.42.100
复制代码
3.6 MQTT 的主题订阅与发布格式
得到三元组之后,就可以登录 MQTT 服务器进行下一步的主题发布与订阅。
主题的格式详情:https://support.huaweicloud.com/api-iothub/iot_06_v5_3004.html
上传的数据格式详情:https://support.huaweicloud.com/devg-iothub/iot_01_2127.html#ZH-CN_TOPIC_0240834853__zh-cn_topic_0251997880_li365284516112
设备消息上报 $oc/devices/{device_id}/sys/messages/up
平台下发消息给设备 $oc/devices/{device_id}/sys/messages/down
上传的消息格式:
{
"services": [{
"service_id": "Connectivity",
"properties": {
"dailyActivityTime": 57
},
"event_time": "20151212T121212Z"
},
{
"service_id": "Battery",
"properties": {
"batteryLevel": 80
},
"event_time": "20151212T121212Z"
}
]
}
复制代码
根据当前设备的格式总结如下:
ClientId 62cd6da66b9813541d510f64_dev1_0_0_2022071609
Username 62cd6da66b9813541d510f64_dev1
Password a23fb6db6b5bc428971d5ccf64cc8f7767d15ca63bd5e6ac137ef75d175c77bf
//订阅主题: 平台下发消息给设备
$oc/devices/62cd6da66b9813541d510f64_dev1/sys/messages/down
//设备上报数据
$oc/devices/62cd6da66b9813541d510f64_dev1/sys/properties/report
//上报的属性消息 (一次可以上报多个属性,在json里增加就行了)
{"services": [{"service_id": "fish","properties":{"LED":1}},{"service_id": "fish","properties":{"motor":1}},{"service_id": "fish","properties":{"水温":36.2}}]}
复制代码
3.7 MQTT 客户端模拟设备调试
得到信息之后,将参赛填入软件进行登录测试。
数据发送之后,在设备页面上可以看到设备已经在线了,并且收到了上传的数据。
4. STM32 程序设计
4.1 硬件连线
硬件连接方式:
1. TFT 1.44 寸彩屏接线
GND 电源地
VCC 接5V或3.3v电源
SCL 接PC8(SCL)
SDA 接PC9(SDA)
RST 接PC10
DC 接PB7
CS 接PB8
BL 接PB11
2. 板载LED灯接线
LED1---PA8
LED2---PD2
3. 板载按键接线
K0---PA0
K1---PC5
K2---PA15
4. DS18B20温度传感器接线
DQ->PC6
+ : 3.3V
- : GND
5. 步进电机
ULN2003控制28BYJ-48步进电机接线:
ULN2003接线:
IN-D: PB15 d
IN-C: PB14 c
IN-B: PB13 b
IN-A: PB12 a
+ : 5V
- : GND
6. 抽水电机
GND---GND
VCC---5V
AO----PA4
7. 水质检测传感器
AO->PA1
+ : 3.3V
- : GND
8. RGB灯
PC13--R
PC14--G
PC15--B
9. ATK-ESP8266 WIFI接线
PA2(TX)--RXD 模块接收脚
PA3(RX)--TXD 模块发送脚
GND---GND 地
VCC---VCC 电源(3.3V~5.0V)
复制代码
4.2 硬件原理图
4.3 汉字取模
4.4 程序下载
下载软件在资料包里。点击开始编程之后,点击开发板的复位键即可下载程序进去。
4.5 主要的信息连接代码
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "usart.h"
#include <string.h>
#include "timer.h"
#include "esp8266.h"
#include "mqtt.h"
#include "oled.h"
#include "fontdata.h"
#include "bh1750.h"
#include "iic.h"
#include "sht3x.h"
#define ESP8266_WIFI_AP_SSID "aaa" //将要连接的路由器名称 --不要出现中文、空格等特殊字符
#define ESP8266_AP_PASSWORD "12345678" //将要连接的路由器密码
//华为云服务器的设备信息
#define MQTT_ClientID "62cd6da66b9813541d510f64_dev1_0_0_2022071609"
#define MQTT_UserName "62cd6da66b9813541d510f64_dev1"
#define MQTT_PassWord "a23fb6db6b5bc428971d5ccf64cc8f7767d15ca63bd5e6ac137ef75d175c77bf"
//订阅与发布的主题
#define SET_TOPIC "$oc/devices/62cd6da66b9813541d510f64_dev1/sys/messages/down" //订阅
#define POST_TOPIC "$oc/devices/62cd6da66b9813541d510f64_dev1/sys/properties/report" //发布
复制代码
4.6 ESP8266 主要代码
u8 ESP8266_IP_ADDR[16]; //255.255.255.255
u8 ESP8266_MAC_ADDR[18]; //硬件地址
/*
函数功能: ESP8266命令发送函数
函数返回值:0表示成功 1表示失败
*/
u8 ESP8266_SendCmd(char *cmd)
{
int RX_CNT=0;
u8 i,j;
for(i=0;i<10;i++) //检测的次数--发送指令的次数
{
USARTx_StringSend(USART3,cmd);
for(j=0;j<100;j++) //等待的时间
{
delay_ms(50);
if(USART3_RX_STA&0X8000)
{
RX_CNT=USART3_RX_STA&0x7FFF;
USART3_RX_BUF[RX_CNT]='\0';
USART3_RX_STA=0;
if(strstr((char*)USART3_RX_BUF,"OK"))
{
return 0;
}
}
}
}
return 1;
}
/*
函数功能: ESP8266硬件初始化检测函数
函数返回值:0表示成功 1表示失败
*/
u8 ESP8266_Init(void)
{
//退出透传模式
USARTx_StringSend(USART3,"+++");
delay_ms(100);
//退出透传模式
USARTx_StringSend(USART3,"+++");
delay_ms(100);
return ESP8266_SendCmd("AT\r\n");
}
/*
函数功能: 一键配置WIFI为AP+TCP服务器模式
函数参数:
char *ssid 创建的热点名称
char *pass 创建的热点密码 (最少8位)
u16 port 创建的服务器端口号
函数返回值: 0表示成功 其他值表示对应错误值
*/
u8 ESP8266_AP_TCP_Server_Mode(char *ssid,char *pass,u16 port)
{
char *p;
u8 i;
char ESP8266_SendCMD[100]; //组合发送过程中的命令
/*1. 测试硬件*/
if(ESP8266_SendCmd("AT\r\n"))return 1;
/*2. 关闭回显*/
if(ESP8266_SendCmd("ATE0\r\n"))return 2;
/*3. 设置WIFI模式*/
if(ESP8266_SendCmd("AT+CWMODE=2\r\n"))return 3;
/*4. 复位*/
ESP8266_SendCmd("AT+RST\r\n");
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
/*5. 关闭回显*/
if(ESP8266_SendCmd("ATE0\r\n"))return 5;
/*6. 设置WIFI的AP模式参数*/
sprintf(ESP8266_SendCMD,"AT+CWSAP=\"%s\",\"%s\",1,4\r\n",ssid,pass);
if(ESP8266_SendCmd(ESP8266_SendCMD))return 6;
/*7. 开启多连接*/
if(ESP8266_SendCmd("AT+CIPMUX=1\r\n"))return 7;
/*8. 设置服务器端口号*/
sprintf(ESP8266_SendCMD,"AT+CIPSERVER=1,%d\r\n",port);
if(ESP8266_SendCmd(ESP8266_SendCMD))return 8;
/*9. 查询本地IP地址*/
if(ESP8266_SendCmd("AT+CIFSR\r\n"))return 9;
//提取IP地址
p=strstr((char*)USART3_RX_BUF,"APIP");
if(p)
{
p+=6;
for(i=0;*p!='"';i++)
{
ESP8266_IP_ADDR[i]=*p++;
}
ESP8266_IP_ADDR[i]='\0';
}
//提取MAC地址
p=strstr((char*)USART3_RX_BUF,"APMAC");
if(p)
{
p+=7;
for(i=0;*p!='"';i++)
{
ESP8266_MAC_ADDR[i]=*p++;
}
ESP8266_MAC_ADDR[i]='\0';
}
//打印总体信息
printf("当前WIFI模式:AP+TCP服务器\r\n");
printf("当前WIFI热点名称:%s\r\n",ssid);
printf("当前WIFI热点密码:%s\r\n",pass);
printf("当前TCP服务器端口号:%d\r\n",port);
printf("当前TCP服务器IP地址:%s\r\n",ESP8266_IP_ADDR);
printf("当前TCP服务器MAC地址:%s\r\n",ESP8266_MAC_ADDR);
return 0;
}
/*
函数功能: TCP服务器模式下的发送函数
发送指令:
*/
u8 ESP8266_ServerSendData(u8 id,u8 *data,u16 len)
{
int RX_CNT=0;
u8 i,j,n;
char ESP8266_SendCMD[100]; //组合发送过程中的命令
for(i=0;i<10;i++)
{
sprintf(ESP8266_SendCMD,"AT+CIPSEND=%d,%d\r\n",id,len);
USARTx_StringSend(USART3,ESP8266_SendCMD);
for(j=0;j<10;j++)
{
delay_ms(50);
if(USART3_RX_STA&0X8000)
{
RX_CNT=USART3_RX_STA&0x7FFF;
USART3_RX_BUF[RX_CNT]='\0';
USART3_RX_STA=0;
if(strstr((char*)USART3_RX_BUF,">"))
{
//继续发送数据
USARTx_DataSend(USART3,data,len);
//等待数据发送成功
for(n=0;n<200;n++)
{
delay_ms(50);
if(USART3_RX_STA&0X8000)
{
RX_CNT=USART3_RX_STA&0x7FFF;
USART3_RX_BUF[RX_CNT]='\0';
USART3_RX_STA=0;
if(strstr((char*)USART3_RX_BUF,"SEND OK"))
{
return 0;
}
}
}
}
}
}
}
return 1;
}
/*
函数功能: 配置WIFI为STA模式+TCP客户端模式
函数参数:
char *ssid 创建的热点名称
char *pass 创建的热点密码 (最少8位)
char *p 将要连接的服务器IP地址
u16 port 将要连接的服务器端口号
u8 flag 1表示开启透传模式 0表示关闭透传模式
函数返回值:0表示成功 其他值表示对应的错误
*/
u8 ESP8266_STA_TCP_Client_Mode(char *ssid,char *pass,char *ip,u16 port,u8 flag)
{
char ESP8266_SendCMD[100]; //组合发送过程中的命令
//退出透传模式
//USARTx_StringSend(USART3,"+++");
//delay_ms(50);
/*1. 测试硬件*/
if(ESP8266_SendCmd("AT\r\n"))return 1;
/*2. 关闭回显*/
if(ESP8266_SendCmd("ATE0\r\n"))return 2;
/*3. 设置WIFI模式*/
if(ESP8266_SendCmd("AT+CWMODE=1\r\n"))return 3;
/*4. 复位*/
ESP8266_SendCmd("AT+RST\r\n");
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
/*5. 关闭回显*/
if(ESP8266_SendCmd("ATE0\r\n"))return 5;
/*6. 配置将要连接的WIFI热点信息*/
sprintf(ESP8266_SendCMD,"AT+CWJAP=\"%s\",\"%s\"\r\n",ssid,pass);
if(ESP8266_SendCmd(ESP8266_SendCMD))return 6;
/*7. 设置单连接*/
if(ESP8266_SendCmd("AT+CIPMUX=0\r\n"))return 7;
/*8. 配置要连接的TCP服务器信息*/
sprintf(ESP8266_SendCMD,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",ip,port);
if(ESP8266_SendCmd(ESP8266_SendCMD))return 8;
/*9. 开启透传模式*/
if(flag)
{
if(ESP8266_SendCmd("AT+CIPMODE=1\r\n"))return 9; //开启
if(ESP8266_SendCmd("AT+CIPSEND\r\n"))return 10; //开始透传
if(!(strstr((char*)USART3_RX_BUF,">")))
{
return 11;
}
//如果想要退出发送: "+++"
}
printf("WIFI模式:STA+TCP客户端\r\n");
printf("Connect_WIFI热点名称:%s\r\n",ssid);
printf("Connect_WIFI热点密码:%s\r\n",pass);
printf("TCP服务器端口号:%d\r\n",port);
printf("TCP服务器IP地址:%s\r\n",ip);
return 0;
}
/*
函数功能: TCP客户端模式下的发送函数
发送指令:
*/
u8 ESP8266_ClientSendData(u8 *data,u16 len)
{
int RX_CNT=0;
u8 i,j,n;
char ESP8266_SendCMD[100]; //组合发送过程中的命令
for(i=0;i<10;i++)
{
sprintf(ESP8266_SendCMD,"AT+CIPSEND=%d\r\n",len);
USARTx_StringSend(USART3,ESP8266_SendCMD);
for(j=0;j<10;j++)
{
delay_ms(50);
if(USART3_RX_STA&0X8000)
{
RX_CNT=USART3_RX_STA&0x7FFF;
USART3_RX_BUF[RX_CNT]='\0';
USART3_RX_STA=0;
if(strstr((char*)USART3_RX_BUF,">"))
{
//继续发送数据
USARTx_DataSend(USART3,data,len);
//等待数据发送成功
for(n=0;n<200;n++)
{
delay_ms(50);
if(USART3_RX_STA&0X8000)
{
RX_CNT=USART3_RX_STA&0x7FFF;
USART3_RX_BUF[RX_CNT]='\0';
USART3_RX_STA=0;
if(strstr((char*)USART3_RX_BUF,"SEND OK"))
{
return 0;
}
}
}
}
}
}
}
return 1;
}
复制代码
点击关注,第一时间了解华为云新鲜技术~
评论