nucleo-f411re学习记录-12,Wifi模块ESP8684

代码仓库

本次使用的外设是WiFi模块ESP8484,该模块搭载AT固件,可通过AT指令进行配置和操作,其通信方式与蓝牙模块类似。模块通过串口与MCU连接,用MCU的最后一个可用串口UART1来实现通信。

建议在连接WiFi前,先通过USB转TTL连接模块,使用电脑发送AT指令测试模块功能是否正常。

初始化

c 复制代码
void UART_WIFI_Init(uint32_t buad)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    USART_InitTypeDef USART_InitStruct;

    //时钟开启
    RCC_AHB1PeriphClockCmd(UARTx_WIFI_GPIO_CLK, ENABLE);
    RCC_APB2PeriphClockCmd(UARTx_WIFI_RCC_CLK, ENABLE);
	//串口1对应引脚复用映射
	GPIO_PinAFConfig(UARTx_WIFI_TX_GPIO_PORT, UARTx_WIFI_TX_PIN_SOURCE, UARTx_WIFI_TX_AF);
	GPIO_PinAFConfig(UARTx_WIFI_RX_GPIO_PORT, UARTx_WIFI_RX_PIN_SOURCE, UARTx_WIFI_RX_AF);
    /* Reset GPIO init structure parameters values */
    GPIO_InitStruct.GPIO_Pin    = UARTx_WIFI_TX_PIN | UARTx_WIFI_RX_PIN;
    GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_Speed  = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_OType  = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd   = GPIO_PuPd_UP;
    GPIO_Init(UARTx_WIFI_TX_GPIO_PORT, &GPIO_InitStruct);
    
    /* USART_InitStruct members default value */
    USART_InitStruct.USART_BaudRate               = buad;
    USART_InitStruct.USART_WordLength             = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits               = USART_StopBits_1;
    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(UARTx_WIFI, &USART_InitStruct);

    // 使能接收中断 (RXNE)
    USART_ITConfig(UARTx_WIFI, USART_IT_RXNE, ENABLE);
    //使能
    USART_Cmd(UARTx_WIFI, ENABLE);
}

也是由中断来接收数据

c 复制代码
void NVIC_WIFI_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
        
    NVIC_InitStructure.NVIC_IRQChannel                      = USART1_IRQn;  // 中断通道为 USART1
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority    = 0;            // 抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority           = 1;            // 响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd                   = ENABLE;       // 使能中断
    NVIC_Init(&NVIC_InitStructure);
}
void USART1_IRQHandler(void)
{
    if (USART_GetITStatus(UARTx_WIFI, USART_IT_RXNE) != RESET)
    {
        if (USARTx_WIFI_Rx_Index < 4096)
        {
            USARTx_WIFI_Rx_Data[USARTx_WIFI_Rx_Index++] = (uint8_t)USART_ReceiveData(UARTx_WIFI);
        }
        else
        {
            // 缓冲区满,丢弃数据并重置索引
            (void)USART_ReceiveData(UARTx_WIFI);
            USARTx_WIFI_Rx_Index = 0;  // 重置避免溢出
        }
    }
    // printf("Received: %.*s\r\n", USARTx_WIFI_Rx_Index, USARTx_WIFI_Rx_Data);
}

接收后的数据处理任务

c 复制代码
void Wifi_RxTask(void *pvParameters)
{
    uint16_t len;
    uint16_t last_index = 0;
    uint32_t last_recv_time = 0;
    while (1)
    {
        if (USARTx_WIFI_Rx_Index > 0)
        {
            if (last_index != USARTx_WIFI_Rx_Index) 
            {
                // 有新的数据到达,更新时间戳
                last_index = USARTx_WIFI_Rx_Index;
                last_recv_time = xTaskGetTickCount();
            } 
            // 检查是否超过10ms没有新数据
            else if ((xTaskGetTickCount() - last_recv_time) > pdMS_TO_TICKS(50) && last_index == USARTx_WIFI_Rx_Index) 
            {
                // 超时,认为接收完成
                taskENTER_CRITICAL();
                len = USARTx_WIFI_Rx_Index;
                USARTx_WIFI_Rx_Index = 0;
                taskEXIT_CRITICAL();
                last_index = 0;
                printf("Received: %.*s\r\n", len, USARTx_WIFI_Rx_Data);
            }
        }
        else {
            last_index = 0;  // 重置
        }
        
        vTaskDelay(pdMS_TO_TICKS(1));  // 1ms轮询
    }
}

发送接口

c 复制代码
uint16_t USARTx_Wifi_Send(uint8_t *data, uint16_t length)
{
    USARTx_Wifi_TxPacket_t packet;
        // 检查队列是否已创建
    if (USARTx_Wifi_TxQueue == NULL)
    {
        printf("Queue not initialized!\r\n");
        return USART_WIFI_QUEUE_CREATION_FAILED;
    }
//    printf("Queueing data for transmission: %.*s\r\n", length, data);
    packet.length = length;
    if (packet.length > 1024) 
        return USART_WIFI_SEND_LEN_ERROR;
    memcpy(packet.buffer, data, packet.length);
    BaseType_t ret = xQueueSend(USARTx_Wifi_TxQueue, &packet, pdMS_TO_TICKS(100));
    if (ret != pdTRUE)
    {
        printf("Queue send failed!\r\n");
        return USART_WIFI_QUEUE_SEND_FAILED;
    }
    return 0;
}

发送任务

c 复制代码
void Wifi_TxTask(void *pvParameters)
{
    USARTx_Wifi_TxPacket_t packet;
    USARTx_Wifi_TxQueue = xQueueCreate(10, sizeof(USARTx_Wifi_TxPacket_t));
        // 添加队列创建失败的检查
    if (USARTx_Wifi_TxQueue == NULL)
    {
        printf("USARTx_Wifi_TxQueue creation failed!\r\n");
        while(1);  // 队列创建失败,停机(喂狗任务也无法执行,会复位)
    }
    printf("USARTx_Wifi_TxQueue created successfully.\r\n");
    while(1)
    {
        if (xQueueReceive(USARTx_Wifi_TxQueue, &packet, portMAX_DELAY) == pdTRUE)
        {
            // printf("Sending data: %.*s\r\n", packet.length, packet.buffer);
            for (int i = 0; i < packet.length; i++)
            {
                USART_SendData(UARTx_WIFI, packet.buffer[i]);
                while (USART_GetFlagStatus(UARTx_WIFI, USART_FLAG_TXE) == RESET);
            }
        }
    }
}

先使用几个AT指令测试通讯是否正常

c 复制代码
uint16_t Wifi_Send_AT_Command(char *command)
{
    return USARTx_Wifi_Send((uint8_t *)command, strlen(command));
}
static uint16_t Wifi_command_init(void)
{
    Wifi_Send_AT_Command("AT\r\n");// 测试AT启动
    vTaskDelay(pdMS_TO_TICKS(100));

    Wifi_Send_AT_Command("ATE0\r\n");// 关闭回显
    vTaskDelay(pdMS_TO_TICKS(100));

//    Wifi_Send_AT_Command("AT+GMR\r\n");// 查看版本信息
//    vTaskDelay(pdMS_TO_TICKS(100));
    
    Wifi_Send_AT_Command("AT+CWHOSTNAME?\r\n");// 查询作为Station时的名称
    vTaskDelay(pdMS_TO_TICKS(100));
    return 0;
}

void Wifi_Init_Task(void *pvParameters)
{
    printf("Wifi initialization task started\r\n");
    
    while (xWifiTxTaskHandle == NULL || xWifiRxTaskHandle == NULL)
    {
        vTaskDelay(pdMS_TO_TICKS(50));  // 等待50ms再检查
    }
    
    // 额外延迟一点,确保队列等资源也初始化完成
    vTaskDelay(pdMS_TO_TICKS(100));
    
    // 执行wifi初始化
    printf("Starting Wifi AT commands...\r\n");
    Wifi_command_init();
    
    printf("Wifi initialization completed, deleting this task\r\n");
    vTaskDelete(NULL);
}

测试结果

c 复制代码
Serial communication is normal
Free heap before any task: 0 bytes
After Key_Task: 40592 bytes
After Feeddog_Task: 40360 bytes
After Wifi_TxTask: 36160 bytes
After Wifi_RxTask: 31960 bytes
After Wifi_Init_Task: 29808 bytes
USARTx_Wifi_TxQueue created successfully.
Wifi initialization task started
Starting Wifi AT commands...
Received: 
OK

Received: 
OK

Received: +CWHOSTNAME:espressif

OK

Wifi initialization completed, deleting this task

注意:当之后若是打开多个外设,需要创建多个任务,那么就需要合理分配堆栈空间

c 复制代码
static void All_Task_Create(void)
{
    printf("Free heap before any task: %d bytes\r\n", xPortGetFreeHeapSize());
    
    xTaskCreate(Key_Task, "Key_Task", 64, NULL, 1, NULL);
    printf("After Key_Task: %d bytes\r\n", xPortGetFreeHeapSize());
    
    xTaskCreate(Feeddog_Task, "Feeddog_Task", 32, NULL, 1, NULL);
    printf("After Feeddog_Task: %d bytes\r\n", xPortGetFreeHeapSize());

    if(dht11_init_flag)
    {
        xTaskCreate(DHT11_Read_Task, "DHT11_Task", 512, NULL, 2, NULL);
        printf("After DHT11_Read_Task: %d bytes\r\n", xPortGetFreeHeapSize());
    }

#if USE_PERIPHERALS_ROCKER
    xTaskCreate(Rocker_Read_Task, "Rocker_Task", 1024, NULL, 2, NULL);
    printf("After Rocker_Read_Task: %d bytes\r\n", xPortGetFreeHeapSize());
#endif

#if USE_PERIPHERALS_BT
    xTaskCreate(BT_TxTask, "BT_TxTask", 512, NULL, 2, &xBTTxTaskHandle);
    printf("After BT_TxTask: %d bytes\r\n", xPortGetFreeHeapSize());
    
    xTaskCreate(BT_RxTask, "BT_RxTask", 512, NULL, 2, &xBTRxTaskHandle);
    printf("After BT_RxTask: %d bytes\r\n", xPortGetFreeHeapSize());

    xTaskCreate(Bluetooth_Init_Task, "Bluetooth_Init_Task", 512, NULL, 3, NULL);
    printf("After Bluetooth_Init_Task: %d bytes\r\n", xPortGetFreeHeapSize());
#endif
    
#if USE_PERIPHERALS_WIFI
    xTaskCreate(Wifi_TxTask, "Wifi_TxTask", 1024, NULL, 2, &xWifiTxTaskHandle);
    printf("After Wifi_TxTask: %d bytes\r\n", xPortGetFreeHeapSize());

    xTaskCreate(Wifi_RxTask, "Wifi_RxTask", 1024, NULL, 2, &xWifiRxTaskHandle);
    printf("After Wifi_RxTask: %d bytes\r\n", xPortGetFreeHeapSize());

    xTaskCreate(Wifi_Init_Task, "Wifi_Init_Task", 512, NULL, 2, NULL);
    printf("After Wifi_Init_Task: %d bytes\r\n", xPortGetFreeHeapSize());
#endif
}

或者设置大一些的总堆空间

c 复制代码
#define configTOTAL_HEAP_SIZE                        (40 * 1024)

不然会一直重启。

相关推荐
吃好睡好便好14 小时前
在Matlab中绘制阶梯图
开发语言·人工智能·学习·算法·机器学习·matlab
Restart-AHTCM14 小时前
LangChain学习之提示词模板 (Prompts) - 练习(2/8)
学习·langchain
YangYang9YangYan14 小时前
2026产品专员学习数据分析的价值与路径
学习·数据挖掘·数据分析
淘矿人14 小时前
【AI大模型】AI 大模型推理平台完整测评:8 家主流聚合服务对比分析
人工智能·sql·gpt·学习·github·php
我想我不够好。15 小时前
2026.5.20 消防监控学习 1.5hour
学习
爱喝水的鱼丶15 小时前
SAP-ABAP:数据类型与数据对象(8篇) 第七篇:进阶优化篇——基于类型与对象特征的性能优化技巧
运维·数据库·学习·性能优化·sap·abap·开发交流
知识分享小能手15 小时前
Flask入门学习教程,从入门到精通, 认识Flask路由 — 知识点详解 (2)
python·学习·flask
清平乐的技术专栏15 小时前
【Flink学习】(六)Flink 三大时间语义 + 水位线 Watermark
大数据·学习·flink
楼兰公子16 小时前
《深入理解Linux网络技术内幕》配套学习大纲 + 源码Demo + 进阶实战实例
linux·arm开发·学习
楼田莉子16 小时前
C++17新特性:结构化绑定/inline变量/if相关的变化
c++·后端·学习