ESP8266源代码实现

本文详细介绍了ESP8266模块通过USART2进行串口初始化的过程,包括GPIO配置、USART参数设置、NVIC中断管理,并展示了如何设置WiFi接收数据的回调函数以及TCP连接的建立和数据传输。
摘要由CSDN通过智能技术生成
#include "usart2.h"
#include "esp8266.h"

usart2_handler u2_h;

void usart_2_init(void)//初始化的函数(初始化GPIO管脚和串口功能)
{
	GPIO_InitTypeDef Gpio_Value;//定义了GPIO固件的结构体变量
	USART_InitTypeDef Usart_Value;//定义了USART固件的结构体变量
	NVIC_InitTypeDef Nvic_Value;//定义了NVIC固件的结构体变量
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	//通过APB2总线使能GPIOA组的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	//通过PAB1总线使能USART2的时钟
	
	Gpio_Value.GPIO_Mode = GPIO_Mode_AF_PP;//选择了推挽的复用模式
	Gpio_Value.GPIO_Pin = GPIO_Pin_2;//选择了 2 号管脚(PA2是发送管脚)
	Gpio_Value.GPIO_Speed = GPIO_Speed_50MHz;//选择了50MHz的输出速度
	GPIO_Init(GPIOA, &Gpio_Value);//按照上述配置初始化GPIOA组的管脚

	Gpio_Value.GPIO_Mode = GPIO_Mode_IN_FLOATING;//选择了浮空的输入模式
	Gpio_Value.GPIO_Pin = GPIO_Pin_3;//选择了 3 号管脚(PA3是接收管脚)
	GPIO_Init(GPIOA, &Gpio_Value);//按照上述配置初始化GPIOA组的管脚
	
	Usart_Value.USART_BaudRate = 115200;//选择了115200的波特率
	Usart_Value.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//选择了关闭硬件流控
	Usart_Value.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//选择了发送模式和接收模式
	Usart_Value.USART_Parity = USART_Parity_No;//选择了没有奇偶校验
	Usart_Value.USART_StopBits = USART_StopBits_1;//选择了1个停止位
	Usart_Value.USART_WordLength = USART_WordLength_8b;//选择了8个数据位
	USART_Init(USART2, &Usart_Value);//按照上述配置初始化USART2
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置组优先级和子优先级的所占比例
	Nvic_Value.NVIC_IRQChannel = USART2_IRQn;//选择了USART2中断源的中断号
	Nvic_Value.NVIC_IRQChannelCmd = ENABLE;//选择使能该中断
	Nvic_Value.NVIC_IRQChannelPreemptionPriority = 2;//选择了组优先级的级别为2
	Nvic_Value.NVIC_IRQChannelSubPriority = 2;//选择了子优先级的级别为2
	NVIC_Init(&Nvic_Value);//按照上述配置初始化NVIC中断控制器
	
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//使能了USART2的接收数据触发中断
	
	USART_Cmd(USART2, ENABLE);//使能USART2的功能
}

void usart_2_send_byte(unsigned char c)//发送一个字节的数据
{
	USART_SendData(USART2, c);//通过USART2把c变量保存的数据发送出去
	while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);//检验USART2的发送数据是否发送成功了(超时处理)
	USART_ClearFlag(USART2, USART_FLAG_TC);//清除USART2的发送成功的标志状态
}

void usart_2_send_data(char *buf)//发送一个字符串的数据
{
	while(*buf)//通过while循环把字符串中的有效字符遍历一遍
	{
		usart_2_send_byte(*buf);//把有效的字符进行发送
		buf++;//让buf指针指向下一个字符
	}
}

unsigned char usart_2_recv_byte(void)//接收一个字节数据
{
	unsigned char ret = 0;//ret变量用来接收USART1接到的数据
	
	if(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == SET)//判断USART2是否接收到了数据
	{
		ret = USART_ReceiveData(USART2);//把USART2接收到的数据保存到ret变量中
		USART_ClearFlag(USART2, USART_FLAG_RXNE);//清除USART2接收到数据的标志
	}
	
	return ret;
}

void USART2_IRQHandler(void)
{
	if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)//判断是否是由USART2的接收数据触发的中断
	{
		dataHandler(USART_ReceiveData(USART2));//接收USART1的数据,并把接收到的数据以传参的形式传递给回调函数
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);//清除USART1接收数据的中断标志
	}
}

void set_usart2_handler(usart2_handler h)//设置回调函数
{
	u2_h = h;//把形参h所存储的函数地址另存到全局变量u1_h中
}













ESP8266.h文件

#ifndef __ESP8266_H
#define __ESP8266_H
/*
ESP8266模块是WIFI无线通讯模块,该模块是串口接口
连接到了我们开发板上的USART2
*/
#include "stm32f10x_conf.h"//包含该头文件所有的外设头文件均已包含

typedef void (*wifi_recv_handler)(char *buf, int len);//通过typedef定义函数指针类型

extern void set_wifi_recv_handler(wifi_recv_handler h);//设置wifi接收到数据的回调函数
extern void esp8266_init(void);//初始化的函数(初始化串口)
extern void esp8266_link_wifi(char *ssid, char *passwd);//连接路由(需要路由的名称和路由的密码)
extern void esp8266_connect(char *ip, char *port);//连接TCP server
extern void esp8266_disconnect(void);//断开TCP连接
extern void esp8266_send(char *msg, char *len);//发送数据
extern void dataHandler(unsigned char c);//处理接收到的数据

#endif

ESP8266.c文件

#include "esp8266.h"
#include "usart2.h"
#include "delay.h"
#include "stdio.h"
#include "stdlib.h"

#define O_F	1//O的状态
#define K_F	2//K的状态
static int flag = O_F;
static int ok_flag = 0;
static int len = 0;//保存数据长度的整数

//"+IPD,13:1234567890ABC"
#define ADD_S 	0//+的状态
#define I_S			1//I的状态
#define P_S			2//P的状态
#define D_S			3//D的状态
#define H_S			4//,的状态
#define LEN_S		5//长度的状态
#define DATA_S	6//数据的状态
static int data_flag = ADD_S;//默认是+的状态
wifi_recv_handler wifi_handler = NULL;

void set_wifi_recv_handler(wifi_recv_handler h)//设置wifi接收到数据的回调函数
{
	wifi_handler = h;
}

void dataHandler(unsigned char c)//处理接收到的数据
{
	static char len_buf[5];//接收到数据的字节数
	static int i = 0;//循环变量
	static char data_buf[512];//存储接收到的数据
	
	switch(data_flag)
	{
		case ADD_S :
									if(c == '+')
										data_flag = I_S;
									break;
		case I_S :
									if(c == 'I')
										data_flag = P_S;
									else
										data_flag = ADD_S;
									break;
		case P_S :
									if(c == 'P')
										data_flag = D_S;
									else
										data_flag = ADD_S;
									break;
		case D_S :
									if(c == 'D')
										data_flag = H_S;
									else
										data_flag = ADD_S;
									break;
		case H_S :
									if(c == ',')
										data_flag = LEN_S;
									else
										data_flag = ADD_S;
									break;
		case LEN_S ://+IPD,13:1234567890ABC
									if(c == ':')
									{
										len_buf[i] = '\0';
										len = atoi(len_buf);
										data_flag = DATA_S;
										i = 0;
										break;
									}
									else
										len_buf[i] = c;
									i++;
									break;
		case DATA_S:
									data_buf[i] = c;
									i++;
									if(i == len)
									{
										i = 0;
										data_flag = ADD_S;
										if(wifi_handler)
											wifi_handler(data_buf, len);
										break;
									}
									break;
	}
	
	if(c == '>')
		ok_flag = 1;
	
	if(ok_flag == 0)
	{
		switch(flag)
		{
			case O_F : 
									if(c == 'O')
										flag = K_F;
									break;
			case K_F : 
									if(c == 'K')
									{
										flag = O_F;
										ok_flag = 1;
									}
									else
										flag = O_F;
									break;
		}
	}
}

void esp8266_init(void)//初始化的函数(初始化串口)
{
	usart_2_init();
}

void esp8266_link_wifi(char *ssid, char *passwd)//连接路由(需要路由的名称和路由的密码)
{
	//AT+RST\r\n 重启无线模块
	usart_2_send_data("AT+RST\r\n");
	delay_ms(2000);//重启之后延时两秒
	
	//AT+CWMODE=1\r\n 选择wifi模式
	ok_flag = 0;
	usart_2_send_data("AT+CWMODE=1\r\n");//选择模式
	while(ok_flag == 0);//等待esp8266的OK
	
	//AT+CWJAP="SSID","password"\r\n 连接路由
	ok_flag = 0;
	usart_2_send_data("AT+CWJAP=");
	usart_2_send_byte('"');
	usart_2_send_data(ssid);
	usart_2_send_byte('"');
	usart_2_send_byte(',');
	usart_2_send_byte('"');
	usart_2_send_data(passwd);
	usart_2_send_byte('"');
	usart_2_send_data("\r\n");
	while(ok_flag == 0);
	
	//AT+CIFSR\r\n 查询分配到的IP地址(必须要查一下,否则无法建立连接)
	usart_2_send_data("AT+CIFSR\r\n");
}

void esp8266_connect(char *ip, char *port)//连接TCP server
{
	//AT+CIPSTART="TCP","192.168.3.116",8080\r\n 建立TCP连接
	ok_flag = 0;
	usart_2_send_data("AT+CIPSTART=");
	usart_2_send_byte('"');
	usart_2_send_data("TCP");
	usart_2_send_byte('"');
	usart_2_send_byte(',');
	usart_2_send_byte('"');
	usart_2_send_data(ip);
	usart_2_send_byte('"');
	usart_2_send_byte(',');
	usart_2_send_data(port);
	usart_2_send_data("\r\n");
	while(ok_flag == 0);
}

void esp8266_disconnect(void)//断开TCP连接
{
	//AT+CIPCLOSE\r\n 断开TCP连接
	usart_2_send_data("AT+CIPCLOSE\r\n");
	//注意:有可能回复有可能不回复,所以不检测closed ok
}

void esp8266_send(char *msg, char *len)//发送数据
{
	//AT+CIPSEND=4\r\n 发送数据
	ok_flag = 0;
	usart_2_send_data("AT+CIPSEND=");
	usart_2_send_data(len);
	usart_2_send_data("\r\n");
	while(ok_flag == 0);//等待 OK
	
	ok_flag = 0;
	while(ok_flag == 0);//等待 >
	
	ok_flag = 0;
	usart_2_send_data(msg);
	while(ok_flag == 0);//等待 SEND OK
}












main.c

#include "led.h"//包含LED灯的头文件
#include "buzzer.h"//包含BUZZER的头文件
#include "button.h"//包含BUTTON的头文件
#include "delay.h"//包含DELAY的头文件
#include "eint.h"//包含EINT的头文件
#include "iwdg.h"//包含IWDG的头文件
#include "dht.h"//包含DHT的头文件
#include "ldt.h"//包含LDT的头文件
#include "usart1.h"//包含USART1的头文件
#include "stdio.h"//包含标准输入输出的头文件
#include "eeprom.h"//包含EEPROM的头文件
#include "oled.h"//包含OLED的头文件
#include "sht.h"//包含SHT30的头文件
#include "adj_res.h"//包含高精度可调电阻的头文件
#include "rtc.h"//包含RTC的头文件
#include "esp8266.h"//包含ESP8266的头文件
#include "string.h"//包含字符串解析的头文件

void recv_handler(char *buf, int len)//buf里存储的是数据的内容 len里存的是数据的字节数
{
	if(strcmp(buf, "BUZZER_ON") == 0)
		buzzer_on();
	if(strcmp(buf, "BUZZER_OFF") == 0)
		buzzer_off();
}

int main(void)
{
	char dht_buf[5] = {0};//该数组用于存储DHT11采集到的数据
	int dht_value = 0;//该变量用于存储DHT11温湿度结合的数据
	int i = 500;//循环变量
	int adc_value = 0;//存储高精度可调电阻转换的数据
	u8 old_value = 97;//存储要保存的数据
	u8 new_value = 0;//存储读取出的数据
	double sht_data[2] = {0};//用于存储SHT30传感器采集到的数据
	struct time_st old_time = {2021, 11, 29, 1, 15, 0, 0};//要设置的时间
	struct time_st new_time;//保存获取到的时间
	
	led_init();//调用LED灯初始化的函数
	buzzer_init();//调用蜂鸣器初始化的函数
	button_init();//调用功能按键初始化的函数
	delay_init();//调用系统定时器初始化的函数
	eint_init();//调用按键中断初始化的函数
	dht_init();//调用DHT11初始化的函数
	ldt_init();//调用数码管初始化的函数
	usart_1_init();//调用USART1初始化的函数
	eeprom_init();//调用EEPROM初始化的函数
	OLED_Init();//调用OLED初始化的函数
	sht_init();//调用SHT30初始化的函数
	adj_res_init();//调用高精度可调电阻初始化的函数
	rtc_init(&old_time);//调用RTC初始化的函数
	esp8266_init();//调用ESP8266初始化的函数
	
	OLED_Clear();//清屏
	
	//OLED_ShowChar(0, 0, '%', 16);
	//OLED_ShowNum(0, 0, 9527, 4, 16);
	//OLED_ShowString(0, 0, "Hello World!", 16);
	//OLED_ShowCHinese(0, 0, 7);
	picture_1();
	
	sht_write_mode();//设置SHT30的采样频率
	
	led_on(0);
	esp8266_link_wifi("UPIOT", "easthome");//需要填写自己的手机热点(需要配置为2.4GHz的频段)
	delay_ms(2000);//延时2s
	led_off(0);
	
	led_on(1);
	esp8266_connect("192.168.248.41", "2222");//建立TCP连接
	delay_ms(2000);//延时2s
	led_off(1);
	
	//eeprom_byte_write(0xA0, 0x11, old_value);//写数据
	
	set_wifi_recv_handler(recv_handler);//设置回调函数
	
	while(1)
	{
		esp8266_send("Hello World", "11");
		adc_value = get_adj_res_value();//获取高精度可调电阻转换的数据
		get_time(&new_time);//把获取到的时间保存到new_time变量中
		get_dht_value(dht_buf);//获取DHT11传感器采集到的数据
		new_value = eeprom_rand_addr_read(0xA0, 0x11);//读取EEPROM的数据
		sht_read_mode();//发送采集SHT30数据的指令
		sht_read_data(sht_data);//获取SHT30采集的数据
		printf("%d-%d-%d %d %02d:%02d:%02d\n", new_time.Y, new_time.M, new_time.D, new_time.W, new_time.h, new_time.m, new_time.s);
		printf("DHT:%d-%d Eeprom:%d SHT:%.2f-%.2f ADC:%d\n", dht_buf[0], dht_buf[2], new_value, sht_data[0], sht_data[1], adc_value);
		dht_value = dht_buf[0] * 100 + dht_buf[2];//把湿度的整数以及温度的整数整合成一个4位数据
		while(i--)
			digit_show_data(dht_value);//通过数码管显示温湿度数据
		i = 500;
		led_on(0);
		delay_ms(500);
		led_off(0);
		delay_ms(500);
	}
}











  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ESP8266是一款低成本、低功耗的Wi-Fi模块,它可以作为一个独立的微控制器运行,也可以作为其他主控芯片的Wi-Fi模块使用。ARP(Address Resolution Protocol)是一种网络协议,用于将IP地址映射到MAC地址。 在ESP8266实现ARP功能的代码如下: ```c #include <ESP8266WiFi.h> #include <WiFiUdp.h> IPAddress targetIP; // 目标IP地址 uint8_t targetMAC; // 目标MAC地址 void sendARPRequest() { // 创建ARP请求数据包 uint8_t packet[42] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 目标MAC地址(广播地址) 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, // 源MAC地址(ESP8266的MAC地址) 0x08, 0x06, // 帧类型(ARP) 0x00, 0x01, // 硬件类型(以太网) 0x08, 0x00, // 协议类型(IPv4) 0x06, // 硬件地址长度(6字节) 0x04, // 协议地址长度(4字节) 0x00, 0x01, // 操作码(ARP请求) 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, // 发送方MAC地址(ESP8266的MAC地址) 192, 168, 1, 1, // 发送方IP地址 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 目标MAC地址(未知) targetIP, targetIP, targetIP, targetIP // 目标IP地址 }; // 发送ARP请求数据包 WiFiUDP udp; udp.beginPacket(targetIP, 0); udp.write(packet, sizeof(packet)); udp.endPacket(); } void handleARPResponse() { // 接收ARP响应数据包 WiFiUDP udp; int packetSize = udp.parsePacket(); if (packetSize == sizeof(packet)) { uint8_t packet[42]; udp.read(packet, sizeof(packet)); // 解析目标MAC地址 for (int i = 0; i < 6; i++) { targetMAC[i] = packet[22 + i]; } } } void setup() { Serial.begin(115200); // 连接Wi-Fi网络 WiFi.begin("SSID", "password"); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } // 设置目标IP地址 targetIP = IPAddress(192, 168, 1, 2); // 发送ARP请求 sendARPRequest(); } void loop() { // 处理ARP响应 handleARPResponse(); // 打印目标MAC地址 Serial.print("Target MAC address: "); for (int i = 0; i < 6; i++) { Serial.print(targetMAC[i], HEX); if (i < 5) { Serial.print(":"); } } Serial.println(); delay(5000); } ``` 上述代码实现了在ESP8266上发送ARP请求并接收ARP响应的功能。在`setup()`函数中,首先连接到Wi-Fi网络,然后设置目标IP地址,并发送ARP请求。在`loop()`函数中,处理接收到的ARP响应,并打印目标MAC地址。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值