STM32通过esp8266连接WiFi接入MQTT服务器

news2024/12/27 12:36:23

上文我们讲到如何搭建本地MQTT服务器,现在介绍如何通过stm32连接MQTT

一.首先我们初始化esp8266这里我们使用的是USART4与其通信代码如下

void UART4_Init(uint32_t bound)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	
	 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);	//使能UART4,GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	
	USART_DeInit(UART4);  //复位串口4
	
	//UART4_TX   PC.10 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化PC10
   
	//UART4_RX	  PC.11
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_Init(GPIOC, &GPIO_InitStructure);  //初始化PC11

	//USART 初始化设置
	USART_InitStructure.USART_BaudRate = bound;	//设置波特率,一般设置为9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;	//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;	//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;	//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;	//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
	
	USART_Init(UART4, &USART_InitStructure); //初始化串口
	USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);//开启中断
	USART_Cmd(UART4, ENABLE);                    //使能串口 


	TIM7_Int_Init(100-1,7200-1);		//10ms 为了判断是不是一串数据后文有解释

	TIM_Cmd(TIM7,ENABLE);			//
}

二.通过数据间隔时间来判断是否是一串数据如果间隔时间大于30ms则判定为不是一串数据,接收缓冲器清零。 代码如下!

//定时器7中断服务程序		    
void TIM7_IRQHandler(void)
{ 	
	if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)//是更新中断
	{
	
		TIM_ClearITPendingBit(TIM7, TIM_IT_Update  );  //清除TIM7更新中断标志    
	    if(F_UART4_RX_RECEIVING)//正在接收串口数据
		{
			UART4_RX_TIMEOUT_COUNT++;//串口超时计数
			if(UART4_RX_TIMEOUT_COUNT>3)//数据接收间隔超过30ms
			{//串口接收完成或结束
				F_UART4_RX_RECEIVING=0;
				UART4_RX_TIMEOUT_COUNT=0;
				F_UART4_RX_FINISH=1;
			}
		}
	}	    
}
 

//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz 
//通用定时器中断初始化
//这里始终选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数		 
void TIM7_Int_Init(u16 arr,u16 psc)
{	
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);//TIM7时钟使能    
	
	//定时器TIM7初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE ); //使能指定的TIM7中断,允许更新中断
	
	TIM_Cmd(TIM7,ENABLE);//开启定时器7
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
}

三.初始化esp8266后我们就可以连接WiFi及mqtt了

 首先我们将esp8266设置为station模式,如果返回ok则设置成功

代码如下:

#define AT_CWMODE	"AT+CWMODE=1" //设置为“station”模式
int8_t ESP8266_SetStation(void)
{
	ClrAtRxBuf();//清空缓存
	SendAtCmd((uint8_t *)AT_CWMODE,strlen(AT_CWMODE));
	delay_ms(100);
	if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
	{
		return -1;
	}
	return 0;
}

四.设置成功之后就可以连接WiFi(可以是路由器也可以是手机或电脑开热点)

代码如下:

/*******************************************************************
*函数:int8_t ESP8266_SetAP(void)
*功能:设置ESP8266要连接的热点名称和密码
*输入:char *wifi-热点名称 char *pwd-热点密码
*输出:
		return = 0 ,sucess
		return < 0 ,error
*特殊说明:
*******************************************************************/
#define WIFI_AP		"dmx"//WiFi热点名称       
#define WIFI_PWD	"88888888"	//WiFi密码

int8_t ESP8266_SetAP(void)
{
	uint8_t AtCwjap[MAX_AT_TX_LEN];
	memset(AtCwjap, 0x00, MAX_AT_TX_LEN);//清空缓存
	ClrAtRxBuf();//清空缓存
	sprintf((char *)AtCwjap,"AT+CWJAP=\"%s\",\"%s\"",WIFI_AP, WIFI_PWD	);
	SendAtCmd((uint8_t *)AtCwjap,strlen((const char *)AtCwjap));
	delay_ms(5500);
	if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
	{
		return -1;
	}
	return 0;
}

五.现在就已经成功连接WiFi了下一步连接本地mqtt服务器(上篇博客我教大家如何搭建的)

#define SERVER_PC_IP	"172.16.40.36"	//服务器IP地址
#define SERVER_PC_PORT	1883			//服务器端口号   
int8_t ESP8266_IpStart(void)
{
	uint8_t IpStart[MAX_AT_TX_LEN];
	memset(IpStart, 0x00, MAX_AT_TX_LEN);//清空缓存
	ClrAtRxBuf();//清空缓存
	
	/**************配置MQTT_USER信息***************/
	//AT+MQTTUSERCFG=0,1,"用户ID","账号","密码",0,0,""
	                       //AT+MQTTUSERCFG=0,1,\"M3\",\"\",\"\",0,0,\"\"
	sprintf((char *)IpStart,"AT+MQTTUSERCFG=0,1,\"M3\",\"\",\"\",0,0,\"\"");
	SendAtCmd((uint8_t *)IpStart,strlen((const char *)IpStart));
	delay_ms(1500);
	printf("IpStart-USER_Config: %s\r\n", (char *)AT_RX_BUF);
	if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
	{
		/******断开连接*****/
		memset(IpStart, 0x00, MAX_AT_TX_LEN);//清空缓存
		ClrAtRxBuf();//清空缓存
		
		//AT+MQTTCLEAN=0
		sprintf((char *)IpStart,"AT+MQTTCLEAN=0");
		
		SendAtCmd((uint8_t *)IpStart,strlen((const char *)IpStart));
		
		return -1;
	}
	
	/**************建立MQTT连接***************/
	memset(IpStart, 0x00, MAX_AT_TX_LEN);//清空缓存
	ClrAtRxBuf();//清空缓存
	
	//AT+MQTTCONN=0,"服务器IP",1883,0
	//AT+MQTTCONN=0,"172.16.40.36",1883,0
	sprintf((char *)IpStart,"AT+MQTTCONN=0,\"%s\",%d,0",SERVER_PC_IP, SERVER_PC_PORT	);
	
	SendAtCmd((uint8_t *)IpStart,strlen((const char *)IpStart));
	delay_ms(1500);
	printf("IpStart-MQTT_Connect: %s\r\n", (char *)AT_RX_BUF);
	if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
	{
		return -2;
	}
	
	return 0;
}

六.经过以上五步就已经成功连接mqtt服务器了。现在通过命令设置自己为订阅者

int8_t ESP8266_MQTT_Sub(char *topic) //主题自己设置
{
	int8_t error = 0;
	uint8_t IpSend[MAX_AT_TX_LEN];
	memset(IpSend, 0x00, MAX_AT_TX_LEN);//清空缓存
	ClrAtRxBuf();//清空缓存
	
	
	//AT+MQTTSUB=0,M3",0
	sprintf((char *)IpSend,"AT+MQTTSUB=0,\"%s\",1", topic);
	SendAtCmd((uint8_t *)IpSend,strlen((const char *)IpSend));
	delay_ms(1500);
	printf("MQTT_Sub_Ack: %s\r\n",AT_RX_BUF);
	if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
	{
		return -4;
	}
	
	return error;
}

在这里我们通过mqtt.fx同样连接本地搭建的服务器,作为一个发布者发送消息stm32就能收到了。不过此处还没写收到信息的代码

七.stm32作为发布者者代码,这边你可以开一个mqtt.fx订阅相同的主题就能收到消息了

int8_t ESP8266_MQTT_Pub(char *IpBuf, uint8_t len, uint8_t qos)//信息 消息长度 以及qos(百度)
{
	uint8_t TryGo = 0;
	int8_t error = 0;
	uint8_t IpSend[MAX_AT_TX_LEN];
	memset(IpSend, 0x00, MAX_AT_TX_LEN);//清空缓存
	ClrAtRxBuf();//清空缓存
	/************设置为MQTT_Binary发送模式************/
/*   注意----------dmx为发布的主题-----------*/
	sprintf((char *)IpSend,"AT+MQTTPUBRAW=0,\"dmx\",%d,%d,0", len, qos);
	//printf("%s\r\n",IpSend);
	SendAtCmd((uint8_t *)IpSend,strlen((const char *)IpSend));
	delay_ms(100);
	//注意--如果断开连接或者怎么样,这一步ESP8266就会返回ERROR
	if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
	{
		printf("MQTT_Pub Fail:%s\r\n", AT_RX_BUF);
		MQTTSendErrorTimes++;
		return -1;
	}
	
	ClrAtRxBuf();//清空缓存
	
	//以二进制数据形式发送字符串
	SendAtCmd((uint8_t *)IpBuf, len);
	printf("MQTT_Pub: %s\r\n", IpBuf);
	if(qos == 0){
		return 0;
	}
	
	//等待qos回执处理
	delay_ms(100);
	if(strstr((const char *)AT_RX_BUF, (const char *)"OK") == NULL)
	{
		MQTTSendErrorTimes++;
		return -2;
	}
	return error;
}

八.到这里,完成的步骤已经完成,由于篇幅有限,很多细节也讲不完,如果有什么问题可以评论区留言,最后我附一个搭建好的mqtt的一个简易智能家居!可以读取各种传感器器数据,如温湿度,光照,烟雾溶度等上传给服务器,风扇 PWM灯也可以被服务器传来的数据控制。

 

 最后如果想要源码的可以评论区留言或者私信博主!希望大家多支持一下就行!!!

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

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

相关文章

高通 Camera HAL3:添加一条PipeLine

一.概述 添加一条PipeLine实现两路Raw进&#xff0c;一路Raw出 二.简介 要添加的PipeLine&#xff1a;SWMFMergeRawTwo2One 包含1个memcpy node&#xff0c;这个node用于将2个raw buffer input输入 变为 1个raw buffer output输出 三.添加 3.1 在相应的Usecase下添加一个p…

Spring Cloud Alibaba - Nacos源码分析(一)

目录 一、源码 1、为什么要分析源码 2、看源码的方法 二、Nacos服务注册与发现源码剖析 1、Nacos核心功能点 2、Nacos服务端/客户端原理 2.1、nacos-example 2.2、Nacos-Client测试类 3、项目中实例客户端注册 一、源码 1、为什么要分析源码 1. 提升技术功底&#x…

NB使用MQTT连接格物平台

内容简介&#xff1a; 本文主要记述了怎么使用NB-IoT模块&#xff0c;采用MQTT协议连接联通的格物平台&#xff0c;并且实现单属性和多属性数据的上报。 1 创建产品 打开格物平台&#xff0c;进行注册登录&#xff1b;之后点击页面的控制台&#xff0c;进入设备管理引擎&#x…

爬取中文新闻+正向、逆向最大匹配算法分词+算法优化+P、R、F值评估(完整详细过程+Python源码)

如标题所示&#xff0c;本文旨在记录这次分词实验&#xff0c;将主要从以下四点展开&#xff1a; 1、新闻文本的获取&#xff08;完整爬虫过程&#xff09; 爬取新闻网站中多个板块的新闻&#xff0c;这里建议可以多爬一些板块&#xff0c;保证新闻内容主题丰富&#xff0c;分…

计算机网络 - 移动网络

Wireless links and network Characterstics 无线网络信号会衰减很快, 会被别的source影响, 传播过程中经历多个路径比如经过建筑, 树木等收到影响. 所以就有了信噪比的概念 CDMA CDMA是一种在多点连接时候避免collision的一种算法. 主要是每个sender都用不同的编码, 然后se…

chatgpt赋能python:Python声音处理入门指南

Python声音处理入门指南 如果你是一个音乐爱好者或者处理声音的工程师&#xff0c;Python语言是值得你考虑的一种工具&#xff0c;它拥有丰富的库&#xff0c;可以帮助你在声音分析、编辑、压缩和转换等方面做出成果。 Python声音处理库 Python语言拥有一个大量的声音处理库…

电脑通过VNC连接树莓派

0. 实验准备 VNC软件 VNC Viewer 或者 MobaXterm&#xff08;安装包点击即可下载&#xff09; 可以使用SSH登录进去或者有屏幕的树莓派 一台可以使用的电脑 树莓派和电脑连接在同一个局域网下 0.5 树莓派的公共操作 打开树莓派的 VNC 功能 有屏幕的 打开 VNC 功能&#xff…

日志框架 --- Logback

文章目录 1. 什么是logback2. logback的日志级别3. 日志级别的层级4. logback配置文件4.1 logger标签4.2 root标签4.3 appender标签4.4 filter标签4.5 encoder标签 5. 整体演示5.1 配置文件5.2 运行结果 1. 什么是logback Logback是一个用于Java应用程序的日志框架&#xff0c…

android 如何分析应用的内存(三)

android 如何分析应用的内存&#xff08;三&#xff09; 接上文 细节部分包括如下 native部分 寄存器内容是什么。如pc指向何处&#xff0c;sp指向何处指定地址内容是什么。如变量a对应的内容线程堆栈内容是什么。如主线程的堆栈&#xff0c;UI线程的堆栈堆区的对象有哪些。…

图像边缘提取

什么是图像边缘: 图象的边缘是指图象局部区域亮度变化显著的部分&#xff0c;该区域的灰度剖面一般可以看作是一个阶跃&#xff0c;既从一个灰度值在很小的缓冲区域内急剧变化到另一个灰度相差较大的灰度值。 什么是灰度值: 指图像中点的颜色深度&#xff0c;范围一般从0到255…

C/C++性能提升之cache分析

在开发过程中&#xff0c;我们有时会碰到程序性能瓶颈&#xff0c;这时候需要我们查找热点代码&#xff0c;借用一些命令、工具去分析自己的程序&#xff0c;下面我就介绍一下如何使用perf工具分析程序的cache命中率。 在编写代码前先介绍一下我们的硬件平台&#xff0c;我电脑…

【LeetCode全题库算法速练】2、两数相加

文章目录 一、题目&#x1f538;题目描述&#x1f538;样例1&#x1f538;样例2&#x1f538;样例3 二、代码参考 作者&#xff1a;KJ.JK &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &a…

chatgpt赋能python:Python多行代码一行展示:精简代码,高效编程的绝佳选择

Python多行代码一行展示&#xff1a;精简代码&#xff0c;高效编程的绝佳选择 介绍 在Python的开发中&#xff0c;我们经常需要编写较长的代码&#xff0c;在展示和调试代码时&#xff0c;多行代码会使代码显得过长和复杂。同时&#xff0c;多行代码还会增加代码中的空白行数…

chatgpt赋能python:Python处理颜色RGB简介

Python 处理颜色 RGB 简介 在现代 Web 设计中&#xff0c;颜色的使用非常重要。网站和应用程序的设计师通常需要控制经他们的项目中使用的颜色。最常见的颜色表示方法是 RGB&#xff0c;即红、绿、蓝。RGB 是一种添加光线颜色的方法&#xff0c;它基于红、绿和蓝三种颜色原料的…

Linux操作系统——第一章 进程

目录 基本概念 描述进程-PCB task_struct-PCB的一种 task_ struct内容分类 组织进程 查看进程 通过系统调用获取进程标示符 通过系统调用创建进程-fork初识 进程状态 进程状态查看 Z(zombie)-僵尸进程 僵尸进程危害 孤儿进程 进程优先级 基本概念 查看系统进程 …

【RestAPI】优秀Rest API设计规范

一、API 设计原则 将 REST 映射到 DDD 模式 实体、聚合和值对象等模式旨在对领域模型中的对象施加特定的约束。 在 DDD 的许多介绍文章中&#xff0c;模式是使用构造函数或属性 getter 和 setter 等面向对象的 (OO) 语言概念建模的。 设计 API 时&#xff0c;请考虑这些 API…

前后端分离的前端部署渲染方案总结

前后端分离主要是为了区分后端和前端&#xff0c;以前前端代码是直接将HTML和静态文件丢给后端&#xff0c;由后端完成数据动态交互&#xff0c;所以后端既要写后端逻辑&#xff0c;又要写前端的数据交互逻辑。 前后端分离后后端只需要提供接口&#xff0c;前端则必须要完成对…

安装lora+启动lora+训练一个model

一、安装步骤 conda create -n kohya_ss python3.10.8 cd code git clone https://github.com/bmaltais/kohya_ss.git cd kohya_ss 然后修改了setup.sh里面的xformers里面的下载地址&#xff08;因为自带的那个地址&#xff0c;拉取需要1个小时&#xff0c;太慢了&#xff09;…

chatgpt赋能python:Python基础词汇解析

Python基础词汇解析 作为一门流行且易学的编程语言&#xff0c;Python在很多场合得到了广泛的应用。在学习Python编程的过程中&#xff0c;掌握各类基础词汇是非常关键的。本文将介绍Python编程中一些常见且重要的基础词汇&#xff0c;帮助大家更好地了解和掌握Python编程。 …

chatgpt赋能python:Python多级雷达图绘制解析

Python多级雷达图绘制解析 雷达图&#xff08;Radar Chart&#xff09;是一种可视化工具&#xff0c;常用于多个指标的对比展示。与其他图形不同&#xff0c;雷达图中&#xff0c;数据不是放在X、Y轴上&#xff0c;而是以多边形的形式展现。利用Python语言&#xff0c;可以绘制…