前言
上一篇我们已经能够使用单片机去实现物联网了,后面单片机的原理也是差不多,建议把上篇和中篇都看过实践一遍后,下篇的思路一看就能明白
因为上篇和中篇的思路我已经讲得很清楚了,本篇直接给代码,不做讲解。
用法和中篇最后说的一样
esp8266.c
#include "esp8266.h"
#include "tim.h"
#include "gpio.h"
#include "usart.h"
#include "stdio.h"
#include "string.h"
/**
* @brief ESP8266通信相关的全局变量
*/
uint8_t esp8266_buffer[128],esp8266_buff[1],esp8266_len=0,esp8266_flag=0;
uint16_t esp8266_time=0;
char esp8266_wait[100];
/**
* @brief TCP服务器连接模式的配置参数
*/
const char ESP8266_WIFI_SSID[]="lty2";
const char ESP8266_WIFI_PassWord[]="2395832518";
const char ESP8266_WIFI_TCP_IP[]="112.125.89.8";
const char ESP8266_WIFI_TCP_PORT[]="42137";
/**
* @brief 主机模式的配置参数
*/
const char ESP8266_WIFI_SSID_main[]="ESP8266_A";
const char ESP8266_WIFI_PassWord_main[]="";
char ESP8266_WIFI_TCP_IP_main[20]="192.168.4.1";
uint8_t esp8266_connect_main_port=0;
/**
* @brief 从机模式的配置参数
*/
const char ESP8266_WIFI_SSID_other[]="ESP8266_A";
const char ESP8266_WIFI_PassWord_other[]="";
char ESP8266_WIFI_TCP_IP_other[20]="192.168.4.1";
uint8_t esp8266_connect_other_port=80;
/*---------------------------- 初始化相关函数 ----------------------------*/
/**
* @brief ESP8266模块初始化
* @note 启动定时器中断和串口接收中断
*/
void ESP8266_Init(void)
{
HAL_TIM_Base_Start_IT(ESP8266_TIM);
HAL_UART_Receive_IT(ESP8266_UART,(uint8_t *)esp8266_buff,1);
}
/*---------------------------- 连接模式函数 ----------------------------*/
/**
* @brief TCP服务器连接模式的AT命令处理
* @param cmd: 命令类型(0-8)
* @param leng: 发送数据长度(仅在cmd=7时使用)
* @note 处理TCP服务器连接相关的AT命令序列
*/
void ESP8266_TCP_CONNECT(uint8_t cmd,uint16_t leng)
{
char buffer[100];
switch(cmd)
{
case 0:
sprintf(buffer,"AT+RST\r\n");
sprintf(esp8266_wait,"OK");
break;
case 1:
sprintf(buffer,"AT\r\n");
sprintf(esp8266_wait,"OK");
break;
case 2:
sprintf(buffer,"AT+CWMODE=1\r\n");
sprintf(esp8266_wait,"OK");
break;
case 3:
sprintf(buffer,"AT+CWJAP=\"%s\",\"%s\"\r\n",ESP8266_WIFI_SSID,ESP8266_WIFI_PassWord);
sprintf(esp8266_wait,"WIFI GOT IP");
break;
case 4:
sprintf(buffer,"AT+CWJAP?\r\n");
sprintf(esp8266_wait,"OK");
break;
case 5:
sprintf(buffer,"AT+CIPMUX=0\r\n");
sprintf(esp8266_wait,"OK");
break;
case 6:
sprintf(buffer,"AT+CIPSTART=\"TCP\",\"%s\",%s\r\n",ESP8266_WIFI_TCP_IP,ESP8266_WIFI_TCP_PORT);
sprintf(esp8266_wait,"OK");
break;
case 7:
sprintf(buffer,"AT+CIPSEND=%d\r\n",leng);
sprintf(esp8266_wait,"");
break;
case 8:
sprintf(buffer,"");
sprintf(esp8266_wait,"SEND OK");
break;
}
ESP8266_commom(buffer);
}
/**
* @brief 主机模式的AT命令处理
* @param cmd: 命令类型(0-11)
* @param leng: 发送数据长度(仅在cmd=10时使用)
* @note 处理ESP8266作为主机时的AT命令序列
*/
void ESP8266_CONNECT_main(uint8_t cmd,uint16_t leng)
{
char buffer[100];
switch(cmd)
{
case 0:
sprintf(buffer,"AT+RST\r\n");
sprintf(esp8266_wait,"OK");
break;
case 1:
sprintf(buffer,"AT\r\n");
sprintf(esp8266_wait,"OK");
break;
case 2:
sprintf(buffer,"AT+CWMODE=2\r\n");
sprintf(esp8266_wait,"OK");
break;
case 3:
sprintf(buffer,"AT+CWSAP=\"%s\",\"%s\",1,0\r\n",ESP8266_WIFI_SSID_main,ESP8266_WIFI_PassWord_main);
sprintf(esp8266_wait,"OK");
break;
case 4:
sprintf(buffer,"AT+CIFSR\r\n");
sprintf(esp8266_wait,"OK");
break;
case 5:
sprintf(buffer,"");
sprintf(esp8266_wait,"STA_CONNECTED");
break;
case 6:
sprintf(buffer,"AT+CIPMUX=1\r\n");
sprintf(esp8266_wait,"OK");
break;
case 7:
sprintf(buffer,"AT+CIPSERVER=1,80\r\n");
sprintf(esp8266_wait,"OK");
break;
case 8:
sprintf(buffer,"AT+CIFSR\r\n");
sprintf(esp8266_wait,"OK");
break;
case 9:
sprintf(buffer,"+++\r\n");
sprintf(esp8266_wait,"CONNECT");
break;
case 10:
sprintf(buffer,"AT+CIPSEND=%d,%d\r\n",esp8266_connect_main_port,leng);
sprintf(esp8266_wait,"");
break;
case 11:
sprintf(buffer,"");
sprintf(esp8266_wait,"SEND OK");
break;
}
ESP8266_commom(buffer);
}
/**
* @brief 从机模式的AT命令处理
* @param cmd: 命令类型(0-7)
* @param leng: 发送数据长度(仅在特定cmd时使用)
* @note 处理ESP8266作为从机时的AT命令序列
*/
void ESP8266_CONNECT_Other(uint8_t cmd,uint16_t leng)
{
char buffer[100];
switch(cmd)
{
case 0:
sprintf(buffer,"AT+RST\r\n");
sprintf(esp8266_wait,"OK");
break;
case 1:
sprintf(buffer,"AT\r\n");
sprintf(esp8266_wait,"OK");
break;
case 2:
sprintf(buffer,"AT+CWMODE=1\r\n");
sprintf(esp8266_wait,"OK");
break;
case 3:
sprintf(buffer,"AT+CWJAP=\"%s\",\"%s\"\r\n",ESP8266_WIFI_SSID_other,ESP8266_WIFI_PassWord_other);
sprintf(esp8266_wait,"WIFI GOT IP");
break;
case 4:
sprintf(buffer,"AT+CIPMUX=0\r\n");
sprintf(esp8266_wait,"OK");
break;
case 5:
sprintf(buffer,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",ESP8266_WIFI_TCP_IP_other,esp8266_connect_other_port);
sprintf(esp8266_wait,"CONNECT");
break;
case 6:
sprintf(buffer,"AT+CIPMODE=1\r\n");
sprintf(esp8266_wait,"OK");
break;
case 7:
sprintf(buffer,"AT+CIPSEND\r\n");
sprintf(esp8266_wait,"OK");
break;
}
ESP8266_commom(buffer);
}
/*---------------------------- 连接控制函数 ----------------------------*/
/**
* @brief ESP8266通用AT命令发送和等待响应
* @param cmd: AT命令字符串
* @note 发送AT命令并等待预期响应,超时会重试
*/
void ESP8266_commom(const char *cmd)
{
HAL_UART_Transmit(ESP8266_UART,(uint8_t *)cmd,strlen(cmd),100);
esp8266_flag=0;
while (esp8266_flag==0){
if (esp8266_time>1000)
{
HAL_UART_Transmit(ESP8266_UART,(uint8_t *)cmd,strlen(cmd),100);
esp8266_time=0;
}
}
}
/**
* @brief 连接到TCP服务器的完整初始化过程
* @note 按顺序执行TCP连接所需的AT命令序列
*/
void ESP8266_CONNECT_TO_TCP()
{
for(uint8_t i = 0; i < 7; i++)
{
ESP8266_TCP_CONNECT(i,0);
printf("cmd=%d\r\n",i);
HAL_Delay(500);
}
}
/**
* @brief 切换ESP8266为主机模式
* @note 执行主机模式初始化所需的AT命令序列
*/
void ESP8266_change_to_main()
{
for(uint8_t i = 0; i < 10; i++)
{
ESP8266_CONNECT_main(i,0);
printf("main cmd=%d\r\n",i);
HAL_Delay(500);
}
}
/**
* @brief 切换ESP8266为从机模式
* @note 执行从机模式初始化所需的AT命令序列
*/
void ESP8266_change_to_other()
{
for(uint8_t i = 0; i < 8; i++)
{
ESP8266_CONNECT_Other(i,0);
printf("other cmd=%d\r\n",i);
HAL_Delay(500);
}
}
/*---------------------------- 数据发送函数 ----------------------------*/
/**
* @brief 向TCP服务器发送数据
* @param data: 要发送的数据字符串
* @note 使用TCP服务器连接模式发送数据
*/
void ESP8266_send_TCP(const char *data)
{
ESP8266_TCP_CONNECT(7,strlen(data));
HAL_UART_Transmit(ESP8266_UART,(uint8_t *)data,strlen(data),100);
ESP8266_TCP_CONNECT(8,0);
}
/**
* @brief 主机模式下发送数据
* @param data: 要发送的数据字符串
* @note 使用主机模式发送数据
*/
void ESP8266_main_send_data(const char *data)
{
ESP8266_CONNECT_main(10,strlen(data));
HAL_UART_Transmit(ESP8266_UART,(uint8_t *)data,strlen(data),100);
ESP8266_CONNECT_main(11,0);
}
/**
* @brief 从机模式下发送数据
* @param data: 要发送的数据字符串
* @note 使用从机模式发送数据
*/
void ESP8266_other_send_data(const char *data)
{
HAL_UART_Transmit(ESP8266_UART,(uint8_t *)data,strlen(data),100);
}
/*---------------------------- 数据处理函数 ----------------------------*/
/**
* @brief 检查字符串是否包含特定子串
* @param str: 要检查的字符串
* @param substr: 要查找的子串
* @retval 1: 包含子串, 0: 不包含子串
*/
int contains_OK(const char *str, const char *substr) {
if (strstr(str, substr) != NULL) {
return 1;
}
return 0;
}
/**
* @brief ESP8266接收数据处理
* @param 无
* @note 处理接收缓冲区中的数据,包括响应确认和特殊数据处理
*/
void ESP8266_Change()
{
printf("%s\r\n",esp8266_buffer);
if(contains_OK(esp8266_buffer,esp8266_wait))
{
esp8266_flag=1;
}
if(contains_OK(esp8266_buffer,"IPD"))
ESP8266_IPD(esp8266_buffer);
if(contains_OK(esp8266_buffer,"APIP"))
ESP8266_Check_IP(esp8266_buffer);
}
/**
* @brief 处理IPD数据
* @param data: 接收到的IPD数据
* @note 解析并处理+IPD格式的数据
*/
void ESP8266_IPD(const char *data)
{
char *p=data;
uint8_t leng=0;
char hand[256];
if(hand[7]!=esp8266_connect_main_port)
{
p+=6;
while (*p != ':') {
leng = leng * 10 + *p - '0';
p++;
}
p++;
strncpy(hand, p, leng);
hand[leng] = '\0';
printf("hand:%s\r\n", hand);
}
else
{
while (*p!= ':')
{
p++;
}
p++;
while (*p!='\0') {
hand[leng++] = *p;
p++;
}
hand[leng] = '\0';
printf("hand:%s\r\n", hand);
}
}
/**
* @brief 解析并保存ESP8266的IP地址
* @param data: 包含IP信息的字符串
* @note 从CIFSR响应中提取AP模式的IP地址
*/
void ESP8266_Check_IP(const char *data)
{
const char *p = data;
uint8_t leng = 0;
p = strstr(p, "+CIFSR:APIP,\"");
if (p == NULL) {
printf("APIP string not found\r\n");
return;
}
p += strlen("+CIFSR:APIP,\"");
while (*p != '\"' && leng < sizeof(ESP8266_WIFI_TCP_IP_main) - 1) {
ESP8266_WIFI_TCP_IP_main[leng++] = *p;
p++;
}
ESP8266_WIFI_TCP_IP_main[leng] = '\0';
printf("IP:%s\r\n", ESP8266_WIFI_TCP_IP_main);
}
/**
* @brief 从字符串中提取端口号
* @param data: 包含端口信息的字符串
* @retval 提取的端口号,失败返回0
*/
uint8_t extract_port_number(const char *data) {
char temp[20];
strncpy(temp, data, sizeof(temp) - 1);
temp[sizeof(temp) - 1] = '\0';
char *token = strtok(temp, ",");
if (token != NULL) {
return (uint8_t)atoi(token);
}
return 0;
}
/*---------------------------- 中断和回调函数 ----------------------------*/
/**
* @brief ESP8266串口接收中断处理
* @note 处理串口接收到的数据
*/
void ESP8266_UART_Handler(void)
{
esp8266_buffer[esp8266_len++]=esp8266_buff[0];
esp8266_time=0;
HAL_UART_Receive_IT(ESP8266_UART,(uint8_t *)esp8266_buff,1);
}
/**
* @brief ESP8266定时器中断处理
* @note 处理接收超时和数据处理
*/
void ESP8266_Time(void)
{
esp8266_time++;
if((esp8266_time>10)&&(esp8266_len>0))
{
esp8266_buffer[esp8266_len]=0;
ESP8266_Change();
memset(esp8266_buffer, '\0', sizeof(esp8266_buffer));
esp8266_len=0;
esp8266_time=0;
}
}
/**
* @brief 串口接收完成回调函数
* @param huart: 串口句柄
* @note 处理USART2的接收中断
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART2)
{
ESP8266_UART_Handler();
}
}
/**
* @brief 定时器周期回调函数
* @param htim: 定时器句柄
* @note 处理TIM2的定时中断
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM2)
{
ESP8266_Time();
}
}
esp8266.h
#ifndef HC_TR_H
#define HC_TR_H
#include "main.h"
/**
* @brief ESP8266硬件接口定义
*/
#define ESP8266_UART &huart2 /* ESP8266使用的串口 */
#define ESP8266_TIM &htim2 /* ESP8266使用的定时器 */
/*---------------------------- 初始化相关函数 ----------------------------*/
void ESP8266_Init(void);
/*---------------------------- 连接模式函数 ----------------------------*/
void ESP8266_TCP_CONNECT(uint8_t cmd, uint16_t leng);
void ESP8266_CONNECT_main(uint8_t cmd, uint16_t leng);
void ESP8266_CONNECT_Other(uint8_t cmd, uint16_t leng);
/*---------------------------- 连接控制函数 ----------------------------*/
void ESP8266_commom(const char *cmd);
void ESP8266_CONNECT_TO_TCP(void);
void ESP8266_change_to_main(void);
void ESP8266_change_to_other(void);
/*---------------------------- 数据发送函数 ----------------------------*/
void ESP8266_send_TCP(const char *data);
void ESP8266_main_send_data(const char *data);
void ESP8266_other_send_data(const char *data);
/*---------------------------- 数据处理函数 ----------------------------*/
int contains_OK(const char *str, const char *substr);
void ESP8266_Change(void);
void ESP8266_IPD(const char *data);
void ESP8266_Check_IP(const char *data);
/*---------------------------- 中断和回调函数 ----------------------------*/
void ESP8266_UART_Handler(void);
void ESP8266_Time(void);
#endif /* HC_TR_H */