微信小程序和stm32+esp8266采用tcp协议通信(f103标准库,具体例子)
时间: 2023-12-06 11:39:51 浏览: 206
要实现微信小程序和STM32+ESP8266之间的TCP通信,需要在STM32上使用TCP协议栈来实现TCP连接和数据传输。在这里,我以STM32F103为例,使用标准库进行开发。
首先,需要在STM32上初始化ESP8266模块并建立TCP连接。下面是一个简单的示例代码:
```c
#include "stm32f10x.h"
#include "stdio.h"
#include "string.h"
// ESP8266连接信息
#define WIFI_SSID "your_ssid"
#define WIFI_PASSWORD "your_password"
#define TCP_SERVER_IP "192.168.1.100"
#define TCP_SERVER_PORT 1234
// 接收缓冲区大小
#define RX_BUF_SIZE 1024
// 接收缓冲区
uint8_t rx_buf[RX_BUF_SIZE];
uint16_t rx_index = 0;
// USART1初始化函数
void USART1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 使能USART1和GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置PA9为推挽输出,TXD
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置PA10为浮空输入,RXD
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// USART1初始化
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
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_Tx | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
// 使能USART1
USART_Cmd(USART1, ENABLE);
}
// 发送数据到USART1
void USART1_SendData(uint8_t *data, uint16_t len)
{
for(uint16_t i = 0; i < len; i++)
{
USART_SendData(USART1, data[i]);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
}
// 接收数据
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
rx_buf[rx_index++] = USART_ReceiveData(USART1);
}
}
// 初始化ESP8266
void ESP8266_Init(void)
{
// 等待模块启动完成
DelayMs(500);
// 发送AT指令,检查模块是否正常
ESP8266_SendCmd("AT\r\n");
if(!ESP8266_WaitResponse("OK", 1000))
{
printf("ESP8266 init failed!\r\n");
while(1);
}
// 设置WIFI模式为STA
ESP8266_SendCmd("AT+CWMODE=1\r\n");
if(!ESP8266_WaitResponse("OK", 1000))
{
printf("ESP8266 set mode failed!\r\n");
while(1);
}
// 连接WIFI
ESP8266_SendCmd("AT+CWJAP=\"" WIFI_SSID "\",\"" WIFI_PASSWORD "\"\r\n");
if(!ESP8266_WaitResponse("OK", 5000))
{
printf("ESP8266 connect wifi failed!\r\n");
while(1);
}
// 获取本地IP地址
ESP8266_SendCmd("AT+CIFSR\r\n");
if(!ESP8266_WaitResponse("+CIFSR:STAIP,\"", 1000))
{
printf("ESP8266 get ip failed!\r\n");
while(1);
}
// 解析IP地址
uint8_t *ip_str = strstr((char *)rx_buf, "+CIFSR:STAIP,\"");
uint8_t *ip_end = strstr((char *)ip_str + 15, "\"");
if(ip_str && ip_end)
{
*ip_end = 0;
printf("ESP8266 IP: %s\r\n", ip_str + 15);
}
else
{
printf("ESP8266 parse ip failed!\r\n");
while(1);
}
}
// 建立TCP连接
void TCP_Connect(void)
{
// 发送AT指令,建立TCP连接
char cmd[128];
sprintf(cmd, "AT+CIPSTART=\"TCP\",\"%s\",%d\r\n", TCP_SERVER_IP, TCP_SERVER_PORT);
ESP8266_SendCmd(cmd);
if(!ESP8266_WaitResponse("CONNECT", 5000))
{
printf("TCP connect failed!\r\n");
while(1);
}
}
int main(void)
{
// 初始化USART1
USART1_Init();
// 初始化ESP8266
ESP8266_Init();
// 建立TCP连接
TCP_Connect();
while(1)
{
// 发送数据到服务器
uint8_t data[] = "Hello, world!";
uint16_t len = sizeof(data) - 1;
char cmd[128];
sprintf(cmd, "AT+CIPSEND=%d\r\n", len);
ESP8266_SendCmd(cmd);
if(!ESP8266_WaitResponse(">", 1000))
{
printf("TCP send data failed 1!\r\n");
continue;
}
USART1_SendData(data, len);
if(!ESP8266_WaitResponse("SEND OK", 1000))
{
printf("TCP send data failed 2!\r\n");
continue;
}
}
}
```
在上面的代码中,我们使用USART1与ESP8266模块进行通信,并在USART1的中断服务函数中接收数据。在初始化ESP8266模块后,我们首先连接WIFI并获取本地IP地址,然后通过发送AT指令来建立TCP连接。在建立连接后,我们可以通过发送AT指令和USART1将数据发送到服务器。
接下来,我们需要通过TCP协议栈来实现TCP连接和数据传输。使用TCP协议栈可以使我们更方便地控制TCP连接,并提供更高效的数据传输。下面是一个简单的TCP客户端示例代码:
```c
#include "stm32f10x.h"
#include "stdio.h"
#include "string.h"
#include "lwip/opt.h"
#include "lwip/arch.h"
#include "lwip/api.h"
#include "lwip/tcp.h"
#include "lwip/tcpip.h"
#include "netif/etharp.h"
// ESP8266连接信息
#define WIFI_SSID "your_ssid"
#define WIFI_PASSWORD "your_password"
#define TCP_SERVER_IP "192.168.1.100"
#define TCP_SERVER_PORT 1234
// 接收缓冲区大小
#define RX_BUF_SIZE 1024
// 接收缓冲区
uint8_t rx_buf[RX_BUF_SIZE];
uint16_t rx_index = 0;
// TCP协议栈任务
void tcp_task(void *arg)
{
struct netconn *conn = NULL;
err_t err;
struct netbuf *buf;
// 创建TCP连接
conn = netconn_new(NETCONN_TCP);
if(conn == NULL)
{
printf("TCP connect failed!\r\n");
return;
}
err = netconn_connect(conn, IP_ADDR_ANY, TCP_SERVER_PORT);
if(err != ERR_OK)
{
printf("TCP connect failed!\r\n");
return;
}
while(1)
{
// 接收数据
err = netconn_recv(conn, &buf);
if(err != ERR_OK)
{
continue;
}
// 处理数据
uint16_t len = buf->p->tot_len;
uint8_t *data = malloc(len);
if(data != NULL)
{
uint16_t index = 0;
struct pbuf *q;
for(q = buf->p; q != NULL; q = q->next)
{
memcpy(data + index, q->payload, q->len);
index += q->len;
}
printf("TCP recv data: %s\r\n", data);
free(data);
}
// 释放缓冲区
netbuf_delete(buf);
}
}
// USART1初始化函数
void USART1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// 使能USART1和GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置PA9为推挽输出,TXD
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置PA10为浮空输入,RXD
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// USART1初始化
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
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_Tx | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
// 使能USART1
USART_Cmd(USART1, ENABLE);
// USART1中断配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 使能USART1接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
}
// 发送数据到USART1
void USART1_SendData(uint8_t *data, uint16_t len)
{
for(uint16_t i = 0; i < len; i++)
{
USART_SendData(USART1, data[i]);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
}
// 接收数据
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
rx_buf[rx_index++] = USART_ReceiveData(USART1);
}
}
// 初始化ESP8266
void ESP8266_Init(void)
{
// 等待模块启动完成
DelayMs(500);
// 发送AT指令,检查模块是否正常
ESP8266_SendCmd("AT\r\n");
if(!ESP8266_WaitResponse("OK", 1000))
{
printf("ESP8266 init failed!\r\n");
while(1);
}
// 设置WIFI模式为STA
ESP8266_SendCmd("AT+CWMODE=1\r\n");
if(!ESP8266_WaitResponse("OK", 1000))
{
printf("ESP8266 set mode failed!\r\n");
while(1);
}
// 连接WIFI
ESP8266_SendCmd("AT+CWJAP=\"" WIFI_SSID "\",\"" WIFI_PASSWORD "\"\r\n");
if(!ESP8266_WaitResponse("OK", 5000))
{
printf("ESP8266 connect wifi failed!\r\n");
while(1);
}
// 获取本地IP地址
ESP8266_SendCmd("AT+CIFSR\r\n");
if(!ESP8266_WaitResponse("+CIFSR:STAIP,\"", 1000))
{
printf("ESP8266 get ip failed!\r\n");
while(1);
}
// 解析IP地址
uint8_t *ip_str = strstr((char *)rx_buf, "+CIFSR:STAIP,\"");
uint8_t *ip_end = strstr((char *)ip_str + 15, "\"");
if(ip_str && ip_end)
{
*ip_end = 0;
printf("ESP8266 IP: %s\r\n", ip_str + 15);
}
else
{
printf("ESP8266 parse ip failed!\r\n");
while(1);
}
}
int main(void)
{
// 初始化USART1
USART1_Init();
// 初始化ESP8266
ESP8266_Init();
// 初始化TCP协议栈
tcpip_init(NULL, NULL);
// 创建TCP协议栈任务
sys_thread_new("tcp_task", tcp_task, NULL, 512, 2);
while(1)
{
// 发送数据到服务器
uint8_t data[] = "Hello, world!";
uint16_t len = sizeof(data) - 1;
char cmd[128];
sprintf(cmd, "AT+CIPSEND=%d\r\n", len);
ESP8266_SendCmd(cmd);
if(!ESP8266_WaitResponse(">", 1000))
{
printf("TCP send data failed 1!\r\n");
continue;
}
USART1_SendData(data, len);
if(!ESP8266_WaitResponse("SEND OK", 1000))
{
printf("TCP send data failed 2!\r\n");
continue;
}
}
}
```
在上面的代码中,我们使用lwIP协议栈来实现TCP连接和数据传输。首先,我们需要在主函数中调用tcpip_init函数来初始化lwIP协议栈。然后,我们创建一个TCP协议栈任务,并在任务中使用netconn_new函数创建一个TCP连接。在循环中,我们使用netconn_recv函数接收数据,并使用netbuf_delete函数释放缓冲区。
在主函数中,我们使用USART1与ESP8266模块进行通信,并在USART1的中断服务函数中接收数据。在初始化ESP8266模块后,我们首先连接WIFI并获取本地IP地址,然后通过发送AT指令和USART1将数据发送到服务器。
阅读全文