进行这个之前首选要知道几个理解知识和工具。
下面是当时找的相关文档和资料连接:
ESP8266笔记 ---- 常用AT指令_esp8266 at-CSDN博客
esp8266WIFI模块教程:正点原子ATK-ESP8266进行网络通信,单片机与电脑,单片机与手机发送数据_正点原子esp8266-CSDN博客
【常用模块】ESP8266 WIFI串口通信模块使用详解(实例:附STM32详细代码)_正点原子wifiesp8266提供代码-CSDN博客
最有用的是乐鑫官方给的AT指令操作示例:
TCP-IP AT 示例 - ESP32 - — ESP-AT 用户指南 latest 文档 (espressif.com)
首先说说AT指令:
AT指令,也称为Attention指令,是应用于终端设备与PC应用之间的连接与通信的指令。这些指令是从终端设备(Terminal Equipment,TE)或数据终端设备(Data Terminal Equipment,DTE)向终端适配器(Terminal Adapter,TA)或数据电路终端设备(Data Circuit Terminal Equipment,DCE)发送的。AT指令主要用于控制移动台(Mobile Station,MS)的功能,与GSM网络业务进行交互。
工具:串口工具(调试助手),网络调试助手。
下面了解一下当时使用的WIFI模块:
https://docs.ai-thinker.com/_media/esp8266/docs/esp-12f_product_specification_zh_v1.0.pdf
型号:安信可ESP-12F。
模块的定义与尺寸图:

引脚定义:

模组启动模式:

推荐的电路连接方式(正常工作模式)

下载步骤:
下载模式需要把只需要把GPIO0接到地,rst先浮空,配置好flash下载软件之后,先点击擦除,之后会等待上电复位,将rst用杜邦线触碰一下地,即可开始烧录,此时等待烧录完毕,将GPIO接到高电平,重新上电即可正常使用AT指令集。
连接调试示意图:

使用串口助手操作时的相关信息显示:

当前程序具备收发功能,请注意,由于我的编程习惯可能不够规范,代码可能显得有些凌乱,建议仔细阅读和理解代码逻辑。
本程序在开发过程中参考了正点原子的代码,在使用串口助手进行调试时,务必确保所有发送的指令后都加上换行符。这是AT指令集的规定,如果不加换行符,指令将无法正确执行,并返回错误提示。
网络调试助手需设置为TCP服务器模式。在选择服务器的IP地址时,请确保它与wifi芯片所分配的IP地址处于同一网段。例如,如果通过查询得到的IP地址是192.168.137.89,掩码是255.255.255.0,那么服务器的IP地址前三个数字也应为192.168.137。设置好IP地址后,您可以在网络调试助手中选择相应的IP号,并使用默认的通道号进行通信。
TCP/IP是网络通信的基础协议,对于理解和使用网络通信至关重要。虽然在这里只需简要了解,但建议深入学习TCP/IP协议的相关知识,以便更好地进行网络编程和调试。
在完成上述注意点的检查和调整后,您可以重新生成程序,确保所有设置和配置都已正确无误,然后进行测试和验证。


当时测试时使用的开发板与wifi串口芯片:

连接参考图:

可以正常运行的代码:
void mywifi_uart_init(void)
{
// GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能USART2,GPIOA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
// USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // PA.2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化GPIOA.2
// USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // PA3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化GPIOA.3
// Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
NVIC_Init(&NVIC_InitStructure); // 根据指定的参数初始化VIC寄存器
// USART 初始化设置
USART_InitStructure.USART_BaudRate = 115200; // 串口波特率
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(USART2, &USART_InitStructure); // 初始化串口2
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // 开启串口接受中断
USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); // 开启串口空闲中断
USART_Cmd(USART2, ENABLE); // 使能串口1
}
/**
* @description: 给wifi芯片传输指定长度数据
* @param {char} *data 传输数据
* @param {u8} len 传输数据长度
* @return {*}
*/
void mywifi_send_nbytes(char *data, u8 len)
{
for (int i = 0; i < len; i++)
{
USART_SendData(USART2, data[i]); // 发送测试
while (!USART_GetFlagStatus(USART2, USART_FLAG_TC))
; // 等待发送完成
}
}
/**
* @description: wifi发送数据
* @param {char} *cmd数据
* @param {char} *ack期待的应答
* @param {u32} timeout超时
* @param {u8} len数据长度
* @return {*}
*/
u8 mywifi_send_at_cmd(char *cmd, char *ack, u32 timeout, u8 len)
{
char *ret = NULL; // 用于接收数据
// atk_mw8266d_uart_rx_restart();
// 正点原子有一个硬件复位的过程,这里没设置了,
mywifi_send_nbytes(cmd, len);
if ((ack == NULL) || (timeout == 0))
{
return MYWIFI_OK;
}
else
{
while (timeout > 0)
{
if (mywifi_recv_data(ret))
{
if (strstr((const char *)mywifi_recv_buf, ack) != NULL) // ack 作为子串去查询
{
// mywifi_send_nbytes(mywifi_recv_buf, sizeof(mywifi_recv_buf));
return MYWIFI_OK;
}
else
{
// 不同则复位
// atk_mw8266d_uart_rx_restart();
}
}
timeout--;
delay_ms(1);
}
return MYWIFI_ERROR; // 这里代表超时
}
}
/**
* @description: 接收数据
* @param {char} *data
* @return {*} 返回当前是否完成了数据接收
*/
u8 mywifi_recv_data(char *data)
{
char temp[MAX_LENGTH] = {0}; // 测试使用
if (rev_finish_flag == 1)
{
// 当前接收完成
data = mywifi_recv_buf; // 先预留的,目前我没有用到
strncpy(temp, mywifi_recv_buf, receive_number);
rev_finish_flag = 0;
receive_number = 0;
// printf("the rec data : \r\n");
// printf("%s", temp);
return 1;
}
else
return 0;
}
/**
* @description: wifi自检测
* @return {*} 自检成功返回1
*/
u8 mywifi_self_test(void)
{
char test[] = {"AT\r\n"};
char ack[] = {"OK"};
u8 flag = 0;
for (u8 i = 0; i < 50; i++)
{
flag = mywifi_send_at_cmd(test, (char *)ack, 20, sizeof(test) / sizeof(test[0]));
char temp[MAX_LENGTH] = {0};
while (strstr((const char *)temp, "busy") != NULL) // 等待忙完成
{
// 等待不忙,才执行后面的,这里写的有点问题,没有达到预期的效果
memset(temp, 0, MAX_LENGTH);
strncpy(temp, mywifi_recv_buf, temp_rec_num);
flag = mywifi_send_at_cmd(test, (char *)ack, 20, sizeof(test) / sizeof(test[0]));
rev_finish_flag = 0;
temp_rec_num = 0;
// 开机都忙等待的话直接给它硬件复位
}
if (flag)
return flag;
}
return flag; // 自检测5次,最后一次成功表示成功
}
/**
* @description: wifi软件重启,这个操作在自检测成功之后
* @return {*}
*/
char soft_rst[] = {"AT+RST\r\n"};
void mywifi_soft_rst(void)
{
mywifi_send_at_cmd(soft_rst, NULL, 20, sizeof(soft_rst) / sizeof(soft_rst[0]));
}
/**
* @description: WiFi回显开关
* @param {u8} flag
* @return {*}
*/
char polldispaly0[] = {"ATE0\r\n"};
char polldispaly1[] = {"ATE1\r\n"};
void mywifi_polldispaly(u8 flag)
{
mywifi_send_at_cmd(flag ? polldispaly0 : polldispaly1, "OK", 20, sizeof(polldispaly0) / sizeof(polldispaly0[0]));
}
/**
* @description: wifi设置工作模式,站点模式 Or AP模式
* @param {u8} mode 1表示设置为站点模式
* @return {*}
*/
char set_mode0[] = {"AT+CWMODE=0\r\n"};
char set_mode1[] = {"AT+CWMODE=1\r\n"};
void mywifi_set_mode(u8 mode)
{
mywifi_send_at_cmd(mode ? set_mode1 : set_mode0, "OK", 20, sizeof(set_mode0) / sizeof(set_mode0[0]));
}
/**
* @description: 芯片连接到热点,这里我默认是我电脑的热点
* @return {*}
*/
char connecet_host[] = {"AT+CWJAP=\"mldesk\",\"12345671\"\r\n"};
bool mywifi_connect_host(void)
{
mywifi_send_at_cmd(connecet_host, "OK", 4000, sizeof(connecet_host) / sizeof(connecet_host[0]));
delay_ms(4000);
return true;
}
/**
* @description: 获取wifi连接获取的ip地址
* @return {*}
*/
char get_ip[] = {"AT+CIPSTA?\r\n"};
void mywifi_get_ip(void)
{
char temp[MAX_LENGTH] = {0};
while (strstr((const char *)temp, "OK") == NULL)
{
// 等待不忙,才执行后面的
memset(temp, 0, MAX_LENGTH);
strncpy(temp, mywifi_recv_buf, temp_rec_num);
rev_finish_flag = 0;
temp_rec_num = 0;
}
mywifi_send_at_cmd(get_ip, NULL, 2000, sizeof(get_ip) / sizeof(get_ip[0]));
delay_ms(1000);
// 获取ip号先保存起来之后使用,这个打来之后是会调硬件错误的,可能是数组超了
// if (rev_finish_flag == 1)
// {
// // 当前接收完成
// u8 i = 0;
// rev_finish_flag = 0;
// for (; i < temp_rec_num; i++)
// {
// if ((mywifi_recv_buf[i] == 0x69) && (mywifi_recv_buf[i + 1] == 0x70))
// break;
// }
// // 找到了ip地址的位置
// memset(temp, 0, MAX_LENGTH);
// strncpy(temp, mywifi_recv_buf + i + 4, 15);
// temp_rec_num = 0;
// //printf("%s",temp);
// }
}
/**
* @description: 判断热点是否连接
* @return {*}
*/
bool mywifi_judge_host_connect(void)
{
if ((strstr((const char *)mywifi_recv_buf, "CONNCETED") != NULL) ||
(strstr((const char *)mywifi_recv_buf, "GOT") != NULL))
{
printf("\r\nconnecet_host ok\r\n");
// 成功之后设置相应的标志位,比如可以用来连接tcp服务器
wifi_connect_flag = 1; // wifi 连接成功
return true;
}
else if ((strstr((const char *)mywifi_recv_buf, "DISCONNECT") != NULL))
{
printf("\r\nconnecet_host error\r\n");
// 失败时候需要将相应标志位清除,显示连接丢失
wifi_connect_flag = 0; // wifi 连接失败
return false;
}
return false;
}
/**
* @description: wifi芯片作为client 连接到服务器
* @return {*}
*/
char connecet_sever[] = {"AT+CIPSTART=\"TCP\",\"192.168.137.1\",8080\r\n"};
void mywifi_connect_sever(void)
{
if (wifi_connect_flag) // 需要保证wifi连接成功之后设置tcpip单路连接
{
char temp[MAX_LENGTH] = {0};
while (strstr((const char *)temp, "OK") == NULL)
{
// 等待上一次指令完成,才执行后面的
memset(temp, 0, MAX_LENGTH);
strncpy(temp, mywifi_recv_buf, temp_rec_num);
rev_finish_flag = 0;
temp_rec_num = 0;
}
mywifi_send_at_cmd(connecet_sever, "OK", 2000, sizeof(connecet_sever) / sizeof(connecet_sever[0]));
delay_ms(1000);
}
}
/**
* @description: 设置透传模式
* @param {u8} flag 1 表示透传 0 表示关闭透传发送+++
* @return {*}
*/
char open_transparent[] = {"AT+CIPMODE=1\r\n"};
char close_transparent[] = {"AT+CIPMODE=0\r\n"};
char send_data_cmd[] = {"AT+CIPSEND\r\n"};
char fade_transparent[] = {"+++"};
void mywifi_set_transparent(u8 flag)
{
if (flag)
{
mywifi_send_at_cmd(open_transparent, "OK", 200, sizeof(open_transparent) / sizeof(open_transparent[0]));
delay_ms(1000);
mywifi_send_at_cmd(send_data_cmd, ">", 200, sizeof(send_data_cmd) / sizeof(send_data_cmd[0]));
}
else
{
delay_ms(2000); // 需要等待一秒,结束透传
mywifi_char_printf("+++"); // 发送结束标志
delay_ms(4000); // 需要等待一秒,结束透传
mywifi_send_at_cmd("\r\n", NULL, 200, 0);
mywifi_send_at_cmd(close_transparent, "OK", 200, sizeof(close_transparent) / sizeof(close_transparent[0]));
mywifi_close_tcp_connection(); // 断开tcp连接
}
}
/**
* @description: 通过透传模式进行输出传输
* @param {u8} *data
* @param {u8} len
* @return {*}
*/
void mywifi_data_send(u8 *data, u8 len)
{
if (wifi_connect_flag) // 需要保证wifi连接成功,服务器连接成功,才能进行输出传输
{
mywifi_send_at_cmd(data, NULL, 0, len); // 数据发送,需要等待
}
}
/**
* @description: 断开tcp连接
* @return {*}
*/
char close_tcp[] = {"AT+CIPCLOSE\r\n"};
void mywifi_close_tcp_connection(void)
{
mywifi_send_at_cmd(close_tcp, "OK", 200, sizeof(close_tcp) / sizeof(close_tcp[0]));
}
/**
* @description: 判断是否结束透传,需要通过服务器发送+++,判断
* @return {*}
*/
void mywifi_judge_tranfer_end(void)
{
}
/**
* @description: 用于打印+++,推出透传模式
* @param {char} *fmt
* @return {*}
*/
void mywifi_char_printf(char *fmt, ...)
{
va_list ap;
uint16_t len;
char cmd[MAX_LENGTH] = {0};
va_start(ap, fmt);
vsprintf((char *)cmd, fmt, ap);
va_end(ap);
len = strlen((const char *)cmd);
mywifi_send_nbytes(cmd, len);
}
/**
* @description: 串口2中断回调函数
* @return {*}
*/
void USART2_IRQHandler()
{
static char res; // 静态变量防止堆栈溢出
static u32 temp;
char temp1[MAX_LENGTH] = {0}; // 静态变量防止堆栈溢出
if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
res = USART_ReceiveData(USART2); // 读取接收到的数据
if (receive_number >= MAX_LENGTH) // 防止刷爆
receive_number = MAX_LENGTH - 1;
mywifi_recv_buf[receive_number] = res;
receive_number++;
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
}
if (USART_GetFlagStatus(USART2, USART_FLAG_IDLE) != RESET) // 命中空闲中断
{
/*---------------使用串口1打印从wifi芯片接收到的数据--------*/
strncpy(temp1, mywifi_recv_buf, receive_number);
temp_rec_num = receive_number;
printf("%s", temp1);
/*----------------end-------------------------------------*/
rev_finish_flag = 1;
// 判断wifi是否断开连接
mywifi_judge_host_connect();
// 判断服务器是否断开连接
// ------还没实现,可以通过各个指令不同的返回值去判定
// 下面这个操作是必要的,清除空闲中断标志位
temp = USART2->SR;
temp = USART2->DR;
USART_ClearITPendingBit(USART2, USART_IT_IDLE); // 清除空闲中断标志位
receive_number = 0;
}
}
我要赚赏金
