基于stm32的esp8266的WIFI控制风扇实验

news2024/11/25 23:02:52

实验案例WIFI控制风扇

项目需求

电脑通过esp8266模块远程遥控风扇。

项目框图

风扇模块封装 

#include "sys.h"
#include "fan.h"

void fan_init(void)
{
		GPIO_InitTypeDef gpio_initstruct;
		//打开时钟
		__HAL_RCC_GPIOB_CLK_ENABLE();
		//调用GPIO初始化函数
	gpio_initstruct.Pin  = GPIO_PIN_6;
	gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;
	gpio_initstruct.Pull = GPIO_PULLUP;//上拉需要给一个下降沿
	gpio_initstruct.Speed= GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOB,&gpio_initstruct);
		//关闭LED
	fan1_off();
}
void fan1_on(void)
{
  	//由电路图可知,将GPIO拉低
	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);

}
//熄灭LED1的函数

void fan1_off(void)
{
		//由电路图可知,将GPIO拉低
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);


}

//获取继电器的状态

uint8_t fan_status_get(void)
{
		return (uint8_t)HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6);//要么返回0,要么返回1

}


esp8266功能代码封装 

头文件

#include "sys.h"
#include "esp8266.h"
#include "string.h"
#include "delay.h"
#include "stdarg.h"

uint8_t esp8266_tx_buf[ESP8266_TX_BUF_SIZE];
uint8_t esp8266_rx_buf[ESP8266_RX_BUF_SIZE]; 

uint16_t esp8266_cnt = 0 ,esp8266_cntPre = 0; /* esp8266接收缓冲区 */

UART_HandleTypeDef esp8266_handle;             /* esp8266句柄 */

esp8266串口初始化配置

void esp8266_uart_init(uint32_t baudrate)//正常会有启动的流程只是作为一个串口的初始化
{
    /*esp8266 初始化设置*/
    esp8266_handle.Instance = USART2;                               /* USART1 */
    esp8266_handle.Init.BaudRate = baudrate;                        /* 波特率 */
    esp8266_handle.Init.WordLength = UART_WORDLENGTH_8B;            /* 字长为8位数据格式*/
    esp8266_handle.Init.StopBits = UART_STOPBITS_1;                 /* 一个停止位 */
    esp8266_handle.Init.Parity = UART_PARITY_NONE;                  /* 无奇偶校验位 */
    esp8266_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;            /* 无硬件流控 */
    esp8266_handle.Init.Mode = UART_MODE_TX_RX;                     /* 收发模式 */
    HAL_UART_Init(&esp8266_handle);                                 /*会使能esp8266 */                 
}

接收缓冲区配置

void esp8266_rx_clear(void)
{
    memset(esp8266_rx_buf, 0, sizeof(esp8266_rx_buf)); /* 清空接收缓冲区 */
    esp8266_cnt = 0;                                   /* 接收计数器清零 */
}

中断服务函数

void USART2_IRQHandler(void)
{
    uint8_t receive_data = 0;   
    if(__HAL_UART_GET_FLAG(&esp8266_handle, UART_FLAG_RXNE) != RESET){/* 获取接收RXNE标志位是否被置位 */
        if(esp8266_cnt >= sizeof(esp8266_rx_buf))                     /* 如果接收的字符数大于接收缓冲区大小, */
            esp8266_cnt = 0;                                          /* 则将接收计数器清零 */
        HAL_UART_Receive(&esp8266_handle, &receive_data, 1, 1000);    /* 接收一个字符 */
        esp8266_rx_buf[esp8266_cnt++] = receive_data;    /* 将接收到的字符保存在接收缓冲区 */
    }

    if (__HAL_UART_GET_FLAG(&esp8266_handle, UART_FLAG_IDLE) != RESET) /* 获取接收空闲中断标志位是否被置位 */
    {
        printf("recv: %s\r\n", esp8266_rx_buf);                  /* 将接收到的数据打印出来 */
        esp8266_rx_clear();
        __HAL_UART_CLEAR_IDLEFLAG(&esp8266_handle);              /* 清除UART总线空闲中断 */
    }
}

等待接收函数

uint8_t esp8266_wait_receive(void)
{
	if(esp8266_cnt == 0)
			return ESP8266_ERROR;
	if(esp8266_cnt == esp8266_cntPre)
	{
		esp8266_cnt = 0;
		return ESP8266_EOK;
	}
		esp8266_cntPre = esp8266_cnt;
		return ESP8266_ERROR;
}

发送指令并期待返回值

uint8_t esp8266_send_command(char *cmd,char *res)//发送一个指令去   在指定时间内返回回来 否则没有接收到一个返回值
{
	uint8_t timeout_out = 250;
	
	esp8266_rx_clear(); //防止忍心内的数据影响
	HAL_UART_Transmit(&esp8266_handle,(uint8_t *)cmd,strlen(cmd),100);//发送命令 cmd在这里是一个uint8_t的数据 长度 阻塞的值
	//等待
	while(timeout_out--)//不停的等待
	{
		if(esp8266_wait_receive() == ESP8266_EOK)
		{
			if(strstr((const char*)esp8266_rx_buf, res) != NULL)//判断是否又有期待的字符串
			return ESP8266_EOK;
		}
		delay_ms(10);
		}
		return ESP8266_ERROR;//否则接收错误
	
}

接收数据

//接收的函数
void esp8266_receiv_data(void)
{
	if(esp8266_wait_receive() == ESP8266_EOK)
	{
		printf("esp8266 recv: %s\r\n", esp8266_rx_buf);
		esp8266_rx_clear();
	}
}

发送不定长数据

//发送的函数  不定长数据 参数不固定
void esp8266_send_data(char *fmt, ...)
{
	va_list ap;
	uint16_t len;
	
	va_start(ap,fmt);
	vsprintf((char *)esp8266_tx_buf,fmt, ap);
	va_end(ap);
	
	len = strlen((const char*)esp8266_tx_buf);
	HAL_UART_Transmit(&esp8266_handle, esp8266_tx_buf, len,100);//发送
}

设置a模块是否存在测试



uint8_t esp8266_at_test(void)
{
		return esp8266_send_command("AT\r\n", "OK");//记得加回车换行才能作为指令发送期待返回值为OK  直接作为返回值发送

}

设置模式

uint8_t esp8266_set_mode(uint8_t mode)//s四个函数
{
	switch(mode)
	{
		case ESP8266_STA_MODE:
				return esp8266_send_command("AT+CWMODE=1\r\n","OK");
		
		case ESP8266_AP_MODE:
				return esp8266_send_command("AT+CWMODE=2\r\n","OK");
		
		case ESP8266_STA_AP_MODE:
				return esp8266_send_command("AT+CWMODE=3\r\n","OK");
		
		default:
				return ESP8266_EINVAL;//如果指令不存在
	}
}

加入AP


uint8_t esp8266_join_ap(char *ssid,char *pwd)//账号密码
{
		char cmd[64];
		sprintf(cmd, "AT+CWJAP=\"%s\",\"%s\"\r\n",ssid,pwd);//\"HUAWEIAP-1\",=\"%s\  就指令带引号直接写不行,我们需要如此就不会将“”认为是配对的
		return esp8266_send_command(cmd,"WIFI GOT IP");;//调用指令函数
}

连接模式

	
uint8_t esp8266_connect_mode(uint8_t mode)//设置单路连接的模式(透传只能用此模式)
{
		char cmd[64];
		sprintf(cmd, "AT+CIPMUX=%d\r\n",mode);//作为模式传输进入
		return esp8266_send_command(cmd,"OK");;//调用指令函数
}
//连接TCP服务器

esp8266_连接模式

uint8_t esp8266_connect_mode(uint8_t mode)//设置单路连接的模式(透传只能用此模式)
{
		char cmd[64];
		sprintf(cmd, "AT+CIPMUX=%d\r\n",mode);//作为模式传输进入
		return esp8266_send_command(cmd,"OK");;//调用指令函数
}

 esp8266连接tpc服务器ip和端口

uint8_t esp8266_connect_tcp_server(char *server_ip,char*server_port)
{
		char cmd[64];
		sprintf(cmd, "AT+CIPSTART=\"TCP\",\"%s\",%s\r\n",server_ip,server_port);//作为模式传输进入
		return esp8266_send_command(cmd,"CONNECT");;//调用指令函数
}

进入透传模式

uint8_t esp8266_enter_unvarnished(void)//发送的模式
{
		uint8_t ret;//取巧的方式定义一个返回值
		//两次返回值都等于0,如果有一个不为0就为不为零的情况
		ret  = esp8266_send_command("AT+CIPMODE=1\r\n","OK");;//调用指令函数
		ret += esp8266_send_command("AT+CIPSEND\r\n",">");;//调用指令函数
		if(ret == ESP8266_EOK)
				return ESP8266_EOK;
		else
				return ESP8266_ERROR;		
}

建立tcp服务器

uint8_t esp8266_build_tcp_server(void)
{
		return esp8266_send_command("AT+CIPSERVER=1\r\n","OK");//发送AT+CIPSEVER=1,期待回复OK
}

初始化esp8266


void esp8266_init(uint32_t baudrate)//所以增加新添加一个
{
		printf("esp8266初始化开始...\r\n");
		esp8266_uart_init(baudrate);
	
		printf("1. 测试esp8266是否存在\r\n");
		while(esp8266_at_test())//esp8266_at_test();也是可以的不过一直不成功那就一直等待更为保险
			delay_ms(500);

		printf("2. 设置工作模式为AP...\r\n");
		while(esp8266_set_mode(ESP8266_AP_MODE))
			delay_ms(500);
		
		printf("3. 设置多路链接模式\r\n");
		while(esp8266_connect_mode(ESP8266_MULTI_CONNECTION))
			delay_ms(500);
		printf("4. 建立TCP服务器...\r\n");
		while(esp8266_build_tcp_server())
			delay_ms(500);		

		printf("esp8266初始化完成...\r\n");

		
		
	//esp8266的其他初始化
}

esp8266初始化测试

//测试函数
void esp8266_test(void)
{
	esp8266_send_data("this is from esp8266\r\n");
	esp8266_receiv_data();
}

main函数

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "esp8266.h"
#include "fan.h"
#include "string.h"
int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();	/* LED初始化 */

		uart1_init(115200);
		esp8266_init(115200);
		fan_init();

		printf("helloworld!\r\n");
		char recv_data[ESP8266_RX_BUF_SIZE];//接收传入参数
    while(1)
    { 
      			
			esp8266_receive_data(recv_data);//接收到数据tcp服务器传输过来的字符串
			if(strstr(recv_data, "ON") != NULL)//判断字符串有ON,打开风扇
					fan1_on();
			else if(strstr(recv_data, "OFF") != NULL)
					fan1_off();
			
			delay_ms(10);
    }
}

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

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

相关文章

4K Mini-LED显示器平民价,一千多的联合创新27M3U到底有多香

哈喽小伙伴们好,我是Stark-C~ 要说前几年买显示器还是普通IPS的天下,那个时候虽说也有MiniLED或者OLED显示器,但是价格那也是真贵啊,毕竟那个时候MiniLED和OLED还没普及,只有一些高档电视或者显示器才会用到此技术。不…

OpenCV高级图形用户界面(18)手动设置轨迹条(Trackbar)的位置函数setTrackbarPos()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 该函数设置指定窗口中指定轨迹条的位置。 注意 [仅 Qt 后端] 如果轨迹条附加到控制面板,则 winname 可以为空。 函数原型 void cv…

三周精通FastAPI:4 使用请求从客户端(例如浏览器)向 API 发送数据

FastAPI官网手册:https://fastapi.tiangolo.com/zh/tutorial/query-params/ 上节内容:三周精通FastAPI:3 查询参数 请求 FastAPI 使用请求从客户端(例如浏览器)向 API 发送数据。 请求是客户端发送给 API 的数据。响…

国家信息安全水平考试(NISP一级)最新题库-第十六章

目录 另外免费为大家准备了刷题小程序和docx文档,有需要的可以私信获取 1 防火墙是一种较早使用、实用性很强的网络安全防御技术,以下关于防火墙说法错误的是() A.防火墙阻挡对网络的非法访问和不安全数据的传递;B.防…

Leecode刷题之路第27天之移除元素

题目出处 27-移除元素-题目描述 题目描述 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。假设 nums 中不等于 val 的元素数量为 k,要通过此题&#x…

C++ | Leetcode C++题解之第491题非递减子序列

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> temp; vector<vector<int>> ans;void dfs(int cur, int last, vector<int>& nums) {if (cur nums.size()) {if (temp.size() > 2) {ans.push_back(temp);}return;}if…

【题解】—— LeetCode一周小结42

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结41 14.鸡蛋掉落 题目链接&#xff1a;887. 鸡蛋掉落 给你 k 枚…

c++迷宫游戏

1、问题描述 程序开始运行时显示一个迷宫地图&#xff0c;迷宫中央有一只老鼠&#xff0c;迷宫的右下方有一个粮仓。游戏的任务是使用键盘上的方向健操纵老鼠在规定的时间内走到粮仓处。 基本要求: 老鼠形象可以辨认,可用键盘操纵老鼠上下左右移动&#xff1b;迷宫的墙足够结…

博弈论学习笔记【施工中】

SG函数 首先定义就不用我讲了吧&#xff0c;还不会的自己看看 传送门 再进一步理解一下吧&#xff1a; 黑色数字是节点编号&#xff0c;红色是 S G SG SG 函数值 看下它的过程&#xff1a; 首先 5 5 5 和 6 6 6 没有后继节点&#xff0c;为必败态&#xff0c;先赋值为 …

OpenCV和HALCON

OpenCV和HALCON是两种广泛用于图像处理和计算机视觉的开发库&#xff0c;它们各有优缺点&#xff0c;适合不同的应用场景。以下是两者的比较&#xff1a; 1. 开发背景与定位 OpenCV (Open Source Computer Vision Library)&#xff1a; 开源库&#xff0c;最初由Intel开发&…

【图解版】力扣第146题:LRU缓存

力扣第146题&#xff1a;LRU缓存 一、LRU算法1. 基本概念2. LRU 和 LFU 的区别&#xff1a;3. 为什么 LRU 不需要记录使用频率&#xff1f; 二、Golang代码实现三、代码图解1. LRUCache、DLinkedNode两个结构体2. 初始化结构体对象3. addToHead函数4. removeNode函数5. moveToH…

基于单片机的多功能鱼缸控制系统设计

本设计以STC12C5A60S2单片机为核心的多功能鱼缸控制系统&#xff0c;该系统可分别利用温度传感器、水位传感器和浑浊度传感器来检测鱼缸内部的水温、液体高度和浑浊程度&#xff0c;并在显示屏上进行显示。若检测结果超出阈值范围&#xff0c;则继电器工作从而控制内部环境。通…

LeetCode102. 二叉树的层序遍历(2024秋季每日一题 43)

给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9,20],[15,7]] 示例 2&#xff1a; 输入…

白嫖正版xshell和XFTP

在哪里可以下载正版免费的xshell和XFTP&#xff0c;并且还能够获得官网免费持久更新 白嫖步骤 首先直接在浏览器搜索xshell官网 点进官网之后直接点击下载 接着点击免费授权页面 进入之后就可以免费下载了 下载安装完成后填写用户名和邮箱并提交&#xff0c;这里就以xshell为…

Veritas NetBackup 10.5 发布,新增功能概览

Veritas NetBackup 10.5 发布&#xff0c;新增功能概览 Veritas NetBackup 10.5 (Unix, Linux, Windows) - 领先的企业备份解决方案 The #1 enterprise backup and recovery solution. 请访问原文链接&#xff1a;https://sysin.org/blog/veritas-netbackup-10/ 查看最新版。…

EditPlus的安装软件包

解压并粘贴到C:\Program Files (x86)中 点击激活密匙,并一直同意 确认并选择默认的位置: 关闭并重新激活密匙 就好了 无需添加快捷方式: 只需要选择任意文件 并选择该应用打开一次即可 通过百度网盘分享的文件&#xff1a;EditPlus_5.0.611.zip 链接&#xff1a;https://pa…

在Debian 11/Debian 10上安装MySQL 5.7

本文借鉴 如何在 Debian 11/Debian 10 上安装 MySQL 5.7 |https://cn.linux-console.net/?p20728 下载安装存储库 安装 根据提示选择mysql5.7即可(会车键选择) wget https://dev.mysql.com/get/mysql-apt-config_0.8.16-1_all.debsudo dpkg -i mysql-apt-config_0.8.16-1_a…

MFC工控项目实例二十四模拟量校正值输入

承接专栏《MFC工控项目实例二十三模拟量输入设置界面》 对模拟量输入的零点校正值及满量程对应的电压值进行输入。 1、在SenSet.h文件中添加代码 #include "BtnST.h" #include "ShadeButtonST.h"/ // SenSet dialogclass SenSet : public CDialog { // Co…

AWD初步学习

一般的AWD不提供外网环境&#xff0c; AWD比赛中一般准备语言环境&#xff0c;工具、exploit及相关脚本框架。 1.脚本环境 一般在/var/www/html目录的下面&#xff0c;需要提前PHP和常用的Web开发语言环境在本地进行配置&#xff0c;且统一语言尽量多配置环境&#xff0c;比如P…

基于stm32的4G模块点灯实验

led模块功能封装 #include "led.h" #include "sys.h"//初始化GPIO函数 void led_init(void) {GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOB_CLK_ENABLE();//调用GPIO初始化函数gpio_initstruct.Pin GPIO_PIN_8 | GPIO_PIN_9;gpio_inits…