物联网应用开发--STM32与新大陆云平台通信(云平台控制开发板上蜂鸣器、LED)

实现目标

1、掌握云平台执行器的创建

2、熟悉STM32 与ESP8266模块之间的通信

3、具体实现目标:(1)创建5个执行器:蜂鸣器,LED1,LED2,ED3,LED4;(2)执行器能对应控制开发板的蜂鸣器和LED。


一、项目创建

项目创建详细步骤参考:https://blog.csdn.net/luojuan198780/article/details/138766783

项目整体:创建5个执行器

1.1   执行器之蜂鸣器设置

1.2  执行器之LED设置。4个LED配置除了名称其它都一样

二、开发板连接图

开发板P7四个跳键帽接法如下图:

说明:单片机的USART1用于调试信息打印USART2用于与ESP8266模块通信。

三、STM32CubeMX 配置

1.GPIO配置

BEEP:初始电平为低电平,推挽输出;LED1-LED4:初始电平为高电平,推挽输出。

2.串口USART1配置

USART1:异步模式,波特率115200,功能:用于打印调试信息

3.串口USART2配置

USART2:异步模式,波特率115200,开启DMA,开启中断。功能:用于与ESP8266通信

四、程序设计

说明:整个工程的代码量大,下面只列出了整个工程中最主要的一些函数。

1、串口USART1重定向

#include <stdio.h>int fputc(int ch,FILE *f)
{HAL_UART_Transmit (&huart1 ,(uint8_t *)&ch,1,HAL_MAX_DELAY );return ch;
}

2、串口USART2收发实现

uint8_t UART2_RX_BUF[255];//开启DMA空闲接收中断,将数据存放在数组UART2_RX_BUF中HAL_UARTEx_ReceiveToIdle_DMA(&huart2,UART2_RX_BUF,sizeof(UART2_RX_BUF)); //中断回调函数:实现接收云平台发来的数据
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if(huart == &huart2) //  { HAL_UARTEx_ReceiveToIdle_DMA(&huart2,UART2_RX_BUF,sizeof(UART2_RX_BUF));__HAL_DMA_DISABLE_IT(&hdma_usart2_rx,DMA_IT_HT);			}
}//功能:发送AT指令字符串
void SendAtCmd(uint8_t *string, uint8_t len)
{HAL_UART_Transmit(&huart2,string, len,1000);HAL_UART_Transmit(&huart2,(uint8_t *)"\r\n", 2,20);	
}//清空AT串口接收缓存
void ClrAtRxBuf(void)
{memset(AT_RX_BUF, 0x00, MAX_AT_RX_LEN);//清空缓存AT_RX_COUNT = 0;F_AT_RX_FINISH = 0;
}

3、STM32发送AT指令主要函数

//ESP8266设置为station模式  -----1
int8_t ESP8266_SetStation(void)
{ClrAtRxBuf();//清空缓存SendAtCmd((uint8_t *)AT_CWMODE,strlen(AT_CWMODE));printf("AT+CWMODE_CUR=1\r\n");HAL_Delay(100);if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL){printf("AT+CWMODE_CUR=1 error\r\n");return -1;}else{printf("AT+CWMODE_CUR=1 ok\r\n");}return 0;
}//设置ESP8266要连接的热点名称和密码  -----2int8_t ESP8266_SetAP(char *wifi, char *pwd)
{uint8_t AtCwjap[MAX_AT_TX_LEN];memset(AtCwjap, 0x00, MAX_AT_TX_LEN);//清空缓存ClrAtRxBuf();//清空缓存sprintf((char *)AtCwjap,"AT+CWJAP_CUR=\"%s\",\"%s\"",wifi, pwd);printf("AT+CWJAP_CUR=newland-edu1,12345678 \r\n");SendAtCmd((uint8_t *)AtCwjap,strlen((const char *)AtCwjap));HAL_Delay(5500);if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL){return -1;}return 0;
}//ESP8266建立TCP连接  -----3int8_t ESP8266_IpStart(char *IpAddr, uint16_t port)
{uint8_t IpStart[MAX_AT_TX_LEN];   memset(IpStart, 0x00, MAX_AT_TX_LEN);//清空缓存   ClrAtRxBuf();//清空缓存   sprintf((char *)IpStart,"AT+CIPSTART=\"TCP\",\"%s\",%d",IpAddr, port);   printf("%s\r\n",IpStart);//SendAtCmd((uint8_t *)IpStart,strlen((const char *)IpStart));   HAL_Delay(1500);   if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)   {   return -1;   }   return 0;  	
}//ESP8266建立TCP连接  -----4int8_t ESP8266_IpSend(char *IpBuf, uint8_t len)
{uint8_t TryGo = 0; int8_t error = 0;   uint8_t IpSend[MAX_AT_TX_LEN];   memset(IpSend, 0x00, MAX_AT_TX_LEN);//清空缓存   ClrAtRxBuf();//清空缓存   sprintf((char *)IpSend,"AT+CIPSEND=%d",len);   printf("%s\r\n",IpSend);/SendAtCmd((uint8_t *)IpSend,strlen((const char *)IpSend));   HAL_Delay(3);   if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)  {   return -1;   }   ClrAtRxBuf();//清空缓存   SendStrLen((uint8_t *)IpBuf, len);   printf("%s\r\n",IpBuf);//for(TryGo = 0; TryGo<60; TryGo++)//最多等待时间 100*60=6000ms   {   if(strstr((const char *)AT_RX_BUF, (const char *)"SEND OK") == NULL) {   error = -2;   }   else   {   error = 0;   break;   }   HAL_Delay(100);   }   return error; 	
}//连接到服务器  -----5int8_t ConnectToServer(char *DeviceID, char *SecretKey)
{uint8_t TryGo = 0;int8_t error = 0;uint8_t TxetBuf[MAX_AT_TX_LEN];memset(TxetBuf,0x00,MAX_AT_TX_LEN);//清空缓存for(TryGo = 0; TryGo<3; TryGo++){if(ESP8266_SetStation() == 0)//设置WiFi通讯模块工作模式{error = 0;break;}else{error = -1;}}if(error < 0){return error;}for(TryGo = 0; TryGo<3; TryGo++){if(ESP8266_SetAP((char *)WIFI_AP, (char *)WIFI_PWD) == 0)//设置热点名称和密码{error = 0;break;}else{error = -2;}}if(error < 0){return error;}for(TryGo = 0; TryGo<3; TryGo++){if(ESP8266_IpStart((char *)SERVER_IP,SERVER_PORT) == 0)//连接服务器IP地址,端口:120.77.58.34,8600{error = 0;break;}else{error = -3;}}if(error < 0){return error;}sprintf((char *)TxetBuf,"{\"t\":1,\"device\":\"%s\",\"key\":\"%s\",\"ver\":\"v0.0.0.0\"}",DeviceID,SecretKey);//printf("%s\r\n",TxetBuf);if(ESP8266_IpSend((char *)TxetBuf, strlen((char *)TxetBuf)) < 0){//发送失败error=-4;}else{//发送成功for(TryGo = 0; TryGo<50; TryGo++)//最多等待时间50*10=500ms{if(strstr((const char *)AT_RX_BUF, (const char *)"\"status\":0") == NULL)//检查响应状态是否为握手成功{error = -5;}else{error = 0;break;}HAL_Delay(10);}}return error;
}//发送传感数据到服务器 -----6int8_t ESP8266_SendSensor(uint8_t sensor, char *TimeStr)
{uint8_t TryGo = 0;int8_t error = 0;uint8_t TxetBuf[MAX_AT_TX_LEN];memset(TxetBuf,0x00,MAX_AT_TX_LEN);//清空缓存sprintf((char *)TxetBuf,"{\"t\":3,\"datatype\":2,\"datas\":{\"alarm\":{\"%s\":%d},\"temp\":{\"%s\":%d}},\"msgid\":001}",TimeStr,sensor,TimeStr,sensor+1);//printf("%s\r\n",TxetBuf);if(ESP8266_IpSend((char *)TxetBuf, strlen((char *)TxetBuf)) < 0){//发送失败error=-1;}else{//发送成功for(TryGo = 0; TryGo<50; TryGo++)//最多等待时间50*10=500ms{if(strstr((const char *)AT_RX_BUF, (const char *)"\"status\":0") == NULL)//检查响应状态是否为"上报成功"{error = -1;}else{error = 0;break;}HAL_Delay(10);}}return error;
}

4、解析云平台数据函数

//解析服务器数据-----7uint8_t ESP8266_GetIpData(uint8_t *AtRxBuf, char *GetIpData)
{char *Point = NULL;uint8_t len = 0;Point = strstr((const char *)AtRxBuf, (const char *)"+IPD,");if(Point != NULL)//检查模块收到TCP/IP数据包?{len=(Point[5]-'0')*10+Point[6]-'0';//这里IP数据长度不会超过100,故可以按“个位”和“十位”计算收到的IP数据长度Point = strstr((const char *)AtRxBuf, (const char *)":")+1;memcpy(GetIpData, Point, len);GetIpData[len]='\0';printf("收到IP数据:%s\r\n",GetIpData);///printf("收到IP数据长度=%d\r\n",len);///}return (len);
}//对服务器下发的命令进行判断处理-----8
void USER_DataAnalysisProcess(char *RxBuf)
{char *cmdid = NULL;uint8_t TxetBuf[128];if(strstr((const char *)RxBuf, (const char *)PING_REQ) != NULL)//心跳请求?{if(ESP8266_IpSend((char *)PING_RSP, strlen((const char *)PING_RSP)) < 0)//响应心跳{//发送失败printf("发送心跳包失败!\r\n");}else{printf("心跳包!\r\n");}}else if(strstr((const char *)RxBuf, (const char *)"\"t\":5") != NULL)//命令请求?{if(strstr((const char *)RxBuf, (const char *)"\"apitag\":\"defense\"") != NULL)//布防/撤防请求{memset(TxetBuf,0x00,128);//清空缓存if((strstr((const char *)RxBuf, (const char *)"\"data\":1") != NULL))//布防{printf("布防!\r\n");;//...;//...;//...cmdid = USER_GetJsonValue((char *)RxBuf, (char *)"cmdid");sprintf((char *)TxetBuf,"{\"t\":6,\"cmdid\":%s,\"status\":0,\"data\":1}",cmdid);//printf("%s\r\n",TxetBuf);if(ESP8266_IpSend((char *)TxetBuf, strlen((char *)TxetBuf)) < 0){//发送失败printf("发送响应失败!\r\n");}}else if((strstr((const char *)RxBuf, (const char *)"\"data\":0") != NULL))//撤防{printf("撤防!\r\n");;//...;//...;//...cmdid = USER_GetJsonValue((char *)RxBuf, (char *)"cmdid");sprintf((char *)TxetBuf,"{\"t\":6,\"cmdid\":%s,\"status\":0,\"data\":0}",cmdid);//printf("%s\r\n",TxetBuf);if(ESP8266_IpSend((char *)TxetBuf, strlen((char *)TxetBuf)) < 0){//发送失败printf("发送响应失败!\r\n");}}}else if(strstr((const char *)RxBuf, (const char *)"\"apitag\":\"ctrl\"") != NULL)//开锁/关锁请求{memset(TxetBuf,0x00,128);//清空缓存if((strstr((const char *)RxBuf, (const char *)"\"data\":1") != NULL))//开锁{printf("开锁!\r\n");;//...;//...;//...cmdid = USER_GetJsonValue((char *)RxBuf, (char *)"cmdid");sprintf((char *)TxetBuf,"{\"t\":6,\"cmdid\":%s,\"status\":0,\"data\":1}",cmdid);//printf("%s\r\n",TxetBuf);if(ESP8266_IpSend((char *)TxetBuf, strlen((char *)TxetBuf)) < 0){//发送失败printf("发送响应失败!\r\n");}lock=1;}else if((strstr((const char *)RxBuf, (const char *)"\"data\":0") != NULL))//关锁{printf("关锁!\r\n");;//...;//...;//...cmdid = USER_GetJsonValue((char *)RxBuf, (char *)"cmdid");sprintf((char *)TxetBuf,"{\"t\":6,\"cmdid\":%s,\"status\":0,\"data\":0}",cmdid);//printf("%s\r\n",TxetBuf);if(ESP8266_IpSend((char *)TxetBuf, strlen((char *)TxetBuf)) < 0){//发送失败printf("发送响应失败!\r\n");}}}}
}

五、工程修改

由于代码量大,作为上课学生,只需要按照下面教程在我下发的工程基础上进行修改程序即可。

1、在CloudReference.h  修改wifi名称和密码

2、对云平台下发命令进行处理

    在stm32App.c 文件void USER_DataAnalysisProcess(char *RxBuf)函数中对下发命令做相应处理

方法:上面代码段是对云平台LED1下发的指令进行相应的处理:当云平台点击"开",则它会下发数据{"apitag":"LED1","cmdid":"96c80b17-a9d9-4169-9a22-a7ad07fd8e2f","data":1,"t":5} ,单片机收到后作打开开发板LED1操作;当云平台点击"关",则它会下发数据{"apitag":"LED1","cmdid":"3b698d9a-34fc-4448-b707-fec5de1da636","data":0,"t":5},单片机收到后作熄灭开发板LED1操作。如果对其它3个LED灯的命令解析,我们可以复制一份“else if”代码块,接在这代码块后。

五、实验效果

六、仿真实现


总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/837758.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】每日一题 17 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 可以使用回溯法来解决这个问题。首先定义一个映射关系将数字与字母对应起来…

Web开发三层架构

##Controller Service Dao(mapper) 软件设计&#xff1a;高内聚 低耦合 Controller 调用Service&#xff0c; Service调用 DAO 模块之间耦合 如果要从EmpServiceA切换到EmpServiceB&#xff0c;Controller代码也要修改 new EmpServiceB 分层接耦 容器中放EmpServiceA&am…

文本批量高效管理,一键删除前后第一行,轻松提升工作效率!

在信息爆炸的时代&#xff0c;文本处理成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;面对大量的文本数据&#xff0c;如何高效地进行批量管理&#xff0c;成为了许多人头疼的问题。今天&#xff0c;我们将向您介绍一种简单而高效的方法&#xff0c;让您轻松删除…

【UE5.1 角色练习】01-使用小白人蓝图控制商城角色移动

目录 效果 步骤 一、导入资源 二、控制角色移动 三、更换角色移动动作 效果 步骤 一、导入资源 新建一个工程&#xff0c;然后在虚幻商城中将角色动画的相关资源加入工程&#xff0c;这里使用的是“动画初学者内容包”和“MCO Mocap Basics” 将我们要控制的角色添加进…

搜索引擎的设计与实现(四)

目录 6 系统测试 6.1测试重要性 6.2测试用例 结 论 参 考 文 献 前面内容请移步 搜索引擎的设计与实现&#xff08;三&#xff09; 免费源代码&毕业设计论文 搜索引擎的设计与实现 6 系统测试 6.1测试重要性 该项目是在本地服务器上进行运行和调试&#xff0c;…

【从零开始学习Redis | 第十一篇】快速介绍Redis持久化策略

前言&#xff1a; Redis 作为一种快速、高效的内存数据库&#xff0c;被广泛应用于缓存、消息队列、会话存储等场景。然而&#xff0c;由于其特性是基于内存的&#xff0c;一旦服务器进程退出&#xff0c;内存中的数据就会丢失。为了解决这一问题&#xff0c;Redis 提供了持久…

IT技术产品:开发者极为重要的思维习惯

1、特色内容预告 1、我用敏捷开发思维&#xff0c;提高工作效率。 2、我用代码批判思维&#xff0c;逐渐让自己的作品变得无可挑剔。 3、我是一个顶级程序员&#xff0c;是哪些重要的专业习惯&#xff0c;让我如此优秀&#xff1f; 2、可以免费获取到的IT资源 1、《软件工程&a…

【嵌入式模块芯片开发】ADXL345的优化精确测量和角度计算(中断单次测量、卡尔曼滤波)

【嵌入式模块芯片开发】ADXL345的优化精确测量和角度计算&#xff08;中断单次测量、卡尔曼滤波&#xff09; 文章目录 ADXL345的一般读取方式ADXL345的中断读取方式&#xff08;单次测量&#xff09;角度计算卡尔曼滤波优化后完整代码附录&#xff1a;压缩字符串、大小端格式…

计算机vcruntime140.dll找不到如何修复,分享5种靠谱的修复教程

当您在运行某个应用程序或游戏时遇到提示“找不到vcruntime140.dll”&#xff0c;这通常意味着系统中缺少了Visual C Redistributable for Visual Studio 2015或更高版本的一个重要组件。这个错误通常发生在运行某些程序时&#xff0c;系统无法找到所需的动态链接库文件。小编将…

手撸XXL-JOB(三)——本地定时任务管理平台

引言 在XXL-JOB中&#xff0c;有一个xxl-job-admin项目&#xff0c;这个就相当于定时任务的调度平台&#xff0c;我们参考XXL-JOB&#xff0c;也添加这么一个调度平台&#xff0c;由于篇幅有限&#xff0c;我们先实现一个本地的定时任务调度平台&#xff0c;至于如何调用远程的…

算法练习day8

反转字符串 代码随想录 0344.反转字符串 344. 反转字符串 - 力扣&#xff08;LeetCode&#xff09; &#xff08;用时&#xff1a;0.05小时&#xff09; 思路 这道题很简单也很经典。 字符串的反转方法有很多&#xff0c;我这里是用for循环通过数组长度和下标计算来交换。…

【小积累】@Qualifier注解

今天在看rabbitMQ的时候需要绑定交换机和队列&#xff0c;交换机和队列都已经注入到spring容器中&#xff0c;写了一个配置类&#xff0c;使用了bean注解注入的。所以这时候绑定的时候需要使用容器中的交换机和队列&#xff0c;必须要使用Qualifier去确定是容器中的哪个bean对象…

【Unity Shader入门精要 第7章】基础纹理补充内容:MipMap原理

1.纹理采样 我们对纹理采样进行显示的过程&#xff0c;可以理解为将屏幕上的一个像素&#xff08;下文用像素表示&#xff09;映射到纹理上的一个像素&#xff08;下文用纹素表示&#xff09;&#xff0c;然后用纹理上的这个像素的颜色进行显示。 理想情况下&#xff0c;屏幕…

Optional用法

说明&#xff1a;Optional和Stream一样&#xff0c;是Java8引入的特性&#xff0c;本文介绍Optional的几个实际用法。Steam流使用&#xff0c;参考下面这篇文章&#xff1a; Stream流使用 使用 1.保证值存在 // 1.保证值存在&#xff0c;pageNumber&#xff0c;pageSizeInte…

HTTP基础概念和HTTP缓存技术

什么是HTTP HTTP是超文本传输协议&#xff0c;主要分为三个部分&#xff1a;超文本、传输、协议。 超文本是指&#xff1a;文字、图片、视频的混合体。传输是指&#xff1a;点与点之间的信息通信。协议是指&#xff1a;通信时的行为规范或约定 HTTP常见字段 字段名 解释 例…

图片标签 以及 常见的图片的格式

1.图片的基本使用 2.图片的常见格式 3.bmp格式

前端已死? Bootstrap--JS-jQuery

目录 Bootstrap--JS-jQuery 1 jQuery基础 介绍 基础语法&#xff1a; $(selector).action() 1.1 安装jQuery 地址 基础语法&#xff1a; $(selector).action() 2 jQuery事件 事件处理程序指的是当 HTML 中发生某些事件时所调用的方法。 jQuery常用事件 2.1 鼠标事件…

element-ui的表单中,输入框、级联选择器的长度设置

使用<el-col>控制输入框的长度 <el-form-item label"姓名" label-width"80px"><el-col :span"15"><el-input v-model"form.name" autocomplete"off"></el-input></el-col></el-form…

AI助力内容创作:让效率与质量齐飞

简述&#xff1a; 本文介绍了AI如何帮助创作者在保持内容质量的同时&#xff0c;大幅度提升生产效率的一些方法&#xff0c;希想 对大家有帮助。 一、自动化内容生成 1. 文本内容生成 使用GPT等模型&#xff1a;利用如GPT-3或GPT-4等大型语言模型&#xff0c;可以直接输入关…

[译文] 恶意代码分析:2.LNK文件伪装成证书传播RokRAT恶意软件(含无文件攻击)

这是作者新开的一个专栏&#xff0c;主要翻译国外知名安全厂商的技术报告和安全技术&#xff0c;了解它们的前沿技术&#xff0c;学习它们威胁溯源和恶意代码分析的方法&#xff0c;希望对您有所帮助。当然&#xff0c;由于作者英语有限&#xff0c;会借助LLM进行校验和润色&am…