物联网应用开发--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要连接的热点名称和密码  -----2

int8_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连接  -----3

int8_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连接  -----4

int8_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; 	
}


//连接到服务器  -----5

int8_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;
}

//发送传感数据到服务器 -----6

int8_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、解析云平台数据函数

//解析服务器数据-----7

uint8_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”代码块,接在这代码块后。

五、实验效果

六、仿真实现


总结

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CodeGeeX 智能编程助手 6 项功能升级,在Visual Studio插件市场霸榜2周!

CodeGeeX是支持适配Visual Studio 2019的唯一一款国产智能辅助编程工具&#xff0c;已经在Visual Studio趋势上霸榜2周&#xff01; CodeGeeX v1.0.4版本上线Visual Studio插件市场&#xff0c;带来了多项新功能和性能优化&#xff0c;提升编程体验。 新功能亮点速览&#xf…

用面向对象的思想编写实时嵌入式C程序

实时嵌入式系统的软件一般由C语言编写&#xff0c;程序结构基本上都是这样的&#xff1a; // 主程序 int main(void) {init(); // 初始化while(1){tick(); // 业务逻辑}return 0; }// 计时器 static unsigned int g_timer_tick_cnt 0; // 时钟中断回调 void isr_time…

Docker 基础认识

文章目录 概念铺垫&#xff08;1&#xff09;概念铺垫&#xff08;2&#xff09;概念铺垫 &#xff08;3&#xff09;概念铺垫&#xff08;4&#xff09;Docker 定义Docker 特点Docker 架构 概念铺垫&#xff08;1&#xff09; 虚拟化相关概念 物理机&#xff1a;实际的服务器…

【前端】CSS基础(2)

文章目录 前言1、CSS选择器1.1选择器的功能1.2 选择器的种类1.2.1 基础选择器1.2.1.1 标签选择器1.2.1.2 类选择器1.2.1.3 id选择器1.2.1.4 通配符选择器1.2.1.5 伪类选择器 1.2.2 复合选择器1.2.2.1 后代选择器1.2.2.2 子选择器1.2.2.3 并集选择器 前言 这篇博客仅仅是对CSS的…

vue3自定义指令​(通过指令钩子获得dom和钩子参数)

实现文本框自动获得焦点 Index.vue: <script setup> import { ref, onMounted } from vue import ./index.cssconst vFocus {mounted: (el, binding) > {el.focus()console.log(binding)} }onMounted(() > {}) </script><template><div class&qu…

JSPfilters过滤技术

1.创建动态web项目 2.创建filters的文件 3.创建主页面 4.配置xml项目 总结构 主页面代码 <% page language"java" contentType"text/html; charsetUTF-8"pageEncoding"UTF-8"%><!DOCTYPE html><html><head><meta cha…

C++学习第二十九课:C++ 输入输出流详解:从基础到高级应用

在 C 中&#xff0c;流&#xff08;stream&#xff09;是一种用于实现输入输出操作的抽象概念。流可以看作是字节的流动&#xff0c;这些字节可以从一个地方流向另一个地方&#xff0c;例如从键盘输入到程序中&#xff0c;或者从程序输出到屏幕。C 提供了一套完整的流库来处理各…

灵卡科技HDMI音视频采集及H.264编码一体化采集卡—LCC260

推荐一款由灵卡科技倾力打造的高品质HDMI音视频采集卡——LCC260。以创新的技术&#xff0c;精湛的工艺和卓越的性能&#xff0c;为您提供全方位的音视频解决方案。 LCC260是一款集HDMI音视频采集与H.264编码于一身的全功能采集卡。它的输入端配备了最先进的HDMI 1.4a标准接口&…

扩散模型diffusion model

一 什么是扩散模型 1.1 现有生成模型 已经有大量的方法证明深度生成模型能够模拟人类的想象思维&#xff0c;生成人类难以分辨真伪的内容&#xff0c;主要方法如下&#xff1a; 1、GAN&#xff1a;用神经网络训练生成器和判别器 GAN 的主要思想&#xff1a; GAN 就是一个互搏的…

ChatGPT-4o发布了,所有人都可以免费用

前言 美国时间 5 月 13 日&#xff0c;在 Sam Altman 缺席的情况下&#xff08;为什么缺席&#xff0c;猜测是可能后面还有更重磅的消息&#xff0c;这次的产品只是一个中间过渡产品&#xff09;&#xff0c;OpenAI CTO Mira Murati 介绍了新的 ChatGPT 产品 ChatGPT-4o。这个…

go语言基础1

1.token token是构成源程序的基本不可在分割单元。编译器编译源程序的第一步就是将源程序分割为一个个独立的token&#xff0c;这个过程就是词法分析。Go语言的token可以分为关键字、标识符、操作符、分隔符和字面常量等&#xff0c;如图所示&#xff1a; Go token分隔符有两类…

Vscode编辑器 js 输入log自动补全

最近换了新电脑&#xff0c;新下载了Vscode&#xff0c;记录一下设置项。 Vscode 版本 想要的效果 js文件中输入log&#xff08;点击tab键&#xff09;&#xff0c;自动补全为 console.log() Vscode 文件》首选项》设置 搜索&#xff1a;snippets Emmet: Show Suggestions…

计算机毕业设计源码 | 基于SpringBoot的线上教学系统 答疑辅导网站(附源码)

1&#xff0c;项目介绍 1.1 项目背景 网络问答平台经历了多年的发展&#xff0c;目前处于一个日益成熟的状态。最早的网络问答平台是知乎&#xff0c;知乎的创立者认为有许多信息在互联网上没有被记录和共享&#xff0c;于是他们决定创造一个平台&#xff0c;能够让更多人可以…

【强训笔记】day22

NO.1 思路&#xff1a;将情况全部枚举出来。 代码实现&#xff1a; #include <iostream> #include<string> using namespace std;string a,b; int main() {cin>>a>>b;int ma.size(),nb.size();int retm;for(int i0;i<n-m;i){int tmp0;for(int j…

软文撰写注意事项有哪些?

软文&#xff0c;作为一种隐性的广告形式&#xff0c;越来越受到企业的青睐。一篇高质量的软文&#xff0c;不仅能吸引读者的眼球&#xff0c;还能在潜移默化中传递品牌价值。撰写一篇高质量的软文&#xff0c;并非一蹴而就。从开头到发布&#xff0c;每一个环节都需要精心打磨…

Charger之二输入电压动态电源原理(VIN-DPM)

主要内容 Charger的VIN-DPM 前篇内容&#xff1a;电池管理IC&#xff08;Charger&#xff09;了解一下&#xff1f; 领资料&#xff1a;点下方↓名片关注回复&#xff1a;粉丝群 正文 一、 VIN-DPM概念 VIN-DPM是指输入电压动态电源管理&#xff08;Input voltage dynamic…

C++ QT设计模式 (第二版)

第3章 Qt简介 3.2 Qt核心模块 Qt是一个大库&#xff0c;由数个较小的库或者模块组成&#xff0c;最为常见的如下&#xff1a;core、gui、xml、sql、phonon、webkit&#xff0c;除了core和gui&#xff0c;这些模块都需要在qmake的工程文件中启用 QTextStream 流&#xff0c;Qdat…

表现孤独的短视频:成都鼎茂宏升文化传媒公司

表现孤独的短视频&#xff1a;孤独之美与心灵的对话 在短视频的浪潮中&#xff0c;有一种特殊的情感表达形式逐渐崭露头角——那就是表现孤独的短视频。这些视频以其独特的视角和深刻的情感内涵&#xff0c;引发了广大观众的共鸣。表现孤独的短视频&#xff1a;成都鼎茂宏升文…

activiti——网关配置

文章目录 前言网关介绍代码案例测试各项网关排他网关 ExclusiveGateway1、绘制流程图2、编写测试代码 并行网关ParallelGateway1、绘制流程图2、编写测试代码 包含网关InclusiveGateway1、绘制流程图2、编写测试代码 前言 在activiti工作流中&#xff0c;还有一个组件也很重要…

代码随想录算法训练营第五十三天

今天同事说他要离职啦&#xff0c;还挣挺多的&#xff0c;我也慢慢努力吧&#xff01;&#xff01; 儿子似乎有点斜颈&#xff0c;还好不是很大的病&#xff0c;儿子也开始面对人生的苦难啦。都好好加油生活&#xff01; 1143.最长公共子序列 二维可以理解一点。 class Solut…