物联网应用开发--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.rhkb.cn/news/327598.html

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

相关文章

SpringCloud2024最新版链路追踪教程micrometer+zipkin

本文基于B站尚硅谷2024版springcloud教学视频&#xff0c;主要用于自己学习记录以及分享技术&#xff0c;侵权私删 自己本机环境信息&#xff1a; jdk&#xff1a;17.0.10springboot&#xff1a;3.2.0springcloud&#xff1a;2023.0.0 micrometer 之前行业内使用的分布式链路…

tomcat--目录结构和文件组成

目录结构 目录说明bin服务启动&#xff0c;停止等相关程序和文件conf配置文件lib库目录logs日志记录webapps应用程序&#xff0c;应用部署目录workjsp编译后的结果文件&#xff0c;建议提前预热访问 /usr/local/apache-tomcat-8.5.100/work/Catalina/localhost/ROOT/org/apac…

《四》系统模块整体功能关联与实现

在上一篇里&#xff0c;我们完成了动作的创建&#xff0c;那么这一次&#xff0c;我们把它加载到界面上&#xff0c;把需要是实现的动作都加上。 MyWord::MyWord(QWidget *parent): QMainWindow(parent) {mdiAreanew QMdiArea;mdiArea->setHorizontalScrollBarPolicy(Qt::S…

对关系型数据库管理系统的介绍

1.数据库的相关介绍 关系型数据库管理系统&#xff1a;&#xff08;英文简称&#xff1a;RDBMS&#xff09; 为我们提供了一种存储数据的特定格式&#xff0c;所谓的数据格式就是表&#xff0c; 在数据库中一张表就称为是一种关系. 在关系型数据库中表由两部分组成&#xf…

ZL-016D多通道小鼠主动跑轮系统主要研究动物生活节律

简单介绍&#xff1a; 多通道小鼠主动跑轮系统是由动物本身自发运动来推动跑轮转动。在这种构型中&#xff0c;笼内动物长期活动的信息&#xff0c;如跑轮转动方向、转数、累计总行程等&#xff0c;能够使用编码器进行长度计记录。此装置由转轮组件、笼体、以及转动方向速度传…

【LeetCode刷题】136.只出现一次的数字(Ⅰ)

【LeetCode刷题】136.只出现一次的数字&#xff08;Ⅰ&#xff09; 1. 题目&#xff1a;2.思路分析&#xff1a;思路1&#xff1a;一眼异或&#xff01; 1. 题目&#xff1a; 2.思路分析&#xff1a; 思路1&#xff1a;一眼异或&#xff01; 看到题目&#xff0c;如果有一定基…

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

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

【Ajax零基础教程】-----第四课 简单实现

一、XMLHttpRequest对象 通过XMLHttpRequest对象来向服务器发送异步请求&#xff0c;从服务器获取数据。然后用JavaScript来操作DOM而更新页面。XMLHttpRequest是ajax的核心机制&#xff0c;它是IE5中首先引入的&#xff0c;是一种支持异步请求的技术。 简单的说&#xff0c;也…

leetcode算法笔记-算法复杂度

对于时间复杂度&#xff0c;主要包括三种情况&#xff1a; 渐进紧确界&#xff1a; O渐进上界&#xff1a; 渐进下界&#xff1a; 加法原则&#xff1a;不同的时间复杂度相加取阶数最高的 乘法原则&#xff1a;不同的时间复杂度相乘&#xff0c;结果为时间复杂度的乘积 阶乘…

古月居讲师/签约作者招募计划

机器人&#xff0c;作为一个集成了多学科技术的复杂系统&#xff0c;其开发过程充满了挑战。为了帮助开发者们更好地克服这些挑战&#xff0c;提升项目的开发效率和质量&#xff0c;古月居特别招募[博客签约作者/课程讲师]。如果您平常热爱记录、分享开发者经验的习惯&#xff…

数据分离和混淆矩阵的学习

1.明确意义 通过训练集建立模型的意义是对新的数据进行准确的预测&#xff08;测试集的准度高才代表good fit&#xff09;&#xff1b; 2.评估流程 3.单单利用准确率accuracy进行模型评估的局限性 模型一&#xff1a;一共1000个数据&#xff08;分别为900个1和100个0&#x…

代码审计平台sonarqube的安装及使用

docker搭建代码审计平台sonarqube 一、代码审计关注的质量指标二、静态分析技术分类三、使用sonarqube的目的四、sonarqube流程五、docker快速搭建sonarqube六、sonarqube scanner的安装和使用七、sonarqube对maven项目进行分析八、sonarqube分析报告解析九、代码扫描规则定制十…

Docker 使用 Fedora 镜像

Fedora 在 Docker 中的使用也非常简单&#xff0c;直接使用命令 docker run -it fedora:latest bash 就可以 pull 到本地的容器中并且运行。 C:\Users\yhu>docker run -it fedora:latest bash Unable to find image fedora:latest locally latest: Pulling from library/fed…

数据库笔记-【视图】

视图 视图通俗是企业想展示给用户看的&#xff0c;数据库存储的数据有很多&#xff0c;但是也有很多是不能对外公开的&#xff0c;做项目的过程就通过视图这个媒介达到这种效果 视图也可以保证数据库表结构字段的隐私安全等 create or replace view stu_v_1 as select id st…

C#反编译太容易了,转qt怎么样?

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「qt的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;方案1&#xff1a;随机报错 反编都…

LoRA Land: 310个经微调的大语言模型可媲美GPT-4

摘要 低秩自适应 (LoRA) 已成为大语言模型 (LLM) 参数有效微调 (PEFT) 中最广泛采用的方法之一。LoRA 减少了可训练参数的数量和内存使用,同时达到了与全面微调相当的性能。该研究旨在评估在实际应用中训练和服务使用 LoRA 微调的 LLM 的可行性。首先,该研究测量了在 10 个基础…

如何使用恢复模式修复Mac启动问题?这里提供详细步骤

如果你的Mac无法启动,不要惊慌,Mac有一个隐藏的恢复模式,你可以使用它来诊断和修复任何问题,或者在需要时完全重新安装macOS。以下是如何使用它。 如何在Mac上启动到恢复模式 你需要做的第一件事是启动到恢复模式。尽管操作说明会因你使用的Mac电脑而异,但幸运的是,启动…

postman 使用教程

1. get 请求 &#xff1f;号后为 get 请求的参数 参数之间用符号"&" 分隔。 假设url 为&#xff1a;http://10.71.7.101/cgi-bin/gw-config.cgi?methodgetway_param&t1715658871647 复制进来到postman的地址栏 后 &#xff1f;后面的参数会自动添加到参…

kali linux2024.1版安装

1 基于 VMware 安装 Kali 系统 打开已经安装好的 VMware 程序&#xff0c;点击选项卡中的“主页”--》而后点击“创建新的虚拟机” 选择“典型(推荐)”&#xff0c;并点击“下一步” 客户机操作系统镜像选择&#xff1a;选择“稍后安装操作系统”&#xff0c;并点击“下一步”…

C#窗体程序设计笔记:如何调出控件工具箱,并设置控件的属性

文章目录 调出控件工具箱设置控件属性 调出控件工具箱 使用Visual Studio打开C#解决方案后&#xff0c;初始界面如下图所示&#xff1a; 接着&#xff0c;在上方的菜单栏依次选择“视图”“工具箱”&#xff0c;即可打开工具箱&#xff0c;如下图所示&#xff1a; 设置控件属…