stm32与esp8266WIFI模块

news2024/10/7 1:26:05

硬件介绍

WIFI模块ESP-01S

使用AT指令控制1-ESP8266-AT指令初试化及部分基础知识_ch_pd-CSDN博客

项目需求

通过ESP-01SWIFI模块控制LED状态模拟插座

串口1用于与ESP8266通讯,串口2连接PC,用于打印log,查看系统状态

项目接线

WIFI模块TXRX分别接到单片机的RX1和TX1

CH340TXDRXD分别接到单片机的RX2和TX2

项目注意事项 

1. 在这个项目里,烧写完单片机之后,不光要点击复位,还要重启单片机电源,以确保WIFI模块重新启动

2. 在以后的工作中一般不直接在中断服务函数里处理数据,而是在收到数据后直接丢给队列,再处理数据

3. 在中断服务函数里尽量减少使用延时函数及打印函数

4. 2,3条在本项目中并没有实现,因为还没有学到Linux的队列概念,只是先留个印象

5. 由于之前的WIFI模块波特率改成了9600,所以现在连接CH340修改回 115200(使用AT指令修改)

 AP模式下控制的实现(透传)

CubeMX

1. 惯例配置(时钟,gpio,系统时钟)

2. 打开两个串口(uart1和uart2),并在WIFI模块对应的串口1打开中断

 3. 由于在中断处理函数中使用了Delay函数,得调整中断的优先级(非必要不使用,容易造成未知错误)

4. 惯例配置,导出工程(路径,编程软件)

Keil

要在魔术棒中将MiroLIB勾选,使得可以重写printf

代码:

#include <stdio.h>
#include <string.h>

//串口接收缓存(1字节)
uint8_t buf=0;

//定义最大接收字节数 200,可根据需求调整
#define UART1_REC_LEN 200

// 接收缓冲, 串口接收到的数据放在这个数组里,最大UART1_REC_LEN个字节
uint8_t UART1_RX_Buffer[UART1_REC_LEN];

//  接收状态
//  bit15,      接收完成标志
//  bit14,      接收到0x0d
//  bit13~0,    接收到的有效字节数目
uint16_t UART1_RX_STA=0;

char buffer[12];

char connect_net[]       = "AT+CWJAP=\"bbb\",\"56893233\"\r\n";              //入网指令   \r\n新行
char connect_servere[]   = "AT+CIPSTART=\"TCP\",\"192.168.93.248\",8880\r\n";//连接服务器指令


char Transparent_mode[]  = "AT+CIPMODE=1\r\n";     //透传模式指令
char data_transmission[] = "AT+CIPSEND\r\n";       //数据传输开始指令                //数据传输
char reset[]             = "AT+RST\r\n";           //重启模块指令
char AT_OK_flag = 0;			    //OK返回值的标志位
char AT_Connect_Net_Flag = 0;		//WIFI GOT IP返回值的标志位


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	// 判断中断是由哪个串口触发的
	if(huart->Instance == USART1)
	{
		// 判断接收是否完成(UART1_RX_STA bit15 位是否为1)
		if((UART1_RX_STA & 0x8000) == 0)
		{
			// 如果已经收到了 0x0d (回车),
			if(UART1_RX_STA & 0x4000)
			{
				// 则接着判断是否收到 0x0a (换行)
				if(buf == 0x0a)
				{
				// 如果 0x0a 和 0x0d 都收到,则将 bit15 位置为1
					UART1_RX_STA |= 0x8000;
				
				//程序运行到此处,代表数据已经完整接收,可以开始判断//
				
					//查看是否收到WIFI GOT IP
					if(strcmp(UART1_RX_Buffer,"WIFI GOT IP") == 0){
						HAL_UART_Transmit(&huart2, "111\r\n",strlen("111\r\n"), 100);
						AT_Connect_Net_Flag = 1;
					}
					//查看是否收到OK
					if(strcmp(UART1_RX_Buffer,"OK") == 0){
						HAL_UART_Transmit(&huart2, "222\r\n",strlen("222\r\n"), 100);
						AT_OK_flag = 1;
					}
					
					
					//灯控指令
					if(strcmp(UART1_RX_Buffer,"open") == 0){
						HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
					}
					if(strcmp(UART1_RX_Buffer,"close") == 0){
						HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
					}
					
					
					//如果联网失败,收到FAIL
					if(!strcmp(UART1_RX_Buffer,"FAIL")){
						HAL_UART_Transmit(&huart2, "error\r\n",strlen("error\r\n"), 100);
						int i;
						for(i = 0;i <5;i++){
							HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
							HAL_Delay(1000);}
							printf(reset);
						}
					
					memset(UART1_RX_Buffer,0,UART1_REC_LEN);
					UART1_RX_STA = 0;
				}
				else
					// 否则认为接收错误,重新开始
					UART1_RX_STA = 0;
			}
			else	// 如果没有收到了 0x0d (回车)
			{
				//则先判断收到的这个字符是否是 0x0d (回车)
				if(buf == 0x0d)
				{
					// 是的话则将 bit14 位置为1
					UART1_RX_STA |= 0x4000;
				}
				else
				{
					// 否则将接收到的数据保存在缓存数组里
					UART1_RX_Buffer[UART1_RX_STA & 0X3FFF] = buf;
					UART1_RX_STA++;
					
					// 如果接收数据大于UART1_REC_LEN(200字节),则重新开始接收
					if(UART1_RX_STA > UART1_REC_LEN - 1)
						UART1_RX_STA = 0;
				}
			}
		}
		// 重新开启中断
		HAL_UART_Receive_IT(&huart1, &buf, 1);
	}
}

int fputc(int ch, FILE *f)
{//注意,printf的重写是针对串口1的,也就是wifi的,对于串口2的数据发送不能用printf 
	unsigned char temp[1]={ch};
	HAL_UART_Transmit(&huart1,temp,1,0xffff);  
	return ch;
}


int main(void)
{

	HAL_NVIC_SetPriority(SysTick_IRQn,0,0);
	// 开启接收中断
	
	HAL_UART_Receive_IT(&huart1, &buf, 1);
	HAL_UART_Transmit(&huart2, "START\r\n",strlen("START\r\n"), 100);
	
	printf(connect_net); //发送联网AT指令并等待成功
	
	while(!AT_Connect_Net_Flag)  HAL_Delay(50);//此处这个delay必须得加,不然程序会卡死
	while(!AT_OK_flag)  HAL_Delay(50);//此处这个delay必须得加,不然程序会卡死
	HAL_UART_Transmit(&huart2, "5555\r\n",strlen("5555\r\n"), 100);
	AT_OK_flag = 0;
	
	
	//发送连服务器指令并等待成功
	printf(connect_servere);
	while(!AT_OK_flag)  HAL_Delay(50);
	HAL_UART_Transmit(&huart2, "6665\r\n",strlen("6665\r\n"), 100);
	AT_OK_flag = 0;
	
	//发送透传模式指令并等待成功
	printf(Transparent_mode);
	while(!AT_OK_flag)	HAL_Delay(50);
	HAL_UART_Transmit(&huart2, "7775\r\n",strlen("7775\r\n"), 100);
	AT_OK_flag = 0;
	
	
	//发送数据传输指令并等待成功
	printf(data_transmission);
	while(!AT_OK_flag)	HAL_Delay(50);

  while (1)
  {

		printf("hhhhhhhhhhhhaaaaaaaaaa");
		HAL_UART_Transmit(&huart2, "hello shion\r\n",strlen("hello shion\r\n"), 100);

		HAL_Delay(3000);
  }

}




实验效果: 

注意!要记得将服务器打开,不然一直连接不上(以至于折磨了我好长时间调试)


在电脑串口和网络调试助手可以看到不断发来的心跳包。

同时,串口1作为单片机和WIFI的通信,而串口2作为日志发回电脑的串口助手,串口1每发送并成功接收了回应,串口2就会返回电脑成功的信息,这样用户就可以可视化的看到连接进行到了哪一步,这算是用两路串口实现了以前白盒测试和黑盒测试的效果。

 当在网络助手发送“open”加上回车时,继电器会打开;反之输入“close”加上回车,继电器会闭合

STA模式下控制的实现

在这种模式下,ESP作为路由器,由电脑连接ESP的WIFI,作为Client来接收和发送。

以下是之前学习WIFI模块时总结的,关于ESP作为STA模式下的相关命令

 

CubeMX

同上

Keil

通过白盒测试可知:在ESP作为STA的模式下,WIFI助手发送的数据在串口中显示的是有特定格式的:

如果发送“open”加回车,那么显示的是:+IPD,0,6:open

如果发送“close”加回车,那么显示的是:+IPD,0,7:close

因此,在KEIL中的代码中,字符串的比较不能直接和open close比较,而是和以上两个字符串进行比较!!!

代码

#include <stdio.h>
#include <string.h>

//串口接收缓存(1字节)
uint8_t buf=0;

//定义最大接收字节数 200,可根据需求调整
#define UART1_REC_LEN 200

// 接收缓冲, 串口接收到的数据放在这个数组里,最大UART1_REC_LEN个字节
uint8_t UART1_RX_Buffer[UART1_REC_LEN];

//  接收状态
//  bit15,      接收完成标志
//  bit14,      接收到0x0d
//  bit13~0,    接收到的有效字节数目
uint16_t UART1_RX_STA=0;

char buffer[12];

char connect_net[]       = "AT+CWJAP=\"bbb\",\"56893233\"\r\n";              //入网指令   \r\n新行

char mode[]    = "AT+CWMODE=2\r\n";    //路由器模式指令
char mul_con[] = "AT+CIPMUX=1\r\n";    //使能多链接
char server[]  = "AT+CIPSERVER=1\r\n"; //建立TCPServer   default port = 333
char send[]    = "AT+CIPSEND=0,5\r\n"; //发送数据
char end[]     = "AT+CIPCLOSE=0\r\n";  //断开连接

char AT_Connect_Net_Flag = 0;		//WIFI GOT IP返回值的标志位

char AT_OK_flag = 0;              //OK返回值的标志位
char Client_Connent_Flag = 0;     //客户端接入返回值标志位

// 接收完成回调函数,收到一个数据后,在这里处理
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	// 判断中断是由哪个串口触发的
	if(huart->Instance == USART1)
	{
		// 判断接收是否完成(UART1_RX_STA bit15 位是否为1)
		if((UART1_RX_STA & 0x8000) == 0)
		{
			// 如果已经收到了 0x0d (回车),
			if(UART1_RX_STA & 0x4000)
			{
				// 则接着判断是否收到 0x0a (换行)
				if(buf == 0x0a)
				{
				// 如果 0x0a 和 0x0d 都收到,则将 bit15 位置为1
					UART1_RX_STA |= 0x8000;
				
					
					
					
				//程序运行到此处,代表数据已经完整接收,可以开始判断//
				
					//查看是否收到WIFI GOT IP
					if(strcmp(UART1_RX_Buffer,"WIFI GOT IP") == 0){
						HAL_UART_Transmit(&huart2, "111\r\n",strlen("111\r\n"), 100);
						AT_Connect_Net_Flag = 1;
					}
					//查看是否收到OK
					if(strcmp(UART1_RX_Buffer,"OK") == 0){
						HAL_UART_Transmit(&huart2, "222\r\n",strlen("222\r\n"), 100);
						AT_OK_flag = 1;
					}
					
					
					//灯控指令
					if(strcmp(UART1_RX_Buffer,"+IPD,0,6:open") == 0){
						HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
					}
					if(strcmp(UART1_RX_Buffer,"+IPD,0,7:close") == 0){
						HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
					}
					
					
					//如果联网失败,收到FAIL
					if(!strcmp(UART1_RX_Buffer,"0,CONNECT")){
						Client_Connent_Flag = 1;
						}
					
					memset(UART1_RX_Buffer,0,UART1_REC_LEN);
					UART1_RX_STA = 0;
				}
				
					
				
			
				else
					// 否则认为接收错误,重新开始
					UART1_RX_STA = 0;
			}
			else	// 如果没有收到了 0x0d (回车)
			{
				//则先判断收到的这个字符是否是 0x0d (回车)
				if(buf == 0x0d)
				{
					// 是的话则将 bit14 位置为1
					UART1_RX_STA |= 0x4000;
				}
				else
				{
					// 否则将接收到的数据保存在缓存数组里
					UART1_RX_Buffer[UART1_RX_STA & 0X3FFF] = buf;
					UART1_RX_STA++;
					
					// 如果接收数据大于UART1_REC_LEN(200字节),则重新开始接收
					if(UART1_RX_STA > UART1_REC_LEN - 1)
						UART1_RX_STA = 0;
				}
			}
		}
		// 重新开启中断
		HAL_UART_Receive_IT(&huart1, &buf, 1);
	}
}

int fputc(int ch, FILE *f)
{//注意,printf的重写是针对串口1的,也就是wifi的,对于串口2的数据发送不能用printf 
	unsigned char temp[1]={ch};
	HAL_UART_Transmit(&huart1,temp,1,0xffff);  
	return ch;
}


int main(void)
{

	HAL_NVIC_SetPriority(SysTick_IRQn,0,0);
	// 开启接收中断
	
	HAL_UART_Receive_IT(&huart1, &buf, 1);
	HAL_UART_Transmit(&huart2, "START\r\n",strlen("START\r\n"), 100);
	
	
	
	printf(mode);//发送客户端模式指令并等待成功
	while(!AT_OK_flag)	HAL_Delay(50);
	AT_OK_flag = 0;
	HAL_UART_Transmit(&huart1, "mode set success\r\n", strlen("mode set success\r\n"), 100);
	
	printf(mul_con);
	while(!AT_OK_flag)	HAL_Delay(50);
	AT_OK_flag = 0;
	
	printf(server);
	while(!Client_Connent_Flag)	HAL_Delay(50);
	AT_OK_flag = 0;
	
	if(Client_Connent_Flag){
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
	}

  while (1)
  {

		printf(send);//发送数据
		HAL_Delay(2000);
		printf("wdnmd");//发给串口1的,共2个字节
		HAL_Delay(2000);
  }

}


 

实现效果

打开单片机点击复位,使得电脑连上”esp8266“的WIFI,然后在网络助手中输入相关信息之后点击连接:(要提前连好wifi的情况)1-ESP8266-AT指令初试化及部分基础知识_ch_pd-CSDN博客STA模式具体连接再次参考这个

当在网络助手发送“open”加上回车时,LED1会打开;反之输入“close”加上回车,LED1会关闭

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

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

相关文章

thinkphp6中使用监听事件和事件订阅

目录 一&#xff1a;场景介绍 二&#xff1a;事件监听 三&#xff1a;配置订阅 一&#xff1a;场景介绍 在项目开发中有很多这样的场景&#xff0c;比如用户注册完了&#xff0c;需要通知到第三方或者发送消息。用户下单了&#xff0c;需要提示给客服等等。这些场景都有一个…

R语言 多组堆砌图

目录 数据格式 普通绘图 添加比例 R语言 堆砌图_r语言堆砌图-CSDN博客 关键点在于数据转换步骤和数据比例计算步骤&#xff0c;然后个性化调整图。 ①data <- melt(dat, id.vars c("ID"))##根据分组变为长数据 ②#计算百分比## data2 <- ddply(data, …

线上研讨会 | 新一代数字化技术赋能机器人及智能产线行业高质量发展

随着智能制造的快速推进&#xff0c;制造业转型升级到了关键阶段。越来越多的企业以数字化技术搭配智能机器人及智慧产线&#xff0c;主动实现数字化转型。达索系统3D体验平台是实现企业数字化转型的新一代数智化平台&#xff0c;基于型、数字驱动、数字化连续技术&#xff0c;…

.NET 设计模式—装饰器模式(Decorator Pattern)

简介 装饰者模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许你在不改变对象接口的前提下&#xff0c;动态地将新行为附加到对象上。这种模式是通过创建一个包装&#xff08;或装饰&#xff09;对象&#xff0c;将要被装饰的对象包裹起来…

OAuth2.0客户端和服务端Java实现

oauth2 引言 读了《设计模式之美》和《凤凰架构》架构安全篇之后&#xff0c;决定写一个OAuth2.0的认证流程的Demo&#xff0c;也算是一个阶段性的总结&#xff0c;具体原理实现见《凤凰架构》(架构安全设计篇)。 涉及到的源码可以从https://github.com/WeiXiao-Hyy/oauth2获…

【MacOs】proxychains配置使用

一、开始 1. 安装proxychains 使用brew进行安装 brew install proxychains-ng没有homebrew的&#xff0c;可以使用该命令安装 /usr/bin/ruby -e "$(curl -fsSL https://cdn.jsdelivr.net/gh/ineo6/homebrew-install/install)"2. 配置代理配置文件 cd /opt/homeb…

用Python+OpenCV截取视频中所有含有字幕的画面

1、需求背景 有的视频文件的字幕已经压制到了视频的图像中&#xff0c;不能单独提取出字幕文件。网上的 “提取视频字幕” 网站多为提取视频中的字幕文件&#xff0c;而非识别视频图像中的字幕。少数通过OCR技术识别画面中字幕的工具需要在线运行、运行速度较慢&#xff0c;或…

React - 你知道在React组件的哪个阶段发送Ajax最合适吗

难度级别:中级及以上 提问概率:65% 如果求职者被问到了这个问题,那么只是单纯的回答在哪个阶段发送Ajax请求恐怕是不够全面的。最好是先详细描述React组件都有哪些生命周期,最后再回过头来点题作答,为什么应该在这个阶段发送Ajax请求。那…

spring cloud gateway openfeign 联合使用产生死锁问题

spring cloud gateway openfeign 联合使用产生死锁问题&#xff0c;应用启动的时候阻塞卡住。 spring.cloud 版本如下 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><vers…

Labview复制文件夹下的内容到另一个文件夹下

1.程序前面板和后面板 2设置 3执行 4.执行后 5源代码 链接&#xff1a;https://pan.baidu.com/s/1u4cHmA_jUL_hptbiIhTVDA?pwdafu6 提取码&#xff1a;afu6

12个建筑数据分析典型用例

建筑企业面临着众多挑战&#xff0c;包括紧迫的期限、预算限制和复杂的监管要求。 然而&#xff0c;很明显&#xff0c;数据分析可以成为克服这些障碍的重要工具。 建筑行业是数据最密集的市场之一&#xff0c;这就是为什么越来越需要更好的建筑分析和大数据管理。 通过大数据…

OpenCV图像处理——基于OpenCV的ORB算法实现目标追踪

概述 ORB&#xff08;Oriented FAST and Rotated BRIEF&#xff09;算法是高效的关键点检测和描述方法。它结合了FAST&#xff08;Features from Accelerated Segment Test&#xff09;算法的快速关键点检测能力和BRIEF&#xff08;Binary Robust Independent Elementary Feat…

期货量化交易软件:MQL5 中的范畴论 (第 15 部分)函子与图论

概述 在上一篇文章中&#xff0c;我们目睹了前期文章中涵盖的概念&#xff08;如线性序&#xff09;如何视作范畴&#xff0c;以及为什么它们的“态射”在与其它范畴相关时即构成函子。在本文中&#xff0c;我们赫兹量化软件将阐述来自前期文章中的概括&#xff0c;即通过查看…

DXP学习002-PCB编辑器的环境参数及电路板参数相关设置

目录 一&#xff0c;dxp的pcb编辑器环境 1&#xff0c;创建新的PCB设计文档 2&#xff0c;PCB编辑器界面 1&#xff09;布线工具栏 2&#xff09;公用工具栏 3&#xff09;层标签栏 ​编辑 3&#xff0c;PCB设计面板 1&#xff09;打开pcb设计面板 4&#xff0c;PCB观…

SSH如何端口映射?

SSH端口映射&#xff08;SSH Port Forwarding&#xff09;是一种通过SSH协议进行端口转发的技术&#xff0c;它能够实现在不直接将服务暴露在公网的情况下&#xff0c;通过私有通道传输数据&#xff0c;并保障数据的安全加密。 SSH端口映射的原理 SSH端口映射主要包括本地端口…

二维码门楼牌管理应用平台建设:智慧化管理的新篇章

文章目录 前言一、二维码门楼牌管理应用平台的建设背景二、二维码门楼牌管理应用平台的功能特点三、二维码门楼牌管理应用平台的意义与价值四、结语 前言 随着信息技术的不断发展&#xff0c;二维码门楼牌管理应用平台的建设已成为城市管理的必然趋势。通过这一平台&#xff0…

稀碎从零算法笔记Day42-LeetCode:分发糖果

题型&#xff1a;数组、贪心 链接&#xff1a; 来源&#xff1a;LeetCode 题目描述 n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。 你需要按照以下要求&#xff0c;给这些孩子分发糖果&#xff1a; 每个孩子至少分配到 1 个糖果。相邻两个孩子评分更…

绝地求生:齐贺PUBG七周年!分享你的游玩感受及反馈赢惊喜道具

PUBG七周年庆典火热进行中&#xff0c;特殊道具、周年主题艾伦格上线&#xff01;七周年期间游玩PUBG&#xff0c;在评论区分享你的游玩感受及反馈&#xff0c;即可参与活动赢取夏日浪潮宝箱奖励。 参与方式 齐贺PUBG七周年&#xff01;在评论区分享分享你的七周年游玩感受及反…

查看MySQL版本的方式

文章目录 一、使用cmd输入命令行查看二、在mysql客户端服务器里查询 一、使用cmd输入命令行查看 1、打开 cmd &#xff0c;输入命令行&#xff1a; mysql --version 2、还是打开cmd&#xff0c;输入命令行&#xff1a;mysql -V (注意了&#xff0c;此时的V是个大写的V) 二、…

5.网络编程-socker(golang版)

目录 一、什么是socket&#xff1f; 二、Golang中使用TCP TCP服务端 TCP客户端​​​​​​​ 三、TCP黏包&#xff0c;拆包 1.什么是粘包&#xff0c;拆包&#xff1f; 2.为什么UDP没有粘包&#xff0c;拆包&#xff1f; 3.粘包拆包发生场景 4.TCP黏包 黏包服务端 …