乐鑫官方FreeRTOS相关文档:FreeRTOS 概述 - ESP32 - — ESP-IDF 编程指南 latest 文档

FreeRTOS 是一个开源的 RTOS(实时操作系统)内核,它以组件的形式集成到 ESP-IDF 中。因此,所有的 ESP-IDF 应用程序及多种 ESP-IDF 组件都基于 FreeRTOS 编写。FreeRTOS 内核已移植到 ESP 芯片的所有 CPU 架构(即 Xtensa 和 RISC-V)中。

此外,ESP-IDF 还提供了不同的 FreeRTOS 实现,支持在多核 ESP 目标芯片上的 SMP(对称多处理)。

FreeRTOS™

适用于微控制器和小型微处理器的实时操作系统

FreeRTOS™ - FreeRTOS™

FreeRTOS 是一款市场领先的嵌入式系统, RTOS 支持 40 多种处理器架构,内存占用小,执行时间快,具有尖端的 RTOS 功能和库,包括对称多处理 (SMP)、具有 IPv6 支持的线程安全 TCP 堆栈以及与云服务的无缝集成。它是开源的,并得到了积极的支持和维护。

RTOS 基础知识

实时操作系统概述

引言

实时操作系统 (RTOS) 是一种体积小巧、确定性强的计算机操作系统。 RTOS 通常用于需要在严格时间限制内对外部事件做出反应的嵌入式系统,如医疗设备和汽车电子控制单元 (ECU)。 通常,此类嵌入式系统中只有一两项功能需要确定性时序,即使嵌入式系统不需要严格的实时反应,使用 RTOS 仍能提供诸多优势。 请参阅常见问题:“为什么使用 RTOS?”。

RTOS 通常比通用操作系统体积更小、重量更轻,因此 RTOS 非常适用于 内存、计算和功率受限的设备。

支持的设备

硬件合作伙伴 支持的处理器系列 支持的工具
A
Altera Cyclone V SoC (ARM Cortex-A9)、Nios II Altera SoC EDS(配备 GCC 的 ARM DS-5)、配备 GCC 的 Nios II IDE
ARMv8-M
请注意,此类别仅适用于模拟目标。其他 ARMv8-M 目标属于其各自的供应商类别。
ARM Cortex-M33 模拟器 GCC(和构建 FreeRTOS ARMv8-M GCC 移植的 ARMclang)
Atmel SAMV7 (ARM Cortex-M7)、SAM3 (ARM Cortex-M3)、SAM4 (ARM Cortex-M4)、SAMD20 (ARM Cortex-M0+)、SAMA5 (ARM Cortex-A5)、SAM7 (ARM7)、SAM9 (ARM9)、AT91、AVR 和 AVR32 UC3 IAR、GCC、Keil、Rowley CrossWorks
C
Cadence Tensilica Xtensa 配备 Xtensa Xplora IDE 的 XCC
CEVA SensPro、SensPro2、CEVA-BX1、CEVA-BX2、CEVA-X1、CEVA-X2、CEVA-XC16、CEVA-XM6、CEVA-XM4、CEVA-XC12、CEVA-XC4500 LLVM
Cortus APS3 配备 GCC 的 Cortus IDE
Cypress PSoC 5 ARM Cortex-M3 GCC、ARM Keil 和 RVDS - 都包含在 PSoC Creator IDE 中
F
Freescale Kinetis ARM Cortex-M4、Coldfire V2、Coldfire V1、其他 Coldfire 系列、HCS12、PPC405 和 PPC440(Xilinx 实现)(小型分页内存模型),以及其他贡献的移植 Codewarrior、GCC、Eclipse、IAR
I
Infineon TriCore、XMC4000 (ARM Cortex-M4F)、XMC1000 (ARM Cortex-M0) GCC、Keil、Tasking、IAR
Fujitsu(现为 Spansion FM3 ARM Cortex-M3 32 位(例如 MB91460)和 16 位(例如 MB96340 16FX) Softune、IAR、Keil
L
Luminary Micro/Texas Instruments。另请参阅 TI 所有基于 Luminary Micro ARM Cortex-M3 和 ARM Cortex-M4 的 Stellaris 微控制器 Keil、IAR、Code Red、CodeSourcery GCC、Rowley CrossWorks
M
Microchip
另请参阅 Microsemi(现为 Microchip)
PIC32MX、PIC32MZ、PIC32MZ EF、PIC24、dsPIC33C、dsPIC33E、dsPIC33F、MEC14xx、CEC13xx、CEC17xx、MEC17xx、MEC51xx XC 编译器​编辑
Microsemi MiFive (RISC-V)、SmartFusion、SmartFusion2 IAR、Keil、SoftConsole(使用 Eclipse 的 GCC)
N
NEC(现为 Renesas) V850(32 位)、78K0R(16 位) IAR
Nuvoton NuMicro M2351 (ARM Cortex-M23) IAR、Keil
NXP VEGAboard (RISC-V)、LPC55S6x(ARM Cortex-M33)、LPC1500 (ARM Cortex-M3)、LPC1700 (ARM Cortex-M3)、LPC1800 (ARM Cortex-M3)、LPC1100 (ARM Cortex-M0)、LPC2000 (ARM7)、LPC4000 (ARM Cortex-M4F/ARM Cortex-M0) GCC、Rowley CrossWorks、IAR、Keil、LPCXpresso IDE、Eclipse、MCUXpresso IDE
R
Renesas RZ/A1 / RZ/A2M (ARM Cortex-A9)、RZ/T、RX700 / RX71M、RX600 / RX64M / RX62N / RX63N / RX65N、RX200、RX100、SuperH、RL78、H8/S 以及贡献的移植 GCC、e2 studio、IAR Embedded Workbench、HEW(高性能 Embedded Workbench)
S
SiFive RISC-V RV32 Freedom Studio (GCC)、IAR
Silicon Labs [原为 Energy Micro] EFM32 Gecko(Cortex-M3 和 Cortex-M4F)、8051 兼容微控制器 Simplicity Studio (GCC)、IAR、SDCC
Spansion FM3 ARM Cortex-M3 32 位(例如 MB91460)和 16 位(例如 MB96340 16FX) Softune、IAR、Keil
ST STM32(ARM Cortex-M0、ARM Cortex-M7、ARM Cortex-M3 和 ARM Cortex-M4F)、STR7 (ARM7)、STR9 (ARM9) IAR、Atollic TrueStudio、GCC、Keil、Rowley CrossWorks
T
TI RM48、TMS570、ARM Cortex-M4F MSP432、MSP430、MSP430X、SimpleLink、Stellaris(ARM Cortex-M3、ARM Cortex-M4F) Rowley CrossWorks、IAR、GCC、Code Composer Studio
X
Xilinx Zynq、Zynq UltraScale+ MPSoC(64 位 ARM Cortex-A53 和 32 位 ARM Cortex-R5)、Microblaze、在 Virtex4 FPGA 上运行的 PPC405、在 Virtex5 FPGA 上运行的 PPC440 GCC
Intel/x86 IA32(32 位平面内存模型)、Quark SoC X1000(32 位平面内存模型)、各种仅可在实模式下运行的 x86 兼容计算机,以及 Win32 移植Linux 模拟器的移植 也可用。 GCC、Visual Studio 2010 Express、MingW、Open Watcom、Borland、Paradigm
Tricore、MICO32、Blackfin、Jennic、eZ80、SuperH 等 贡献的移植 贡献的移植以“原样”提供,且无法获得直接支持。

里面没有esp32啊,不过这没有关系,乐鑫说支持,就是支持!

FreeRTOS 内核快速入门指南

FreeRTOS 内核快速入门指南 - FreeRTOS™

本页面首先介绍如何尽快在目标设备上运行 RTOS 。下文“后续步骤 — 延伸阅读”部分提供了一组 链接,可帮助您加深对 FreeRTOS 的了解,获得常见问题的解答, 并且更熟练地使用 FreeRTOS。

另请参阅 简单 FreeRTOS 项目入门文档, 为获得更出色的入门体验,也请参阅相关 FreeRTOS 书籍。我们还提供了 FreeRTOS 移植 (适用于 Windows 和 Linux) 以及 QEMU 项目,供您通过免费工具尝试使用 FreeRTOS, 这些工具对硬件没有任何特殊要求。

入门建议

无论您是刚接触 FreeRTOS,还是已经具有丰富的开发经验,我们始终建议您在开发新项目时,先定义 configASSERT(), 实现 malloc 失败钩子函数,并将 configCHECK_FOR_STACK_OVERFLOW 设置为 2。

RTOS 快速入门说明

FreeRTOS 已移植到许多不同的架构和编译器。每个 RTOS 移植 都附带预配置的演示应用程序,可助您快速开始使用。此外,每个演示应用程序 还配有相应的文档页面,提供的信息非常全面,包括如何找到 RTOS 演示项目源代码、构建演示项目以及配置目标 硬件。

演示应用程序文档页面还提供基本的 RTOS 移植特定信息,包括如何编写与 FreeRTOS 兼容的 中断服务程序。这些内容在不同的微控制器架构上可能会略有不同。

按照以下简单说明,几分钟内即可开始运行:

  1. 下载 RTOS 源代码

RTOS 库可通过 Git 分别获取,但最简单的入门方式是下载 FreeRTOS .zip 文件,因为该文件中还包含针对各官方移植的演示项目。请不要被文件数量吓到,实际上,每个演示只需要其中一小部分文件!将文件解压到您认为合适的目录中。

  1. 找到相关文档页面

在“支持的设备”页面中,查看 FreeRTOS 官方支持的微控制器供应商名单。点击微控制器供应商名称,即可跳转至针对该供应商的文档页面列表。

如果没有针对您所用开发板的预配置移植,请参阅修改演示应用程序以在其他硬件上运行页面。

  1. 构建项目

按照 RTOS 移植文档页面上的说明,在 FreeRTOS 目录结构中找到所需的项目,然后打开并构建演示项目。

  1. 运行演示应用程序

按照 RTOS 移植文档页面上的说明设置目标硬件、下载并执行演示应用程序。该文档页面还提供有关演示应用程序功能的信息,助您判断该应用程序是否正确执行。

  1. 创建您自己的项目:

创建自己的 FreeRTOS 项目,最简单的方法是以您所选移植配套的演示应用程序为基础来进行构建。演示应用程序开始运行后,逐渐删除演示函数和源文件,并替换为您自己的应用程序代码。 如在排查故障时需要帮助,请参阅常见问题:“我的应用程序无法运行,问题可能出在哪里?”。

构建您的首个 FreeRTOS 项目

构建您的首个 FreeRTOS 项目 - FreeRTOS™

引言

FreeRTOS 的设计初衷是简单易用:仅需要 3 个 适用所有 RTOS 移植的源文件和 1 个微控制器专用的源文件, 其 API 的设计简单而直观。

FreeRTOS 已移植到许多不同的微控制器架构和许多 不同的编译器。每个官方移植都附有一个官方演示 (至少在创建时),无需任何修改即可在其硬件开发平台上 编译和执行。

提供演示项目是为了确保新用户可以在最短时间内上手使用 FreeRTOS, 最大限度地降低学习和探索成本。

FreeRTOS 支持的每个架构都用于许多不同的微控制器, 这意味着 FreeRTOS 可以在成千上万个各不相同的微控制器上 顺利工作。将此数字乘以支持的编译器数量, 再乘以市面上与日俱增的开发板和开发入门套组, 虽然我们已经尽了最大努力,但很明显的是 我们提供的官方演示只能完全适用于很小一部分的 设备组合。

**强烈建议在新建 FreeRTOS 项目时, 从提供的预配置演示入手,然后进行相应改编。 此举可以确保新项目包含所有必要的源文件和头文件,并安装必要的中断服务例程,无需项目创建者付出额外的努力。 **

一些 FreeRTOS 用户也想知道如何从头开始创建 FreeRTOS 项目, 而不是在已有项目的基础上进行改编。此操作的具体过程 详见下文。

简易 FreeRTOS 演示项目入门

[另请参阅快速入门指南和演示应用程序简介页面。]

立即尝试,使用 Windows 或 Linux 移植,或在 QEMU 中运行

还没有硬件?别担心,您可以在 Windows 或 Linux 环境中使用免费工具 以及 FreeRTOS Windows 或 Linux 移植来运行简易 blinky 演示,但是这些 RTOS 移植都不会表现出 真正的实时行为。 您还可以使用 QEMU 中的 FreeRTOS Arm Cortex-M3 移植运行演示

如果您是初学者,请先不要阅读 Windows 或 Linux RTOS 移植的主文档页面,而是先配置示例, 以使用 blinky 演示(暂时忽略全面演示) 。对于 Windows 的详细说明如下。

实践

按照乐鑫ESP官方文档,使用官方的sample_projetc例子,从头创建一个项目。

将官方sample_projetc例子项目cp到工作目录。比如例子项目在这里:E:\Espressif\frameworks\esp-idf-v5.3.1\examples\get-started\sample_project

工作目录在这里:E:\work\sample_project

进入工作目录进行实践。

内核配置

执行命令进行配置:

idf.py menuconfig

依次进入选项:Component config  --->   FreeRTOS  --->  Kernel  ---> 

常用的内核配置选项:

  • CONFIG_FREERTOS_UNICORE:仅在核 0 上运行 FreeRTOS。注意,这 不等同于运行原生 FreeRTOS。 另外,此选项还可能影响除 freertos 外其他组件的行为。关于在单核上运行 FreeRTOS 的更多内容,请参考 单核模式 (使用 ESP-IDF FreeRTOS 时)或参考 Amazon SMP FreeRTOS 的官方文档,还可以在 ESP-IDF 组件中搜索 CONFIG_FREERTOS_UNICORE

我们选择都不改,就用默认。比如前面讲的CONFIG_FREERTOS_UNICORE

因为ESP32C3只有一个核,所以这里 Run FreeRTOS only on first core   就固定不能修改。

第二个选项,向后兼容,[ ] configENABLE_BACKWARD_COMPATIBILITY  ,默认是不打开的。

端口配置

执行命令进行配置:

idf.py menuconfig

依次进入:Component config  --->   FreeRTOS  --->   Port  --->  

  

这些选项可以配置以下内容:

  • FreeRTOS 端口本身(如 tick 定时器选择,ISR 堆栈大小)

  • 其他添加到 FreeRTOS 实现或端口的功能

当然本次实践我们还是选择啥都不改。

使用 FreeRTOS

应用程序入口点

与原生 FreeRTOS 不同,在 ESP-IDF 中使用 FreeRTOS 的用户 永远不应调用 vTaskStartScheduler() 和 vTaskEndScheduler()。相反,ESP-IDF 会自动启动 FreeRTOS。用户必须定义一个 void app_main(void) 函数作为用户应用程序的入口点,并在 ESP-IDF 启动时被自动调用。

  • 通常,用户会从 app_main 中启动应用程序的其他任务。

  • app_main 函数可以在任何时候返回(应用终止前)。

  • app_main 函数由 main 任务调用。

官方sample_projetc例子项目是空的,啥都没有,只有目录结构,比如main.c文件只有这几句:

#include <stdio.h>
 
void app_main(void)
{
 
}

这里的app_main就是入口,直接在这里面写代码即可。

 

后台任务

在启动过程中,ESP-IDF 和 FreeRTOS 内核会自动创建多个在后台运行的任务,如下表所示。

启动过程创建任务列表

任务名称

描述

堆栈大小

亲和性

优先级

空闲任务 (IDLEx)

为每个 CPU 核创建并分配一个空闲任务 (IDLEx),其中 x 是 CPU 核的编号。 当启用单核配置时,x 将被删除。

CONFIG_FREERTOS_IDLE_TASK_STACKSIZE

核 x

0

FreeRTOS 定时器任务 (Tmr Svc)

如果应用程序调用了任何 FreeRTOS 定时器 API,FreeRTOS 会创建定时器服务或守护任务

CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH

核 0

CONFIG_FREERTOS_TIMER_TASK_PRIORITY

主任务 (main)

简单调用 app_main 的任务在 app_main 返回时会自我删除

CONFIG_ESP_MAIN_TASK_STACK_SIZE

CONFIG_ESP_MAIN_TASK_AFFINITY

1

IPC 任务 (ipcx)

当 CONFIG_FREERTOS_UNICORE 为假时,为每个 CPU 核创建并分配一个 IPC 任务 (ipcx)。IPC 任务用于实现处理器间调用 (IPC) 功能

CONFIG_ESP_IPC_TASK_STACK_SIZE

核 x

24

ESP 定时器任务 (esp_timer)

ESP-IDF 创建 ESP 定时器任务用于处理 ESP 定时器回调

CONFIG_ESP_TIMER_TASK_STACK_SIZE

核 0

22

备注

注意,如果应用程序使用了其他 ESP-IDF 功能(如 Wi-Fi 或蓝牙),那么这些功能可能会在上表的任务之外创建自己的后台任务。

结合使用wifi的例子

例子在:examples\wifi\getting_started\station

添加wifi名字和密码

修改文件:sdkconfig.ci (实验下来好像不太管用)

添加wifi的网络名和口令

CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}"
CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}"

也可以通过`idf.py menuconfig`来添加wifi密码:

在菜单里选: `Example Configuration`然后选set the Wi-Fi configuration,在后面两项里分别填wifi名字和密码:

    * Set `WiFi SSID`.

    * Set `WiFi Password`.

 

station_example_main.c源代码

/* WiFi station Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sys.h"

/* The examples use WiFi configuration that you can set via project configuration menu

   If you'd rather not, just change the below entries to strings with
   the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID      CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS      CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY  CONFIG_ESP_MAXIMUM_RETRY

#if CONFIG_ESP_WPA3_SAE_PWE_HUNT_AND_PECK
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HUNT_AND_PECK
#define EXAMPLE_H2E_IDENTIFIER ""
#elif CONFIG_ESP_WPA3_SAE_PWE_HASH_TO_ELEMENT
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HASH_TO_ELEMENT
#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID
#elif CONFIG_ESP_WPA3_SAE_PWE_BOTH
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_BOTH
#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID
#endif
#if CONFIG_ESP_WIFI_AUTH_OPEN
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN
#elif CONFIG_ESP_WIFI_AUTH_WEP
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP
#elif CONFIG_ESP_WIFI_AUTH_WPA_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA2_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA_WPA2_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA3_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA2_WPA3_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK
#elif CONFIG_ESP_WIFI_AUTH_WAPI_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK
#endif

/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;

/* The event group allows multiple bits for each event, but we only care about two events:
 * - we are connected to the AP with an IP
 * - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

static const char *TAG = "wifi station";

static int s_retry_num = 0;


static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        } else {
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
        }
        ESP_LOGI(TAG,"connect to the AP fail");
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}

void wifi_init_sta(void)
{
    s_wifi_event_group = xEventGroupCreate();

    ESP_ERROR_CHECK(esp_netif_init());

    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
            /* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (password len => 8).
             * If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value
             * to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to
             * WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards.
             */
            .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,
            .sae_pwe_h2e = ESP_WIFI_SAE_MODE,
            .sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
    ESP_ERROR_CHECK(esp_wifi_start() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");

    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);

    /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
     * happened. */
    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }
}

void app_main(void)
{
    //Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
    wifi_init_sta();
}

因为这里用到了wifi,所以没法用qemu,只能上esp32c3开发板了

设置开发板型号

 idf.py set-target esp32c3

编译固件

先在VSCode里面编译,也可以直接使用idf.py文件编译:

idf.py build

上传固件

到ESP-IDF shell里面上传

idf.py -p com4 flash

进入monitor

然后进入monitor连接

idf.py -p com4 monitor

第一次碰到错误,没连上WiFi:

I (14984) wifi station: connect to the AP fail
I (14984) wifi station: Failed to connect to SSID:myssid, password:mypassword
I (14984) main_task: Returned from app_main()

原来wifi名字和密码没有设上去,用idf.py menuconfig把密码设好,再编译,再烧录,再进入monitor,问题搞定!

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐