#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯 原创 精华

DS小龙哥
发布于 2022-7-16 11:55
浏览
0收藏

本文正在参加星光计划3.0–夏日挑战赛

1. 前言

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

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

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

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

3. 硬件选型

3.1 STM32F103C8T6

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

3.2 太阳能板

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

3.3 锂电池充电模块

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

3.4 功率检测模块

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

3.5 BH1750光敏传感器

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

3.6 LED灯

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

3.7 BC20-NBIOT模块

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

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

4. 创建产品与设备

4.1 创建产品

地址:https://www.huaweicloud.com/?locale=zh-cn
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

4.2 自定义模型

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

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

4.3 创建设备

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

{
    "device_id": "6276134223aaf461a0f6e515_1126626497",
    "secret": "12345678"
}
  • 1.
  • 2.
  • 3.
  • 4.

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
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

MQTT设备登陆密匙生成地址: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

DeviceId      	6276134223aaf461a0f6e515_1126626497
DeviceSecret 	12345678
ClientId  		6276134223aaf461a0f6e515_1126626497_0_0_2022050706
Username  		6276134223aaf461a0f6e515_1126626497
Password  		73ebe0779dbd5b2e2fd3db8ab8f642b78d7a532576f2e14d2799d4f78d37bcc8
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

华为云物联网平台的域名是: 161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com
华为云物联网平台的IP地址是:121.36.42.100
在软件里参数填充正确之后,就看到设备已经连接成功了。
接下来打开设备页面,可以看到设备已经在线了。
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

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"}}]}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

通过MQTT客户端软件模拟上报测试:
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

4.6 应用侧开发

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

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

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

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

5. STM32程序设计

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

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

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

连接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
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.

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
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.

5.3 keil工程代码

#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区
#夏日挑战赛# 基于STM32+华为云IOT设计的智能路灯-鸿蒙开发者社区

5.4 功率检测

#include "INA226.h"
#include "delay.h"
//	接线说明:
//	模拟IIC:
//IIC_SCL -- 时钟线PB6(推挽、开漏输出)
//IIC_SDA -- 双向数据线PB7
INA226 ina226_data;
//初始化INA226
void 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/bit
u16 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;
}

//获取id
void 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/bit
u16 INA226_GetVoltage(u8 addr)
{
	u32 temp = 0;
	INA226_SetRegPointer(addr,BV_REG);
	temp = INA226_ReadData(addr);
	return (u16)temp;	
}

//2.5uV/bit
u16 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;
}
*/

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.

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;  
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
标签
已于2022-7-21 09:41:41修改
1
收藏
回复
举报
1


回复
    相关推荐
    skyyoung
    LV.2
    这个用户很懒,还没有个人简介
    觉得TA不错?点个关注精彩不错过
    34
    帖子
    0
    视频
    154
    声望
    0
    粉丝
    社区精华内容