写点什么

基于 STM32+ 华为云 IOT 设计的智能路灯

作者:DS小龙哥
  • 2022 年 7 月 06 日
  • 本文字数:5014 字

    阅读完需:约 16 分钟

1. 前言

随着工业和城市的快速发展,道路照明系统的产业也在迅速发展,并趋于复杂化,为了更经济地控制和维护复杂的路灯系统,市面上各大科技公司开发了各种路灯控制系统,并且路灯都连上物联网云端,连上了政府网络,可以远程了解路灯的工作情况,运行情况。为了方便了解物联网平台,学习物联网开发,了解智慧路灯的开发,本文就采用华为云 IOT 物联网平台,选择 STM32 作为主控芯片,再配合相关的传感器完成智慧路灯开发。

2. 具体实现的功能以及相关的硬件

当前设计的智慧路灯采用 NBIOT 模块-BC20 连接华为云物联网服务器,上传路灯的各种参数信息:环境光强度、太阳能充电板电压、锂电池电量等信息。设计了一款手机 APP,可以通过华为云物联网平台的应用侧提供的开发接口,获取路灯上传的参数信息,并且可以在手机 APP 上远程手动控制路灯开关,设置路灯的开启和关闭时间等。 智慧路灯的的主控芯片采用 STM32F103C8T6、NBIOT 联网模块采用 BC20,BC20 内置了 MQTT 协议,可以通过 AT 指令连接物联网平台实现通信。智慧路灯采用锂电池供电,并且配有太阳能充电板,可以使用太阳进行充电补偿电量。使用了功率监控器,电池电量检测芯片,可以检测充电效率、电流、电压、电池电量等信息。BC20 带了 GPS 功能,可以上报路灯的 GPS 位置到云端服务器,手机 APP 获取之后,可以调用百度地图显示出路灯的位置。







3. 硬件选型

3.1 STM32F103C8T6


3.2 太阳能板

3.3 锂电池充电模块

3.4 功率检测模块

3.5 BH1750 光敏传感器

3.6 LED 灯

3.7 BC20-NBIOT 模块

型号: BC20+BD+GPS品牌: 创思产地: 中国大陆接口类型: TTL适用场景: NBIOT尺寸: 40x40x12mm工作电流: 0.5A支持TCP/IP协议: 支持传输速率: 115200Kbps工作电压: 5V是否支持语音电话: 否模块类型: 其他是否支持短信: 否支持制式标准: GSM/GPRS(2G)是否支持电话簿: 否
复制代码


4. 创建产品与设备

4.1 创建产品

地址:https://www.huaweicloud.com/?locale=zh-cn





4.2 自定义模型

地址: https://console.huaweicloud.com/iotdm/?region=cn-north-4#/dm-dev/all-product/7211833377cf435c8c0580de390eedbe/product-detail/6276134223aaf461a0f6e515










4.3 创建设备



{    "device_id": "6276134223aaf461a0f6e515_1126626497",    "secret": "12345678"}
复制代码

4.4 MQTT 密匙生成

创建完产品、设备之后,接下来就需要知道如何通过 MQTT 协议登陆华为云服务器。官方的详细介绍在这里:https://support.huaweicloud.com/devg-iothub/iot_01_2127.html#ZH-CN_TOPIC_0240834853__zh-cn_topic_0251997880_li365284516112


属性上报格式:https://support.huaweicloud.com/api-iothub/iot_06_v5_3010.html




MQTT 设备登陆密匙生成地址: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/




DeviceId        6276134223aaf461a0f6e515_1126626497DeviceSecret   12345678ClientId      6276134223aaf461a0f6e515_1126626497_0_0_2022050706Username      6276134223aaf461a0f6e515_1126626497Password      73ebe0779dbd5b2e2fd3db8ab8f642b78d7a532576f2e14d2799d4f78d37bcc8
复制代码


华为云物联网平台的域名是: 161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com华为云物联网平台的 IP 地址是:121.36.42.100在软件里参数填充正确之后,就看到设备已经连接成功了。接下来打开设备页面,可以看到设备已经在线了。



4.5 主题订阅与发布

//订阅主题: 平台下发消息给设备$oc/devices/6276134223aaf461a0f6e515_1126626497/sys/messages/down//设备上报数据$oc/devices/6276134223aaf461a0f6e515_1126626497/sys/properties/report//上报的属性消息 (一次可以上报多个属性,在json里增加就行了){"services": [{"service_id": "led","properties":{"GPS":"lat:12.345,lng:45.678"}}]}
复制代码


通过 MQTT 客户端软件模拟上报测试:



4.6 应用侧开发

为了更方便的展示设备数据,与设备完成交互,还需要开发一个配套的上位机,官方提供了应用侧开发的 API 接口、SDK 接口,为了方便通用一点,我这里采用了 API 接口完成数据交互,上位机软件采用 QT 开发。


帮助文档地址: ttps://support.huaweicloud.com/api-iothub/iot_06_v5_0034.html


设备属性就是设备上传的传感器状态数据信息,应用侧提供了 API 接口,可以主动向设备端下发请求指令;设备端收到指令之后需要按照约定的数据格式上报数据;所以,要实现应用层与设备端的数据交互,需要应用层与设备端配合才能完成。



5. STM32 程序设计

STM32 连接华为云 IOT 的工程案例: https://download.csdn.net/download/xiaolong1126626497/81993720


5.1 BC20 连接华为云物联网服务器-调试


连接MQTT服务器AT+QMTOPEN=0,"a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com",1883
OK
+QMTOPEN: 0,0

登录MQTT服务器命令格式: AT+QMTCONN=<tcpconnectID>,<clientID>,<username>,<password>AT+QMTCONN=0,"6210e8acde9933029be8facf_dev1_0_0_2022021913","6210e8acde9933029be8facf_dev1","6cea55404b463e666cd7a6060daba745bbaa17fe7078dfef45f8151cdf19673d"
OK
+QMTCONN: 0,0,0

订阅主题命令格式: AT+QMTSUB=<tcpconnectID>,<msgID>,"<topic1>”,<qos1>[,"<topic2>”,<qos2>…]
AT+QMTSUB=0,1,"$oc/devices/6210e8acde9933029be8facf_dev1/sys/messages/down",2
OK
+QMTSUB: 0,1,0,2

发布主题命令格式:AT+QMTPUB=<tcpconnectID>,<msgID>,<qos>,<retain>,"<topic>","<msg>"
先发送指令: AT+QMTPUB=0,0,0,0,"$oc/devices/6210e8acde9933029be8facf_dev1/sys/properties/repor"
等待返回 ">" 接着发送数据.不需要加回车。"{"services": [{"service_id": "gps","properties":{"longitude":12.345,"latitude":33.345}}]}"数据发送完毕,再发送结束符。 十六进制的值--0x1a 。某些串口调试助手可以适应ctrl+z 快捷键输入0xA等待模块返回"OK",到此数据发送完成。 OK
+QMTPUB: 0,0,0
复制代码

5.2 测试模块

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


查询模块是否正常AT
OK

获取卡号,查询卡是否插好AT+CIMI
460041052911195
OK

激活网络AT+CGATT=1
OK

获取网络激活状态AT+CGATT?
+CGATT: 1
OK

查询网络质量AT+CSQ
+CSQ: 26,0
OK AT+CEREG=? //检查网络状态+CEREG: 0,1 //找网成功OK
复制代码

5.3 keil 工程代码

MQTT 协议连接华为云 IOT 源码工程: https://download.csdn.net/download/xiaolong1126626497/81993720




5.4 功率检测

#include "INA226.h"#include "delay.h"//  接线说明://  模拟IIC://IIC_SCL -- 时钟线PB6(推挽、开漏输出)//IIC_SDA -- 双向数据线PB7INA226 ina226_data;//初始化INA226void INA226_Init(void){  
IIC_Init(); INA226_SendData(INA226_ADDR1,CFG_REG,0x8000); //重新启动 INA226_SendData(INA226_ADDR1,CFG_REG,0x484f); //设置转换时间204us,求平均值次数128,采样时间为204*128,设置模式为分流和总线连续模式 INA226_SendData(INA226_ADDR1,CAL_REG,CAL); //设置分辨率 //INA226_SendData(INA226_ADDR1,CAL_REG,0x0012);//设置分流电压转电流转换参数 INA226_Get_ID(INA226_ADDR1); //获取ina226的id}
//设置寄存器指针void INA226_SetRegPointer(u8 addr,u8 reg){ IIC_Start();
IIC_Send_Byte(addr); IIC_Wait_Ack();
IIC_Send_Byte(reg); IIC_Wait_Ack();
IIC_Stop();}
//发送,写入数据void INA226_SendData(u8 addr,u8 reg,u16 data){ u8 temp=0; IIC_Start();
IIC_Send_Byte(addr); IIC_Wait_Ack();
IIC_Send_Byte(reg); IIC_Wait_Ack(); temp = (u8)(data>>8); IIC_Send_Byte(temp); IIC_Wait_Ack();
temp = (u8)(data&0x00FF); IIC_Send_Byte(temp); IIC_Wait_Ack(); IIC_Stop();}
//读取数据u16 INA226_ReadData(u8 addr){ u16 temp=0; IIC_Start();
IIC_Send_Byte(addr+1); IIC_Wait_Ack(); temp = IIC_Read_Byte(1); temp<<=8; temp |= IIC_Read_Byte(0); IIC_Stop(); return temp;}//1mA/bitu16 INA226_GetShunt_Current(u8 addr){ u16 temp=0; INA226_SetRegPointer(addr,CUR_REG); temp = INA226_ReadData(addr); if(temp&0x8000) temp = ~(temp - 1); return temp;}
//获取idvoid INA226_Get_ID(u8 addr){ u32 temp=0; INA226_SetRegPointer(addr,INA226_GET_ADDR); temp = INA226_ReadData(addr); ina226_data.ina226_id = temp;}
//获取校准值u16 INA226_GET_CAL_REG(u8 addr){ u32 temp=0; INA226_SetRegPointer(addr,CAL_REG); temp = INA226_ReadData(addr); return (u16)temp;}
//1.25mV/bitu16 INA226_GetVoltage(u8 addr){ u32 temp = 0; INA226_SetRegPointer(addr,BV_REG); temp = INA226_ReadData(addr); return (u16)temp; }
//2.5uV/bitu16 INA226_GetShuntVoltage(u8 addr){ int16_t temp = 0; INA226_SetRegPointer(addr,SV_REG); temp = INA226_ReadData(addr); if(temp&0x8000) temp = ~(temp - 1); return (u16)temp; }
//获取电压void GetVoltage(float *Voltage)//mV{ *Voltage = INA226_GetVoltage(INA226_ADDR1)*Voltage_LSB;}
//获取分流电压void Get_Shunt_voltage(float *Voltage)//uV{ *Voltage = (INA226_GetShuntVoltage(INA226_ADDR1)*INA226_VAL_LSB);//如需矫正电流分流参数请将这里改为2.5}
//获取电流void Get_Shunt_Current(float *Current)//mA{ *Current = (INA226_GetShunt_Current(INA226_ADDR1)* CURRENT_LSB);}
//获取功率= 总线电压 * 电流void get_power()//W{ GetVoltage(&ina226_data.voltageVal); //mV Get_Shunt_voltage(&ina226_data.Shunt_voltage); //uV Get_Shunt_Current(&ina226_data.Shunt_Current); //mA Get_Power(&ina226_data.Power); ina226_data.Power_Val = ina226_data.voltageVal*0.001f * ina226_data.Shunt_Current*0.001f; //mV*mA}
//获取功率装载值,ina226内部计算的的功率,由于未经校准,故不采用
u16 INA226_Get_Power(u8 addr){ int16_t temp=0; INA226_SetRegPointer(addr,PWR_REG); temp = INA226_ReadData(addr); return (u16)temp;}
//获取功率,ina226内部计算,不准确,不采用void Get_Power(float *Power)//W{ *Power = (INA226_Get_Power(INA226_ADDR1)*POWER_LSB);}
//不设置报警,舍弃/*u8 INA226_AlertAddr(){ u8 temp; IIC_Start();
IIC_Send_Byte(INA226_GETALADDR); IIC_Wait_Ack(); temp = IIC_Read_Byte(1); IIC_Stop(); return temp;}*/
复制代码

5.5 BH1750 环境光强度

#include "bh1750.h"float Read_BH1750_Data(){    unsigned char t0;    unsigned char t1;    float t;    u8 r_s=0;    IIC_Start(); //发送起始信号    IIC_WriteOneByteData(0x46);    r_s=IIC_GetACK();//获取应答    if(r_s)printf("error:1\r\n");    IIC_WriteOneByteData(0x01);    r_s=IIC_GetACK();//获取应答     if(r_s)printf("error:2\r\n");    IIC_Stop(); //停止信号         IIC_Start(); //发送起始信号    IIC_WriteOneByteData(0x46);    r_s=IIC_GetACK();//获取应答    if(r_s)printf("error:3\r\n");    IIC_WriteOneByteData(0x01);    r_s=IIC_GetACK();//获取应答    if(r_s)printf("error:4\r\n");    IIC_Stop(); //停止信号         IIC_Start(); //发送起始信号    IIC_WriteOneByteData(0x46);    r_s=IIC_GetACK();//获取应答    if(r_s)printf("error:5\r\n");    IIC_WriteOneByteData(0x10);    r_s=IIC_GetACK();//获取应答    if(r_s)printf("error:6\r\n");    IIC_Stop(); //停止信号         DelayMs(100); //等待        IIC_Start(); //发送起始信号    IIC_WriteOneByteData(0x47);    r_s=IIC_GetACK();//获取应答    if(r_s)printf("error:7\r\n");        t0=IIC_ReadOneByteData(); //接收数据    IIC_SendACK(0); //发送应答信号    t1=IIC_ReadOneByteData(); //接收数据    IIC_SendACK(1); //发送非应答信号    IIC_Stop(); //停止信号         t=(((t0<<8)|t1)/1.2);     return t;  }
复制代码


发布于: 2022 年 07 月 06 日阅读数: 22
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022.01.06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
基于STM32+华为云IOT设计的智能路灯_7月月更_DS小龙哥_InfoQ写作社区