华为云平台创建产品

创建账号

此部分省略…

打开物联网平台

搜索框内搜索物联网平台

image-20230609164140693

点击打开【设备接入IOTDA】

image-20230609164408118

点击进入【管理控制台】

image-20230609164457032

这里进入后可能会提示你进行实名认证,如果不实名认证的话是不可以使用云平台的

创建产品

我记得第一次使用的话好像还需要创建一个空间啥的,如果创建的话就一切默认就行了

  1. 点击右上角的【创建产品】

image-20230609164631340

  1. 参考下图进行信息填写
image-20230609165225429
  1. 创建完成后进入创建的产品,进行产品模型设置
  2. 首先先创建一个服务,服务ID自己根据实际写(因为我是基于STM32开发的,所以写的就是STM32)

image-20230609165726214

  1. 点击【新增属性】,添加产品需要收发的数据

image-20230609165845771

  1. 根据实际项目需求的数据格式,填写内容(下图是我读取和设置电机速度建立的属性)
image-20230609170050359
  1. 如果你还需要进行云端下发指令控制设备,那么还需要点击【添加命令】,进行指令的设置

image-20230609170209153

  1. 指令设置里面,【下发参数】就是下发指令控制设备,【响应参数】就是读取设备上传信息

image-20230609170419208

创建设备

在【所有设备】界面,点击右上角的【注册设备】添加设备

image-20230609170850033

记住下面页面生成的两个参数,他会给你一个下载一个TXT文件,这两个参数一会需要使用

image-20230609171306029

获取MQTT三元组

用下面的网页生成三元组:Huaweicloud IoTDA Mqtt ClientId Generator (myhuaweicloud.com)

image-20230609171618009

点击【Generate】后会根据你填写的信息生成MQTT三元组

平台地址和接口获取

参照下图,找到MQTT协议下的平台地址和端口号

我们使用的是MQTT,所以端口是1883

image-20230609171919965

ESP8266烧录AT指令

这里参考之前连接阿里云的笔记【如果之前烧录过AT指令,这里就可以不用再烧录了】

烧录所需资源

链接:https://pan.baidu.com/s/1TsdqrG8J2jgWOyJGn-KJrw?pwd=u3il
提取码:u3il

image-20230307200620751

打开烧录工具进行烧录

image-20230307201314854

image-20230307201307109

先点击【ERASE】,等完成后,再点击【START】进行烧录

烧录实际可能比较慢,耐心等待进度条跑完

出现提示弹出显示3-run stub fail,可能事端口选择错误或波特率错误(115200与1152000注意)

STM32+标准库函数+连接华为云

这里的设置参考:STM32 标准库+ESP8266+华为云物联网平台_stm32 物联网平台_IOT趣制作的博客-CSDN博客

delay函数使用自己的就行,没有提供

移植文件

这两个文件是我参考的博客里面提供的驱动文件,我并没有完全按照他说的进行移植更改

HuaweiIOT_at_esp8266.c

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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/*
*********************************************************************************************************
* 模块名称:esp8266+AT指令+华为云物联网平台
* 文件名称: HuaweiIOT_at_esp8266.c
* 说明备注:无
* 修改记录:无
* 版本号 日期 作者 说明
* V1.0 22-8-1 funiot.xyz|公众号“IOT趣制作”
* Copyright by JIA
*********************************************************************************************************
*/
//【步骤1】使用本驱动文件时,请在main.c中添加引用 #include "HuaweiIOT_at_esp8266.h"
//【步骤2】使用本驱动文件时,请将HuaweIOT.h中宏定义的数据进行补齐
//【步骤3】使用本驱动文件时,请将下面变量的声明拷贝至main.c
/*
步骤3拷贝开始↓
*********************************************************************************************************
uint8_t uart1_rec_i=0;
extern uint8_t atok_rec_flag;
char uart1_recdata=0,uart1_recstring[256],sub_string[150],analysis_Str[256];
*********************************************************************************************************
步骤3拷贝截至↑
*/
//【步骤4】使用本驱动文件时,请将下面的USART1_IRQHandler()串口接收中断处理函数拷贝至main.c,系统中断函数无需额外声明
/*
步骤4拷贝开始↓
// *********************************************************************************************************
// * 函 数 名: USART1_IRQHandler
// * 功能说明: 串口中断1函数:主要完成esp8266模块的通信接收处理
// * 形 参:无
// * 返 回 值: 无
// *********************************************************************************************************

void USART1_IRQHandler(void) //串口1中断服务程序
{
char str_temp[128];
char request_id[48];

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志
uart1_recdata =USART_ReceiveData(USART1); //读取接收到的数据
if(uart1_recdata!='\n')
{
//防止第一个接收为空格
if((uart1_rec_i==0)&&(uart1_recdata==' '))
{
//测试发现在接收MQTT服务器下发的命令时,有时接收的数据第一位为空格
//通过上述判断方式可以解决,触发原因暂时不明,贾工留坑-2022.9.3.1
}
else
{
uart1_recstring[uart1_rec_i]=uart1_recdata;
//printf("%c",uart1_recstring[uart1_rec_i]); //调试时开启
uart1_rec_i++; //统计接收字符数量
}
}
else
{
//printf("Rec Over,uart1_rec_i=%d,data=%s\r\n",uart1_rec_i,uart1_recstring);//调试时开启,用于检查接收数据内容
if(uart1_rec_i>=2)
{
strncpy(sub_string,uart1_recstring,2); //截取前两位
if(strcmp(sub_string,"OK")==0)
{
atok_rec_flag=1;
//printf("Get Ok\r\n");//调试时开启,用于确定是否接收到"ok"
}

strncpy(sub_string,uart1_recstring,5);
if(strcmp(sub_string,"ready")==0)
{
atok_rec_flag=1;
//printf("Get ready\r\n");//调试时开启,用于确定是否接收到“ready”
}

strncpy(sub_string,uart1_recstring,5);
if(strcmp(sub_string,"ERROR")==0)
{
atok_rec_flag=0;
//printf("Get ERROR\r\n");//调试时开启,用于确定是否接收到“ERROR”
}
//我的接收数据长度为201,下面采用JSON字符串硬解析的方式,具体下标请根据自己实际接收的参数处理
//+MQTTSUBRECV:0,"$oc/devices/61fb2d7fde9933029funiot_esp8266_test01/sys/commands/request_id=4152fb5d-e5ae-4b89-b39d-283ba59cf033",68,{"paras":{"led":1},"service_id":"Dev_data","command_name":"Control"}
if(uart1_rec_i>=200)
{
strncpy(analysis_Str, uart1_recstring, 12); //提取出“+MQTTSUBRECV”
if(strcmp(analysis_Str,"+MQTTSUBRECV")==0)
{
memset(analysis_Str,0,sizeof(analysis_Str)); //清空缓存区
//printf("MQTT命令接收头正确\r\n");
strncpy(request_id, uart1_recstring+92, 36); //提取出request_id
//printf("request_id=%s\r\n",request_id);
strncpy(analysis_Str, uart1_recstring+135, 5); //提取出"paras"
//printf("paras=%s\r\n",analysis_Str);
if(strcmp(analysis_Str,"paras")==0) //有效参数体
{
memset(analysis_Str,0,sizeof(analysis_Str)); //清空缓存区
strncpy(analysis_Str, uart1_recstring+144,3); //提取出"led"
//printf("att is %s\r\n",analysis_Str);
if(strcmp(analysis_Str,"led")==0)
{
//printf("led set %c\r\n",uart1_recstring[149]);

if(uart1_recstring[149]=='0')
{
//printf("关灯\r\n");
LED_TurnOff(3);
}
else if(uart1_recstring[149]=='1')
{
//printf("开灯\r\n");
LED_TurnOn(3);
}
//向云平台完成命令响应
printf("AT+MQTTPUB=0,\"$oc/devices/%s/sys/commands/response/request_id=%s\",\"\",0,0\r\n",HUAWEI_MQTT_DeviceID,request_id);

memset(analysis_Str,0,sizeof(analysis_Str));//清空缓存区
memset(str_temp,0,sizeof(str_temp)); //清空缓存区
}
}
}

}
}
uart1_rec_i=0;
memset(uart1_recstring,0,sizeof(uart1_recstring));//清空uart1_recstring字符串
memset(sub_string,0,sizeof(sub_string)); //清空sub_string字符串
}
}
}
步骤4拷贝截至↑
*/

///////////////////////////////////////////////////////////
/*头文件包含区*/
#include "HuaweiIOT_at_esp8266.h"
#include "string.h"
#include "delay.h"
#include "usart.h"

///////////////////////////////////////////////////////////
/*宏定义区*/

///////////////////////////////////////////////////////////
/*外部变量声明区*/
uint8_t atok_rec_flag;
///////////////////////////////////////////////////////////
/*函数声明区*/

///////////////////////////////////////////////////////////
/*函数实体区*/

/**********************************************************************************************************
* 函 数 名: HuaweiIot_init
* 功能说明: 华为云物联网平台初始化
* 形 参:无
* 返 回 值: 无
**********************************************************************************************************/
void HuaweiIot_init(void)
{
uint8_t i=0;

char str_temp[256]; //虽然在实际使用时str_temp最大不超100,但是测试时发现char str_temp[128]时程序会卡死
//经过景哥和强哥帮助,将其改为char str_temp[256]时可以正常运行,或者将其定义为全局变量
//初步分析为作用域不同导致分配栈空间不同,具体原因待日后分析。—贾工留坑-2023.3.10.1

delay_ms(1000); //等待模块上电稳定

for(i=0;i<10;i++)
{
if(atok_rec_flag==1)
{
AT_write("AT"); //AT测试
printf("AT+RST\r\n"); //重启设备
delay_ms(2000); //等待设备重启
AT_write("AT"); //AT测试
AT_write("AT+CWMODE=1");//设置模块为STA模式

sprintf(str_temp,"AT+CWJAP=\"%s\",\"%s\"",WIFI_SSID,WIFI_PWD); //连接WiFi
AT_write(str_temp);

sprintf(str_temp,"AT+MQTTUSERCFG=0,1,\"NULL\",\"%s\",\"%s\",0,0,\"\"",HUAWEI_MQTT_USERNAME,HUAWEI_MQTT_PASSWORD);//设置MQTT的登陆用户名与密码
AT_write(str_temp);

sprintf(str_temp,"AT+MQTTCLIENTID=0,\"%s\"",HUAWEI_MQTT_ClientID);//设置MQTT的ClientID
AT_write(str_temp);

sprintf(str_temp,"AT+MQTTCONN=0,\"%s\",%s,1",HUAWEI_MQTT_ADDRESS,HUAWEI_MQTT_PORT);//设置MQTT接入地址与端口号
AT_write(str_temp);

sprintf(str_temp,"AT+MQTTSUB=0,\"$oc/devices/%s/sys/properties/report\",1",HUAWEI_MQTT_DeviceID); //订阅设备属性上报的主题
AT_write(str_temp);

sprintf(str_temp,"AT+MQTTSUB=0,\"$oc/devices/%s/sys/commands/#\",1",HUAWEI_MQTT_DeviceID);//订阅设备命令接收的主题
AT_write(str_temp);

sprintf(str_temp,"AT+MQTTSUB=0,\"$oc/devices/%s/sys/commands/response/#\",1",HUAWEI_MQTT_DeviceID);//订阅设备命令响应的主题
AT_write(str_temp);
break;
}
else
{
if(i==9)
{
printf("Connected ESP01s Fail!\r\n"); //连接超时
break;
}
else
{
printf("AT\r\n");
delay_ms(1000);
}

}
}
}
/**********************************************************************************************************
* 函 数 名: AT_write
* 功能说明: AT指令发送
* 形 参:无
* 返 回 值: 无
**********************************************************************************************************/
void AT_write(char atstring[512])//阻塞等待OK
{
atok_rec_flag=0;
printf("%s\r\n",atstring);
while(1)
{
if(atok_rec_flag==1) //接收到OK后串口中断会将atok_rec_flag置1
{
atok_rec_flag=0;
break;
}
else
delay_ms(50);
}
}
/**********************************************************************************************************
* 函 数 名: HuaweiIot_publish
* 功能说明: 华为云设备属性上报
* 形 参:char * att,属性名;uint16_t data:属性值
* 返 回 值: 无
**********************************************************************************************************/
void HuaweiIot_DevDate_publish(char *att,uint16_t data)
{
printf("AT+MQTTPUB=0,\"$oc/devices/%s/sys/properties/report\",\"{\\\"services\\\":[{\\\"service_id\\\":\\\"%s\\\"\\,\\\"properties\\\":{\\\"%s\\\": %d}}]}\",0,0\r\n",HUAWEI_MQTT_DeviceID,HUAWEI_MQTT_ServiceID,att,data);
}

///////////////////////////////////////////////////////////

HuaweiIOT_at_esp8266.h

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
/*
*********************************************************************************************************
* 模块名称: esp8266+AT指令+华为云物联网平台
* 文件名称: HuaweiIOT_at_esp8266.h
* 说明备注:无
* 修改记录:无
* 版本号 日期 作者 说明
* V1.0 22-8-1 funiot.xyz|公众号“IOT趣制作”
* Copyright by JIA
*********************************************************************************************************
*/
#ifndef __HUAWEIIOT_H
#define __HUAWEIIOT_H

///////////////////////////////////////////////////////////
/*头文件包含区*/
#include "sys.h"
///////////////////////////////////////////////////////////
/*宏定义区*/
//使用时请在这里补全相关信息
#define WIFI_SSID "xxxxxxxx"
#define WIFI_PWD "xxxxxxxx"
#define HUAWEI_MQTT_USERNAME "xxxxxxxx"
#define HUAWEI_MQTT_PASSWORD "xxxxxxxx"
#define HUAWEI_MQTT_ClientID "xxxxxxxx"
#define HUAWEI_MQTT_ADDRESS "xxxxxxxx"
#define HUAWEI_MQTT_PORT "xxxxxxxx"
#define HUAWEI_MQTT_DeviceID "xxxxxxxx"
#define HUAWEI_MQTT_ServiceID "xxxxxxxx"
///////////////////////////////////////////////////////////
/*外部变量声明区*/

///////////////////////////////////////////////////////////
/*函数声明区*/
void AT_write(char atstring[512]);//阻塞等待OK
void HuaweiIot_init(void);
void HuaweiIot_DevDate_publish(char * att,uint16_t data);
///////////////////////////////////////////////////////////
#endif

填写宏定义数据

HUAWEI_MQTT_DeviceID:创建产品时生成的产品ID

HUAWEI_MQTT_ServiceID:创建产品时在模型里面创建的服务ID

image-20230609172752098

添加usart文件

我这把usart中断函数放在了usart.c文件中,没有放在main.c中

usart.c

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
#include "stm32f10x.h"                  // Device header
#include <string.h>
#include <stdio.h>
#include "HuaweiIOT_at_esp8266.h"

uint8_t uart1_rec_i = 0;
extern uint8_t atok_rec_flag;
char uart1_recdata = 0, uart1_recstring[256], sub_string[150], analysis_Str[256];
extern uint16_t speed;
uint16_t speed_flag;

void MyUSART_Init(void) {
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//1.开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

GPIO_InitTypeDef GPIO_InitStructure; //初始化GIPIO
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

USART_InitTypeDef USART_InitStructure; //初始化串口
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStructure);

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

}

// *********************************************************************************************************
// * 函 数 名: USART1_IRQHandler
// * 功能说明: 串口中断1函数:主要完成esp8266模块的通信接收处理
// * 形 参:无
// * 返 回 值: 无
// *********************************************************************************************************

void USART1_IRQHandler(void) //串口1中断服务程序
{
char str_temp[128];
char request_id[48];

if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除中断标志
uart1_recdata = USART_ReceiveData(USART1); //读取接收到的数据
if (uart1_recdata != '\n') {
//防止第一个接收为空格
if ((uart1_rec_i == 0) && (uart1_recdata == ' ')) {
//测试发现在接收MQTT服务器下发的命令时,有时接收的数据第一位为空格
//通过上述判断方式可以解决,触发原因暂时不明,贾工留坑-2022.9.3.1
} else {
uart1_recstring[uart1_rec_i] = uart1_recdata;
//printf("%c",uart1_recstring[uart1_rec_i]); //调试时开启
uart1_rec_i++; //统计接收字符数量
}
} else {
//printf("Rec Over,uart1_rec_i=%d,data=%s\r\n",uart1_rec_i,uart1_recstring);//调试时开启,用于检查接收数据内容
if (uart1_rec_i >= 2) {
strncpy(sub_string, uart1_recstring, 2); //截取前两位
if (strcmp(sub_string, "OK") == 0) {
atok_rec_flag = 1;
//printf("Get Ok\r\n");//调试时开启,用于确定是否接收到"ok"
}

strncpy(sub_string, uart1_recstring, 5);
if (strcmp(sub_string, "ready") == 0) {
atok_rec_flag = 1;
//printf("Get ready\r\n");//调试时开启,用于确定是否接收到“ready”
}

strncpy(sub_string, uart1_recstring, 5);
if (strcmp(sub_string, "ERROR") == 0) {
atok_rec_flag = 0;
//printf("Get ERROR\r\n");//调试时开启,用于确定是否接收到“ERROR”
}
//我的接收数据长度为201,下面采用JSON字符串硬解析的方式,具体下标请根据自己实际接收的参数处理
//+MQTTSUBRECV:0,"$oc/devices/61fb2d7fde9933029funiot_esp8266_test01/sys/commands/request_id=4152fb5d-e5ae-4b89-b39d-283ba59cf033",68,{"paras":{"led":1},"service_id":"Dev_data","command_name":"Control"}
if (uart1_rec_i >= 190) {
strncpy(analysis_Str, uart1_recstring, 12); //提取出“+MQTTSUBRECV”
if (strcmp(analysis_Str, "+MQTTSUBRECV") == 0) {
memset(analysis_Str, 0, sizeof(analysis_Str)); //清空缓存区
//printf("MQTT命令接收头正确\r\n");
strncpy(request_id, uart1_recstring + 84, 36); //提取出request_id
//printf("request_id=%s\r\n",request_id);
strncpy(analysis_Str, uart1_recstring + 127, 5); //提取出"paras"
//printf("paras=%s\r\n",analysis_Str);
if (strcmp(analysis_Str, "paras") == 0) //有效参数体
{
memset(analysis_Str, 0, sizeof(analysis_Str)); //清空缓存区
strncpy(analysis_Str, uart1_recstring + 136, 7); //提取出"led"
//printf("att is %s\r\n",analysis_Str);
if (strcmp(analysis_Str, "ActVel1") == 0) {
//printf("led set %c\r\n",uart1_recstring[145]);

if (uart1_recstring[144] == ':') {
speed = (uart1_recstring[145] - '0') * 10 + (uart1_recstring[146] - '0');
// printf("关灯\r\n");

} else if (uart1_recstring[145] == '1') {
printf("开灯\r\n");
//LED_TurnOn(3);
}
//向云平台完成命令响应
printf("AT+MQTTPUB=0,\"$oc/devices/%s/sys/commands/response/request_id=%s\",\"\",0,0\r\n",
HUAWEI_MQTT_DeviceID, request_id);

memset(analysis_Str, 0, sizeof(analysis_Str));//清空缓存区
memset(str_temp, 0, sizeof(str_temp)); //清空缓存区
}
}
}

}
}
uart1_rec_i = 0;
memset(uart1_recstring, 0, sizeof(uart1_recstring));//清空uart1_recstring字符串
memset(sub_string, 0, sizeof(sub_string)); //清空sub_string字符串
}
}
}

//内部调用函数,注意要勾选OPTIONS中的USE Micro LIB选项
int fputc(int ch, FILE *f) //printf重定向
{
USART_SendData(USART1, (uint8_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
return ch;
}

usart.h

1
2
3
4
5
6
7
8
#ifndef __USART_H
#define __USART_H
#include "stdio.h"

void MyUSART_Init(void);

#endif

程序移植更改过程

1.main.c中添加头文件

1
2
#include "HuaweiIOT_at_esp8266.h" 
#include "usart.h"

image-20230609173756860

2.main.c中main函数中开启初始化

1
2
MyUSART_Init();
HuaweiIot_init(); //华为云物联网平台初始化

image-20230609173841240

3.数据上传

1
2
HuaweiIot_DevDate_publish("ActVel1",speed++);
delay_ms(3000);

4.全局变量从HuaweiIOT_at_esp8266.c移植到usart.c(如果直接拷贝上述的usart文件则可以跳过)

image-20230609174046666

5.中断服务函数HuaweiIOT_at_esp8266.c移植到usart.c(如果直接拷贝上述的usart文件则可以跳过)

image-20230609174151183

6.中断服务函数中的接受云端数据的代码分析更改(这部分是需要根据你个人的实际数据格式进行更改的)

image-20230609175235317

这部分最麻烦的就行算那个长度,其实我之前连阿里云的时候用的是使用循环直接查找属性名获取数据值的,但是他提供的驱动里面使用的是这种手动计算长度,然后截取字符串判断后获取数据,我本来想改成自动的,但没改成,就只能用他的了

个人完整工程

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "HuaweiIOT_at_esp8266.h"
#include "usart.h"

uint16_t speed;
int main(){
MyUSART_Init();
HuaweiIot_init(); //华为云物联网平台初始化

while(1){
HuaweiIot_DevDate_publish("ActVel1",speed++);
delay_ms(3000);
}
}

HuaweiIOT_at_esp8266.c

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
#include "HuaweiIOT_at_esp8266.h"
#include "string.h"
#include "Delay.h"
#include "usart.h"

/*外部变量声明区*/
uint8_t atok_rec_flag;

/**********************************************************************************************************
* 函 数 名: HuaweiIot_init
* 功能说明: 华为云物联网平台初始化
* 形 参:无
* 返 回 值: 无
**********************************************************************************************************/
void HuaweiIot_init(void)
{
uint8_t i=0;

char str_temp[256]; //虽然在实际使用时str_temp最大不超100,但是测试时发现char str_temp[128]时程序会卡死
//经过景哥和强哥帮助,将其改为char str_temp[256]时可以正常运行,或者将其定义为全局变量
//初步分析为作用域不同导致分配栈空间不同,具体原因待日后分析。—贾工留坑-2023.3.10.1

delay_ms(1000); //等待模块上电稳定

for(i=0;i<10;i++)
{
if(atok_rec_flag==1)
{
AT_write("AT"); //AT测试
printf("AT+RST\r\n"); //重启设备
delay_ms(2000); //等待设备重启
AT_write("AT"); //AT测试
AT_write("AT+CWMODE=1");//设置模块为STA模式

sprintf(str_temp,"AT+CWJAP=\"%s\",\"%s\"",WIFI_SSID,WIFI_PWD); //连接WiFi
AT_write(str_temp);

sprintf(str_temp,"AT+MQTTUSERCFG=0,1,\"NULL\",\"%s\",\"%s\",0,0,\"\"",HUAWEI_MQTT_USERNAME,HUAWEI_MQTT_PASSWORD);//设置MQTT的登陆用户名与密码
AT_write(str_temp);

sprintf(str_temp,"AT+MQTTCLIENTID=0,\"%s\"",HUAWEI_MQTT_ClientID);//设置MQTT的ClientID
AT_write(str_temp);

sprintf(str_temp,"AT+MQTTCONN=0,\"%s\",%s,1",HUAWEI_MQTT_ADDRESS,HUAWEI_MQTT_PORT);//设置MQTT接入地址与端口号
AT_write(str_temp);

sprintf(str_temp,"AT+MQTTSUB=0,\"$oc/devices/%s/sys/properties/report\",1",HUAWEI_MQTT_DeviceID); //订阅设备属性上报的主题
AT_write(str_temp);

sprintf(str_temp,"AT+MQTTSUB=0,\"$oc/devices/%s/sys/commands/#\",1",HUAWEI_MQTT_DeviceID);//订阅设备命令接收的主题
AT_write(str_temp);

sprintf(str_temp,"AT+MQTTSUB=0,\"$oc/devices/%s/sys/commands/response/#\",1",HUAWEI_MQTT_DeviceID);//订阅设备命令响应的主题
AT_write(str_temp);
break;
}
else
{
if(i==9)
{
printf("Connected ESP01s Fail!\r\n"); //连接超时
break;
}
else
{
printf("AT\r\n");
delay_ms(1000);
}

}
}
}
/**********************************************************************************************************
* 函 数 名: AT_write
* 功能说明: AT指令发送
* 形 参:无
* 返 回 值: 无
**********************************************************************************************************/
void AT_write(char atstring[512])//阻塞等待OK
{
atok_rec_flag=0;
printf("%s\r\n",atstring);
while(1)
{
if(atok_rec_flag==1) //接收到OK后串口中断会将atok_rec_flag置1
{
atok_rec_flag=0;
break;
}
else
delay_ms(50);
}
}
/**********************************************************************************************************
* 函 数 名: HuaweiIot_publish
* 功能说明: 华为云设备属性上报
* 形 参:char * att,属性名;uint16_t data:属性值
* 返 回 值: 无
**********************************************************************************************************/
void HuaweiIot_DevDate_publish(char *att,uint16_t data)
{
printf("AT+MQTTPUB=0,\"$oc/devices/%s/sys/properties/report\",\"{\\\"services\\\":[{\\\"service_id\\\":\\\"%s\\\"\\,\\\"properties\\\":{\\\"%s\\\": %d}}]}\",0,0\r\n",HUAWEI_MQTT_DeviceID,HUAWEI_MQTT_ServiceID,att,data);
}

///////////////////////////////////////////////////////////

HuaweiIOT_at_esp8266.h

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
/*
*********************************************************************************************************
* 模块名称: esp8266+AT指令+华为云物联网平台
* 文件名称: HuaweiIOT_at_esp8266.h
* 说明备注:无
* 修改记录:无
* 版本号 日期 作者 说明
* V1.0 22-8-1 funiot.xyz|公众号“IOT趣制作”
* Copyright by JIA
*********************************************************************************************************
*/
#ifndef __HUAWEIIOT_H
#define __HUAWEIIOT_H

///////////////////////////////////////////////////////////
/*头文件包含区*/
#include "stm32f10x.h" // Device header
///////////////////////////////////////////////////////////
/*宏定义区*/
//使用时请在这里补全相关信息
#define WIFI_SSID "xxxxxxxx" //WiFi名
#define WIFI_PWD "xxxxxxxx" //WiFi密码
#define HUAWEI_MQTT_USERNAME "xxxxxxxx" //Username
#define HUAWEI_MQTT_PASSWORD "xxxxxxxx" //Password
#define HUAWEI_MQTT_ClientID "xxxxxxxx" //ClientId
#define HUAWEI_MQTT_ADDRESS "xxxxxxxx" //平台地址
#define HUAWEI_MQTT_PORT "xxxxxxxx" //端口号
#define HUAWEI_MQTT_DeviceID "xxxxxxxx" //设备ID
#define HUAWEI_MQTT_ServiceID "xxxxxxxx" //服务ID
///////////////////////////////////////////////////////////
/*外部变量声明区*/

///////////////////////////////////////////////////////////
/*函数声明区*/
void AT_write(char atstring[512]);//阻塞等待OK
void HuaweiIot_init(void);
void HuaweiIot_DevDate_publish(char * att,uint16_t data);
///////////////////////////////////////////////////////////
#endif

usart.c

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
#include "stm32f10x.h"                  // Device header
#include <string.h>
#include <stdio.h>
#include "HuaweiIOT_at_esp8266.h"

uint8_t uart1_rec_i = 0;
extern uint8_t atok_rec_flag;
char uart1_recdata = 0, uart1_recstring[256], sub_string[150], analysis_Str[256];
extern uint16_t speed;
uint16_t speed_flag;

void MyUSART_Init(void) {
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//1.开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

GPIO_InitTypeDef GPIO_InitStructure; //初始化GIPIO
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

USART_InitTypeDef USART_InitStructure; //初始化串口
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStructure);

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

}

// *********************************************************************************************************
// * 函 数 名: USART1_IRQHandler
// * 功能说明: 串口中断1函数:主要完成esp8266模块的通信接收处理
// * 形 参:无
// * 返 回 值: 无
// *********************************************************************************************************

void USART1_IRQHandler(void) //串口1中断服务程序
{
char str_temp[128];
char request_id[48];

if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除中断标志
uart1_recdata = USART_ReceiveData(USART1); //读取接收到的数据
if (uart1_recdata != '\n') {
//防止第一个接收为空格
if ((uart1_rec_i == 0) && (uart1_recdata == ' ')) {
//测试发现在接收MQTT服务器下发的命令时,有时接收的数据第一位为空格
//通过上述判断方式可以解决,触发原因暂时不明,贾工留坑-2022.9.3.1
} else {
uart1_recstring[uart1_rec_i] = uart1_recdata;
//printf("%c",uart1_recstring[uart1_rec_i]); //调试时开启
uart1_rec_i++; //统计接收字符数量
}
} else {
//printf("Rec Over,uart1_rec_i=%d,data=%s\r\n",uart1_rec_i,uart1_recstring);//调试时开启,用于检查接收数据内容
if (uart1_rec_i >= 2) {
strncpy(sub_string, uart1_recstring, 2); //截取前两位
if (strcmp(sub_string, "OK") == 0) {
atok_rec_flag = 1;
//printf("Get Ok\r\n");//调试时开启,用于确定是否接收到"ok"
}

strncpy(sub_string, uart1_recstring, 5);
if (strcmp(sub_string, "ready") == 0) {
atok_rec_flag = 1;
//printf("Get ready\r\n");//调试时开启,用于确定是否接收到“ready”
}

strncpy(sub_string, uart1_recstring, 5);
if (strcmp(sub_string, "ERROR") == 0) {
atok_rec_flag = 0;
//printf("Get ERROR\r\n");//调试时开启,用于确定是否接收到“ERROR”
}
//我的接收数据长度为201,下面采用JSON字符串硬解析的方式,具体下标请根据自己实际接收的参数处理
//+MQTTSUBRECV:0,"$oc/devices/61fb2d7fde9933029funiot_esp8266_test01/sys/commands/request_id=4152fb5d-e5ae-4b89-b39d-283ba59cf033",68,{"paras":{"led":1},"service_id":"Dev_data","command_name":"Control"}
if (uart1_rec_i >= 190) {
strncpy(analysis_Str, uart1_recstring, 12); //提取出“+MQTTSUBRECV”
if (strcmp(analysis_Str, "+MQTTSUBRECV") == 0) {
memset(analysis_Str, 0, sizeof(analysis_Str)); //清空缓存区
//printf("MQTT命令接收头正确\r\n");
strncpy(request_id, uart1_recstring + 84, 36); //提取出request_id
//printf("request_id=%s\r\n",request_id);
strncpy(analysis_Str, uart1_recstring + 127, 5); //提取出"paras"
//printf("paras=%s\r\n",analysis_Str);
if (strcmp(analysis_Str, "paras") == 0) //有效参数体
{
memset(analysis_Str, 0, sizeof(analysis_Str)); //清空缓存区
strncpy(analysis_Str, uart1_recstring + 136, 7); //提取出"led"
//printf("att is %s\r\n",analysis_Str);
if (strcmp(analysis_Str, "ActVel1") == 0) {
//printf("led set %c\r\n",uart1_recstring[145]);

if (uart1_recstring[144] == ':') {
speed = (uart1_recstring[145] - '0') * 10 + (uart1_recstring[146] - '0');
// printf("关灯\r\n");

} else if (uart1_recstring[145] == '1') {
printf("开灯\r\n");
//LED_TurnOn(3);
}
//向云平台完成命令响应
printf("AT+MQTTPUB=0,\"$oc/devices/%s/sys/commands/response/request_id=%s\",\"\",0,0\r\n",
HUAWEI_MQTT_DeviceID, request_id);

memset(analysis_Str, 0, sizeof(analysis_Str));//清空缓存区
memset(str_temp, 0, sizeof(str_temp)); //清空缓存区
}
}
}

}
}
uart1_rec_i = 0;
memset(uart1_recstring, 0, sizeof(uart1_recstring));//清空uart1_recstring字符串
memset(sub_string, 0, sizeof(sub_string)); //清空sub_string字符串
}
}
}

//内部调用函数,注意要勾选OPTIONS中的USE Micro LIB选项
int fputc(int ch, FILE *f) //printf重定向
{
USART_SendData(USART1, (uint8_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
return ch;
}

usart.h

1
2
3
4
5
6
7
#ifndef __USART_H
#define __USART_H
#include "stdio.h"

void MyUSART_Init(void);

#endif