#include #include #include "systick.h" #include "queue.h" #include "esp8266.h" /* USART2管脚定义 TX PA2 RX PA3 */ // 创建USART2的接收队列。 static struct queue usart2_rx_queue; // 重置 Wifi 模块的传输模式为工作站模式,成功返回1,失败返回0. int esp8266_reset_module(void) { char buf[100]; // 重置Wifi模块 esp8266_send_cmd("AT+RST"); delay_ms(1000); delay_ms(1000); esp8266_clear_read_buf(); // 设置Wifi的工作模式为 工作站模式 esp8266_send_cmd("AT+CWMODE=1"); if (esp8266_read_response(buf, sizeof(buf), 1000) == 0) return 0; if (strstr(buf, "OK")) return 1; return 0; } // ESP8266初始化 void esp8266_init(void) { GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; // 初始化接收队列 queue_init(&usart2_rx_queue); // 使能PA2和 PA3的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能 USART2外设时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); // 设置PA2 为发送管脚 // 复用推挽输出 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); // 设置PA3 为接受管脚 // 悬空输入 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3; GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化 USART1控制器 USART_InitStruct.USART_BaudRate = 115200; // 设置波特率 USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 字长8bit USART_InitStruct.USART_StopBits = USART_StopBits_1; // 停止位1bit USART_InitStruct.USART_Parity = USART_Parity_No; // 校验位(无) USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 收发 USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 硬件流控制(无) USART_Init(USART2, &USART_InitStruct); // 使能串口2 USART_Cmd(USART2, ENABLE); // 初始化接收中断 USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // 清理中断标志位 USART_ClearFlag(USART2, USART_FLAG_TC); NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn; // 中断通道 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); // 开启接收寄存器非空中断 // USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); if (0 == esp8266_reset_module()) printf("reset Wifi module Error!\r\n"); } // 编写冲断处理函数 void USART2_IRQHandler(void) { uint8_t ch; // 如果是接收寄存器非空中断,则读取数据 if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) { ch = USART_ReceiveData(USART2); // 将接收到的字符放入接收队列,如果队列已满会丢掉此字符 queue_enqueue(&usart2_rx_queue, ch); } } // 用于串口发送一个字节的数据 void usart2_put_char(uint8_t ch) { USART_SendData(USART2, ch); // 发送数据 // 等待发送数据完毕 while (USART_GetFlagStatus(USART2, USART_FLAG_TC) != SET) ; } // ESP8266通过USART2发送字符串数据 void esp8266_send_string(const char *buf) { const char *pchar; for (pchar = buf; *pchar; ++pchar) usart2_put_char((uint8_t)*pchar); } // ESP8266通过USART2发送AT指令 void esp8266_send_cmd(const char *cmd) { esp8266_send_string(cmd); esp8266_send_string("\r\n"); } // 从USART2 读取相应字符串放入 buf,总等待时长timeout_ms毫秒ms, // 直到timeout_ms耗尽为0才返回 int esp8266_read_response(char *buf, int buf_size, int timeout_ms) { int i = 0; int ch = '\0'; // 等待接收数据,最大等待 timeout_ms 微妙 while (--timeout_ms) { if (queue_is_empty(&usart2_rx_queue)) delay_ms(1); else break; } if (timeout_ms == 0) // 超时返回 return 0; // 接收数据 while (i < buf_size - 1 && timeout_ms > 0) { if (queue_is_empty(&usart2_rx_queue)) { delay_ms(1); // 继续等待,直至timeout_ms为零 timeout_ms--; } else { queue_dequeue(&usart2_rx_queue, &ch); buf[i] = ch; i++; } } buf[i] = '\0'; // 添加尾零后返回数据 // debug print for response printf("esp8266_resp: %s\r\n", buf); return i; // for (i = 0; i < buf_size -1; i++) { // queue_dequeue(&usart2_rx_queue, &ch); // buf[i] = ch; // if (queue_is_empty(&usart2_rx_queue)) // delay_ms(1); // if (queue_is_empty(&usart2_rx_queue)) { // i++; // buf[i] = '\0'; // return i; // } // } // return i; } // ESP8266 连接 Wifi,成功返回1,失败返回0 int esp8266_connect_wifi(const char *ssid, const char *passwd) { char buf[100]; // 拼接命令字符串 sprintf(buf, "AT+CWJAP=\"%s\",\"%s\"", ssid, passwd); esp8266_clear_read_buf(); // 清空读缓冲。 esp8266_send_cmd(buf); // WiFi 连接可能需要较长时间,延长超时到 15s if (0 == esp8266_read_response(buf, sizeof(buf), 15000)) return 0; if (strstr(buf, "OK") != NULL) return 1; // print returned response for debugging printf("esp8266_connect_wifi failed resp: %s\r\n", buf); return 0; } // ESP8266 作为客户端远程 TCP 连接。成功返回1,失败返回0 int esp8266_tcp_connect(const char *ip, uint16_t port) { char buf[100]; // 拼接命令字符串 sprintf(buf, "AT+CIPSTART=\"TCP\",\"%s\",%d", ip, port); esp8266_clear_read_buf(); // 清空读缓冲。 esp8266_send_cmd(buf); if (0 == esp8266_read_response(buf, sizeof(buf), 8000)) return 0; // some firmwares may return "OK" or "ALREADY" or "ERROR" if (strstr(buf, "OK") != NULL || strstr(buf, "ALREADY") != NULL) return 1; printf("esp8266_tcp_connect resp: %s\r\n", buf); return 0; } // 关闭tcp 连接 void esp8266_tcp_close(void) { esp8266_send_cmd("AT+CIPCLOSE"); delay_ms(1000); esp8266_clear_read_buf(); // 清空读缓冲。 } // ESP8266 TCP 协议发送数据,返回写入的字节数,0表示失败 int esp8266_write(const char *data, uint16_t len) { char buf[100]; // 拼接命令字符串 sprintf(buf, "AT+CIPSEND=%d", len); esp8266_clear_read_buf(); // 清空读缓冲。 esp8266_send_cmd(buf); // wait for prompt '>' (and optionally OK). Allow longer timeout for some modules. if (0 == esp8266_read_response(buf, sizeof(buf), 8000)) return 0; // If there's no '>' in the response, but OK is present, try to read again shortly if (strstr(buf, ">") == NULL) { if (strstr(buf, "OK") != NULL) { // try a short additional read to get the '>' prompt if (0 == esp8266_read_response(buf, sizeof(buf), 2000) || strstr(buf, ">") == NULL) { printf("esp8266_write: no '>' prompt after CIPSEND, resp: %s\r\n", buf); return 0; } } else { printf("esp8266_write: unexpected resp to CIPSEND: %s\r\n", buf); return 0; } } // send payload esp8266_send_string(data); // wait for SEND OK (some firmwares reply with SEND OK) if (0 == esp8266_read_response(buf, sizeof(buf), 5000)) { // no response, still consider write as attempted return len; } if (strstr(buf, "SEND OK") != NULL || strstr(buf, "OK") != NULL) { return len; } // unknown response, but we've attempted send printf("esp8266_write: post-send resp: %s\r\n", buf); return len; } // ESP8266 读取数据,返回读取的字节数 uint16_t esp8266_read(char *data, uint16_t buf_size) { // accumulate reads and search for +IPD, length:data pattern char tmp[128]; char acc[512]; int acc_len = 0; int total_timeout = 5000; // total wait up to 5s int step = 200; // per-read timeout acc[0] = '\0'; while (total_timeout > 0 && acc_len < (int)sizeof(acc) - 1) { int r = esp8266_read_response(tmp, sizeof(tmp), step); if (r > 0) { // append int copy = r < (int)sizeof(acc) - 1 - acc_len ? r : (int)sizeof(acc) - 1 - acc_len; memcpy(acc + acc_len, tmp, copy); acc_len += copy; acc[acc_len] = '\0'; // debug printf("esp8266_acc: %s\r\n", acc); // search for +IPD, char *pfind = strstr(acc, "+IPD,"); if (pfind) { pfind += 5; // move past +IPD, // parse number until ':' int len = 0; while (*pfind && *pfind != ':' && len < 100000) { if (*pfind >= '0' && *pfind <= '9') len = len * 10 + (*pfind - '0'); pfind++; } if (*pfind == ':') { pfind++; // data start int copylen = len < (int)buf_size - 1 ? len : (int)buf_size - 1; // ensure we have enough bytes in acc; if not, try to read more briefly int available = (int)(acc + acc_len - pfind); if (available < copylen) { // try one more short read int r2 = esp8266_read_response(tmp, sizeof(tmp), 500); if (r2 > 0) { int c = r2 < (int)sizeof(acc) - 1 - acc_len ? r2 : (int)sizeof(acc) - 1 - acc_len; memcpy(acc + acc_len, tmp, c); acc_len += c; acc[acc_len] = '\0'; } } // copy payload memcpy(data, pfind, copylen); data[copylen] = '\0'; return (uint16_t)copylen; } } } else { total_timeout -= step; } } return 0; } // ESP8266 清空读缓冲区 void esp8266_clear_read_buf(void) { queue_clear(&usart2_rx_queue); }