ESP-IDF 笔记

视频教程来自B站Up主孤独的二进制发布的ESP32系列ESP-IDF课程,使用合宙ESP32C3开发板实际测试,本文整理示例代码及我在合宙esp32c3的实际运行效果。

入门笔记

printf函数

  • demo01
    示例程序功能为使用printf函数输出各类信息
    fflush()函数用于刷新流 stream 的输出缓冲区。
  • 示例代码
#include <stdio.h>

void app_main(void)
{

    printf("Hello world!\n");
    printf("Name:%s\n","Dapenson");
    printf("Char:%c %c\n",'A',65);
    printf("%d年%d月%d日\n",2022,11,21);
    printf("传感器1 %+10.3f\n",12.345);
    printf("传感器2 %+10.3f\n",-11.123);
    printf("传感器3 %+10.3f\n",2.345);

    uint64_t millis = 0x12345678;
    printf("millis:%llu\n",millis);


    fflush(stdout);
}

  • 运行效果

日志

  • demo02
    使用ESP_LOGE()打印日志信息
    通过menu更改底层默认打印设置

当产品出现问题,联系售后的时候,用户如何通过神秘的按键,或者按键的组合方式,输出更多的debug 信息,已便于远程排错。

  • 示例代码
#include <stdio.h>
#include "esp_log.h"

const char *tag_traffic = "交通灯";

bool serer_log = true;

void app_main(void)
{
    // 可通过按钮或变量设置日志打印等级,
    // 需在ESP-IDF: Menuconfig将日志可打印等级(Maximum log verbosity)设置为Verbose
    if (serer_log == true)
    {
        esp_log_level_set(tag_traffic, ESP_LOG_VERBOSE);
    }
    else
    {
        esp_log_level_set(tag_traffic, ESP_LOG_INFO);
    }

    // E error
    ESP_LOGE(tag_traffic, "不亮了");

    // W warning
    ESP_LOGW(tag_traffic, "灯泡寿命还有%i%%", 15);

    // I info
    ESP_LOGI(tag_traffic, "灯泡寿命还有%i%%", 80);

    // D debug
    ESP_LOGD(tag_traffic, "灯泡亮度为1000,已使用200小时");

    // V verbose
    ESP_LOGV(tag_traffic, "灯泡灯丝还有5丝厚度,氧化程度0.23,寿命正常");

    ESP_LOGE("人行横道", "有人闯红灯");
    ESP_LOGW("人行横道", "现在是红灯,禁止通行");
    ESP_LOGI("人行横道", "现在是绿灯,可以通行");
}

  • 运行效果

Tick

  • demo03
    使用延时
    通过menu更改底层默认tick设置(默认100Hz,即一个tick是10ms)

  • 示例代码

#include <stdio.h>
#include "esp_log.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

int count;

void app_main(void)
{
    count = 100;
    ESP_LOGI("COUNTER", "Tick (ms): %d", portTICK_PERIOD_MS);
    while (1)
    {
        ESP_LOGI("COUNTER", "Count: %d", count);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        count++;
    }
}

  • 效果演示

任务看门狗

很多朋友在初试IDF时,经常遇到程序莫名跑飞重启的情况,很有可能是出发了任务看门狗。以下对ESP32中众多狗中的任务看门狗进行实际测试与通过idf menu配置看门狗。

  • demo04

示例代码功能为查看当前所有的任务情况

程序运行之前需要先打开两个配置,否则无法使用vTaskList()函数

#include <stdio.h>
#include "esp_log.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"


char ptrTaskList[250];

void app_main(void)
{

    vTaskList(ptrTaskList);
    printf("**********************************************\n")
    printf("Task         State  Priority  Stack  Num\n");
    printf("**********************************************\n")
    printf("%s", ptrTaskList);
    printf("**********************************************\n")

}

  • 演示效果

可以看到main这个任务优先级是高于idle的,当mian中有死循环且一直没有释放资源的时候,程序就不会去跑idle任务,因此跑飞。
可以将示例程序demo03中的vtaskDelay注释之后查看打印信息,程序每5s会报错重启并继续打印。
在menu中搜索watchdogpanic,可以配置任务看门狗的时间和触发时候的动作等(重启+打印寄存器信息、重启 等)

因此在程序开发的时候,最好不要死循环,让代码有时间来运行idle。

经典的点灯来了

  • demo05
    示例程序功能为闪烁合宙esp32c3的板载左侧LED灯

  • 示例程序

#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define LED_LEFT GPIO_NUM_12
#define LED_RIGHT GPIO_NUM_13
#define DELAYS_MS 1000

uint32_t led_state = 0;

void app_main(void)
{
    gpio_reset_pin(LED_LEFT);
    gpio_set_direction(LED_LEFT, GPIO_MODE_OUTPUT);

    while (1)
    {
        led_state = !led_state;
        gpio_set_level(LED_LEFT, led_state);
        vTaskDelay(DELAYS_MS / portTICK_PERIOD_MS);
    }
}

  • 效果演示

获取硬件信息

点击查看代码
#include <stdio.h>
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_log.h"

const char *hw = "硬件";
const char *sw = "软件";

void app_main(void)
{
    ESP_LOGE(sw, "IDF版本号: %s", esp_get_idf_version());

    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);

    ESP_LOGE(hw, "CPU核心数: %d", chip_info.cores);
    // ESP_LOGE(hw, "CPU 版本号: %s", chip_info.revision);

    // char *esp_type;

    // switch (chip_info.model)
    // {
    // case CHIP_ESP32:
    //     esp_type = "ESP32";
    //     break;
    // case CHIP_ESP32S2:
    //     esp_type = "ESP32-S2";
    //     break;
    // case CHIP_ESP32S3:
    //     esp_type = "ESP32-S3";
    //     break;
    // case CHIP_ESP32C3:
    //     esp_type = "ESP32-C3";
    //     break;
    // default:
    //     esp_type = "未知";
    //     break;
    // }

    // ESP_LOGE(hw, "芯片类型: %s", esp_type);
    // ESP_LOGE(hw, "特征: %s", chip_info.features);

    ESP_LOGE(hw, "WIFI: %s", chip_info.features & CHIP_FEATURE_WIFI_BGN ? "支持" : "不支持");
    ESP_LOGE(hw, "蓝牙BLE: %s", chip_info.features & CHIP_FEATURE_BLE ? "支持" : "不支持");
    ESP_LOGE(hw, "蓝牙2.0: %s", chip_info.features & CHIP_FEATURE_BT ? "支持" : "不支持");
    ESP_LOGE(hw, "IEEE 802.15.4: %s", chip_info.features & CHIP_FEATURE_IEEE802154 ? "支持" : "不支持");
    ESP_LOGE(hw, "内置PSRAM: %s", chip_info.features & CHIP_FEATURE_EMB_PSRAM ? "支持" : "不支持");
    ESP_LOGE(hw, "内置FLASH: %s", chip_info.features & CHIP_FEATURE_EMB_FLASH ? "支持" : "不支持");

    ESP_LOGE(hw, "Flash 容量: %d MBytes", spi_flash_get_chip_size() / (1024 * 1024));
    ESP_LOGE(hw, "Flash 容量: %d MBits", spi_flash_get_chip_size() * 8 / (1024 * 1024));
}

  • 效果演示

WIFI基础

WIFI扫描

根据介绍乐鑫官方手册wifi部分,
介绍一种ESP32片上无线模块扫频应用,让ESP32 能够获取周围WiFi热点信息,实现无线扫频功能。详细步骤如下:

  1. 使用NVS存储初始化。
  2. 使用Wi-Fi和LwIP初始化,绑定station或AP。
  3. 配置Wi-Fi模式为station模式,然后启动Wi-Fi。
  4. 进行Wi-Fi扫描,获取周围的热点详情,包括SSID、频道、信号强度、MAC地址等详细信息。
点击查看代码
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_wifi.h"

// https://docs.espressif.com/projects/esp-idf/zh_CN/v4.4.3/esp32/api-guides/wifi.html

void app_main(void)
{
    ESP_LOGI("WIFI", "0.初始化NVS存储");
    nvs_flash_init();

    ESP_LOGI("WIFI", "1.Wi-Fi/LwIP 初始化阶段");
    esp_netif_init();
    esp_event_loop_create_default();
    // 创建有 TCP/IP 堆栈的默认网络接口实例绑定 station 或 AP。
    esp_netif_create_default_wifi_sta();
    wifi_init_config_t wifi_config = WIFI_INIT_CONFIG_DEFAULT();
    esp_wifi_init(&wifi_config);

    ESP_LOGI("WIFI", "2.Wi-Fi 配置阶段");
    esp_wifi_set_mode(WIFI_MODE_STA);

    ESP_LOGI("WIFI", "3.Wi-Fi 启动阶段");
    esp_wifi_start();

    ESP_LOGI("WIFI", "4.WIFI扫描");
    wifi_country_t config_country = {.cc = "CN", .schan = 1, .nchan = 13, .policy = WIFI_COUNTRY_POLICY_AUTO};
    esp_wifi_set_country(&config_country);
    wifi_scan_config_t config_scan = {.show_hidden = true};
    esp_wifi_scan_start(&config_scan, true);

    // 方式1:获取扫描到的AP数量
    uint16_t ap_num = 0;
    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_num));
    ESP_LOGI("WIFI", "扫描到的AP数量: %d", ap_num);

    // 方式2:获取扫描到的AP数量
    uint16_t max_aps = 20;
    wifi_ap_record_t ap_records[max_aps];
    // 初始化结构体数组
    memset(ap_records, 0, sizeof(ap_records));

    uint16_t ap_count = max_aps;
    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_count, ap_records));
    ESP_LOGI("WIFI", "获取到的AP数量: %d", ap_count);

    printf("%30s %s %s %s \n", "SSID", "频道", "强度", "MAC地址");

    for (size_t i = 0; i < ap_count; i++)
    {
        printf("%30s %3d %3d %02x:%02x:%02x:%02x:%02x:%02x \n",
               ap_records[i].ssid,
               ap_records[i].primary,
               ap_records[i].rssi,
               ap_records[i].bssid[0],
               ap_records[i].bssid[1],
               ap_records[i].bssid[2],
               ap_records[i].bssid[3],
               ap_records[i].bssid[4],
               ap_records[i].bssid[5]);
    }
}

  • 输出效果演示

FreeRTOS

在上一个示例的基础上,我们需要先初始化ESP32的NVS存储,使用nvs_flash_init()和nvs_flash_erase()等API进行初始化,这时可以得到一个NVS空间用来存储需要的配置信息,例如Wi-Fi的网络设置等。此外,还需要把esp_wifi_init()放在初始化ESP32的网络适配器esp_netif_init()和默认事件循环esp_event_loop_create_default()之后,并且用esp_netif_create_default_wifi_sta()来创建一个默认的Wi-Fi供应器,这样才能确保Wi-Fi网络设置能够正确的被传递,从而完成Wi-Fi的初始化过程。

然后就可以在ESP32上使用FreeRTOS进行任务分配了。使用xTaskCreate()函数创建应用任务“App Task”。在App Task中,我们可以使用esp_event_handler_register()注册Wi-Fi事件到事件句柄,来监听Wi-Fi的一些事件,比如连接成功事件,从而避免应用程序一直等待Wi-Fi连接完成。然后,使用vTaskDelay()函数控制任务延迟,控制函数的用时,从而实现应用程序的流程控制。

总的来说,FreeRTOS在ESP32上的使用可以极大的提高开发效率和程序稳定性,让开发者可以实现复杂的应用程序功能,快速稳定的嵌入ESP32开发平台中。

点击查看代码
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"

void wifi_scan_task(void *pt)
{
  ESP_LOGI("WIFI", "4. Wi-Fi 扫描");
  wifi_country_t wifi_country_config = {
      .cc = "CN",
      .schan = 1,
      .nchan = 13,
  };
  ESP_ERROR_CHECK(esp_wifi_set_country(&wifi_country_config));
  ESP_ERROR_CHECK(esp_wifi_scan_start(NULL, false));

  vTaskDelete(NULL);
}

void wifi_scan_show(void *pt)
{
  uint16_t ap_num = 0;
  ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_num));
  ESP_LOGI("WIFI", "AP Count : %d", ap_num);

  uint16_t max_aps = 20;
  wifi_ap_record_t ap_records[max_aps];
  memset(ap_records, 0, sizeof(ap_records));

  uint16_t aps_count = max_aps;
  ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&aps_count, ap_records));

  ESP_LOGI("WIFI", "AP Count: %d", aps_count);

  printf("%30s %s %s %s\n", "SSID", "频道", "强度", "MAC地址");

  for (int i = 0; i < aps_count; i++)
  {
    printf("%30s  %3d  %3d  %02X-%02X-%02X-%02X-%02X-%02X\n", ap_records[i].ssid, ap_records[i].primary, ap_records[i].rssi, ap_records[i].bssid[0], ap_records[i].bssid[1], ap_records[i].bssid[2], ap_records[i].bssid[3], ap_records[i].bssid[4], ap_records[i].bssid[5]);
  }

  vTaskDelete(NULL);
}

void run_on_event(void *handler_arg, esp_event_base_t base, int32_t id, void *event_data)
{
  ESP_LOGE("EVENT_HANDLE", "BASE:%s, ID:%d", base, id);

  switch (id)
  {
  case WIFI_EVENT_STA_START:
    ESP_LOGE("EVENT_HANDLE", "WIFI_EVENT_STA_START");
    xTaskCreate(wifi_scan_task, "wifi scan task", 1024 * 12, NULL, 1, NULL);
    break;
  case WIFI_EVENT_SCAN_DONE:
    ESP_LOGE("EVENT_HANDLE", "WIFI_EVENT_SCAN_DONE");
    xTaskCreate(wifi_scan_show, "wifi scan show", 1024 * 12, NULL, 1, NULL);
    break;
  default:
    break;
  }
}

void app_task(void *pt)
{
  ESP_LOGI("APP_TASK", "APP Task 创建完成");
  esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, run_on_event, NULL);
  while (1)
  {
    // ESP_LOGI("APP_TASK", "APP Task 无聊的运行中");
    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }
}

void app_main(void)
{
  ESP_LOGI("WIFI", "0. 初始化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("WIFI", "1. Wi-Fi 初始化阶段");
  ESP_ERROR_CHECK(esp_netif_init());
  ESP_ERROR_CHECK(esp_event_loop_create_default());
  esp_netif_create_default_wifi_sta();

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

  xTaskCreate(app_task, "App Task", 1024 * 12, NULL, 1, NULL);

  ESP_LOGI("WIFI", "2. Wi-Fi 初始化阶段");
  ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));

  ESP_LOGI("WIFI", "3. Wi-Fi 启动阶段");
  ESP_ERROR_CHECK(esp_wifi_start());

  while (1)
  {
    // ESP_LOGI("MAIN_TASK", "MAIN Task 无聊的运行中");
    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }
}


Event Group

Event Group 程序实例

点击查看代码
/*
  通过Event Group 来实现,任务之间的Event通知。
  Task2 执行完自己的秘密任务后,通知Task1,然后Task1执行自己的任务
  Task3 是用来验证,在通过xEventGroupWaitBits的时候CPU进入阻塞状态是不消耗CPU的。
*/
#include <stdio.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"

static EventGroupHandle_t s_wifi_event_group;

#define SECRET_TASK BIT23

void task1(void *pt)
{
  ESP_LOGE("TASK1", "TASK1 创建完毕");
  while (1)
  {
    ESP_LOGE("TASK1", "等待task2的把重要的事情做完");
    xEventGroupWaitBits(s_wifi_event_group,
                        SECRET_TASK,
                        pdFALSE,
                        pdFALSE,
                        portMAX_DELAY);
    ESP_LOGE("TASK1", "终于轮到我了。。。。");
    vTaskDelete(NULL);
  }
}

void task2(void *pt)
{
  ESP_LOGI("TASK2", "TASK2 创建完毕");
  while (1)
  {
    ESP_LOGI("TASK2", "TASK2 假装在做很重要的事情,大约需要5秒");

    vTaskDelay(5000 / portTICK_PERIOD_MS);
    xEventGroupSetBits(s_wifi_event_group, SECRET_TASK);
    vTaskDelete(NULL);
  }
}

void task3(void *pt)
{
  ESP_LOGI("TASK3", "TASK3 创建完毕");
  while (1)
  {
    ESP_LOGI("TASK3", "其他任务阻塞,CPU归我了~");

    vTaskDelay(500 / portTICK_PERIOD_MS);
  }
}

void app_main(void)
{

  ESP_LOGW("MAIN", "Event Group Bits  : %d bits", configUSE_16_BIT_TICKS ? 8 : 24);
  s_wifi_event_group = xEventGroupCreate();

  xTaskCreate(task1, "task1", 1024 * 12, NULL, 1, NULL);
  xTaskCreate(task2, "task2", 1024 * 12, NULL, 1, NULL);
  //xTaskCreate(task3, "task3", 1024 * 12, NULL, 1, NULL);
}

引入FreeRTOS的Event Group 事件标志组来讲上节课的我们创建的3个任务合并起来。
可以简单的把Event Group想成一个全局的变量, FreeRTOS 任务使用这个全局变量来互相沟通的。

点击查看代码
/*
  这节课中,我们在ESP32 event loop handler中使用了freeRtos Event Group 来取代上节课的xTaskCreate
  注意: Event Loop 是 乐鑫的东西, Event Group是FreeRTOS的东西,他们是完全不同的两个东西
*/

#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "freertos/event_groups.h"


static EventGroupHandle_t s_wifi_event_group;

#define STA_START BIT0
#define SCAN_DONE BIT1

void run_on_event(void *handler_arg, esp_event_base_t base, int32_t id, void *event_data)
{
  ESP_LOGE("EVENT_HANDLE", "BASE:%s, ID:%d", base, id);

  switch (id)
  {
  case WIFI_EVENT_STA_START:
    ESP_LOGE("EVENT_HANDLE", "WIFI_EVENT_STA_START");
    xEventGroupSetBits(s_wifi_event_group, STA_START);
    break;
  case WIFI_EVENT_SCAN_DONE:
    ESP_LOGE("EVENT_HANDLE", "WIFI_EVENT_SCAN_DONE");
    xEventGroupSetBits(s_wifi_event_group, SCAN_DONE);
    break;
  default:
    break;
  }
}

void app_task(void *pt)
{
  ESP_LOGI("APP_TASK", "APP Task 创建完成");
  esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, run_on_event, NULL);
  while (1)
  {
    xEventGroupWaitBits(s_wifi_event_group,
                        STA_START,
                        pdFALSE,
                        pdFALSE,
                        portMAX_DELAY);
    ESP_LOGE("APP_TASK", "接收到了STA START事件, 可以运行AP Scan了");
    wifi_country_t wifi_country_config = {
        .cc = "CN",
        .schan = 1,
        .nchan = 13,
    };
    ESP_ERROR_CHECK(esp_wifi_set_country(&wifi_country_config));
    ESP_ERROR_CHECK(esp_wifi_scan_start(NULL, false));

    xEventGroupWaitBits(s_wifi_event_group,
                        SCAN_DONE,
                        pdFALSE,
                        pdFALSE,
                        portMAX_DELAY);
    ESP_LOGE("APP_TASK", "接收到了SCAN DONE事件, 可以打印出AP扫描结果了");
    uint16_t ap_num = 0;
    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_num));
    ESP_LOGI("WIFI", "AP Count : %d", ap_num);

    uint16_t max_aps = 20;
    wifi_ap_record_t ap_records[max_aps];
    memset(ap_records, 0, sizeof(ap_records));

    uint16_t aps_count = max_aps;
    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&aps_count, ap_records));

    ESP_LOGI("WIFI", "AP Count: %d", aps_count);

    printf("%30s %s %s %s\n", "SSID", "频道", "强度", "MAC地址");

    for (int i = 0; i < aps_count; i++)
    {
      printf("%30s  %3d  %3d  %02X-%02X-%02X-%02X-%02X-%02X\n", ap_records[i].ssid, ap_records[i].primary, ap_records[i].rssi, ap_records[i].bssid[0], ap_records[i].bssid[1], ap_records[i].bssid[2], ap_records[i].bssid[3], ap_records[i].bssid[4], ap_records[i].bssid[5]);
    }
    vTaskDelete(NULL);
  }
}

void app_main(void)
{

  ESP_LOGI("WIFI", "0. 初始化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("WIFI", "1. Wi-Fi 初始化阶段");
  ESP_ERROR_CHECK(esp_netif_init());
  ESP_ERROR_CHECK(esp_event_loop_create_default());
  esp_netif_create_default_wifi_sta();

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

  ESP_LOGI("WIFI", "创建App Task 和 FreeRTOS Event Group");
  s_wifi_event_group = xEventGroupCreate();
  xTaskCreate(app_task, "App Task", 1024 * 12, NULL, 1, NULL);

  ESP_LOGI("WIFI", "2. Wi-Fi 初始化阶段");
  ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));

  ESP_LOGI("WIFI", "3. Wi-Fi 启动阶段");
  ESP_ERROR_CHECK(esp_wifi_start());

  while (1)
  {
    // ESP_LOGI("MAIN_TASK", "MAIN Task 无聊的运行中");
    vTaskDelay(1000 / portTICK_PERIOD_MS);
  }
}

Event Loop

为了区分 FreeRTOS的 Event Group 和 乐鑫的 Event Loop 这两个概念,
通过具体形象的夜市吃烧烤喝啤酒,来给大家形象的讲解Event Loop诞生的初衷和代码实现

点击查看代码
#include <stdio.h>
#include "esp_event.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include <string.h>

esp_event_loop_handle_t night_market_loop_handler;

esp_event_base_t XINJIANG_BASE = "新疆餐厅";

typedef enum {
    BBQ_EVENT_LAMB_SKEWERS_SPICY = 0,
    BBQ_EVENT_LAMB_SKEWERS_NOT_SPICY,
    BBQ_EVENT_HOT_PACKET,
    BBQ_EVENT_BAKED_BAOZI,
    BBQ_EVENT_THIN_SKIN_BAOZI,
    BBQ_EVENT_FROZEN_BEER
} bbq_event_t;

// typedef enum {
//     羊肉串_辣 = 0,
//     羊肉串_不辣,
//     热囊,
//     烤包子,
//     薄皮包子,
//     冰冻啤酒
// } bbq_event_t;

void consumer_event_handle(void *handler_arg, esp_event_base_t base, int32_t id, void *event_data)
{   char * msg_from_booth = (char*) event_data;
    char * msg_from_consumer = (char*) handler_arg;
    ESP_LOGE("EVENT_HANDLE", "顾客:%s 摊位:%s, 事件:%li, 老板说:%s", msg_from_consumer, base, id,msg_from_booth);

}

void consumer_add_task(void *pt)
{
    ESP_LOGE("CONSUMER_TASK", "来了一个吃货");
    char * handle_arg = "我是个大胃王,爱吃辣";
    esp_event_handler_register_with(night_market_loop_handler, XINJIANG_BASE, BBQ_EVENT_LAMB_SKEWERS_SPICY, consumer_event_handle, handle_arg);
    esp_event_handler_register_with(night_market_loop_handler, XINJIANG_BASE, BBQ_EVENT_FROZEN_BEER, consumer_event_handle, handle_arg);
    while(1) {
        vTaskDelay(1000/portTICK_PERIOD_MS);
    }
}

void booth_xinjiang_task(void *pt)
{
    ESP_LOGE("BOOTH_TASK", "新疆饭店开张了");
    while(1) {
        vTaskDelay(5000/portTICK_PERIOD_MS);
        char * event_data = "这次肥肉比较多,不好意思哦";
        ESP_LOGE("新疆饭店", "BBQ_EVENT_BAKED_BAOZI好了");
        esp_event_post_to(night_market_loop_handler, XINJIANG_BASE, BBQ_EVENT_BAKED_BAOZI, event_data,strlen(event_data)+1, portMAX_DELAY);

        vTaskDelay(5000/portTICK_PERIOD_MS);
        ESP_LOGE("新疆饭店", "BBQ_EVENT_LAMB_SKEWERS_SPICY");
        event_data = "变态辣, 吃进医院不负责哦";
        esp_event_post_to(night_market_loop_handler, XINJIANG_BASE, BBQ_EVENT_LAMB_SKEWERS_SPICY, event_data,strlen(event_data)+1, portMAX_DELAY);

        vTaskDelay(5000/portTICK_PERIOD_MS);
        ESP_LOGE("新疆饭店", "BBQ_EVENT_LAMB_SKEWERS_NOT_SPICY");
        event_data = "一点辣味都没有,这有啥吃的呀";
        esp_event_post_to(night_market_loop_handler, XINJIANG_BASE, BBQ_EVENT_LAMB_SKEWERS_NOT_SPICY, event_data,strlen(event_data)+1, portMAX_DELAY);

        vTaskDelay(5000/portTICK_PERIOD_MS);
        ESP_LOGE("新疆饭店", "BBQ_EVENT_FROZEN_BEER");
        event_data = "超级冰, 都是冰渣子, 牙齿给你冻掉";
        esp_event_post_to(night_market_loop_handler, XINJIANG_BASE, BBQ_EVENT_FROZEN_BEER, event_data,strlen(event_data)+1, portMAX_DELAY);

        ESP_LOGE("新疆饭店", "新年提前收工了, 明年见");
        vTaskDelete(NULL);
    }
}

void app_main(void)
{   
    /*
    课程开始前,我们先回顾一下
    char_pointer - 指针指向的地址
    %char_pointer - 指针自己的地址
    sizeof(char_pointer) - 指针本身的大小
    strlen(char_pointer) - 指针指向的char数组的大小,不包括最后的NULL
    strlen(char_pointer)+1 - 指针指向的char数组的大小,包括最后的NULL
    */
    char * char_pointer = "1234567890";
    ESP_LOGI("main","char_pointer 内容: %s",char_pointer);
    ESP_LOGI("main","char_pointer %p",char_pointer);
    ESP_LOGI("main","&char_pointer %p",&char_pointer);
    ESP_LOGI("main","sizeof(char_pointer) %d",sizeof(char_pointer));
    ESP_LOGI("main","strlen(char_pointer) %d",strlen(char_pointer));

    
    ESP_LOGE("MAIN","创建 Event Loop");
    esp_event_loop_args_t night_market_loop_args = {
        .queue_size = 5,
        .task_name = "night_market_task",
        .task_priority = uxTaskPriorityGet(NULL),
        .task_stack_size = 1024*4,
        .task_core_id = tskNO_AFFINITY,
    };
    
    ESP_ERROR_CHECK(esp_event_loop_create(&night_market_loop_args, &night_market_loop_handler));

    xTaskCreate(consumer_add_task, "consumer a", 1024 * 12, NULL, 1, NULL);
    xTaskCreate(booth_xinjiang_task, "xinjiang bbq", 1024 * 12, NULL, 1, NULL);

    
    vTaskDelete(NULL);
}
posted @ 2022-11-21 16:11  Dapenson  阅读(587)  评论(0编辑  收藏  举报