注:使用VSCode中的ESP-IDF插件进行开发,笔记基于B站UP主艾谷科技的视频教程

ESP32S3+ESPIDF入门教程 程序纯手打 手把手教学 中文字幕 持续更新中_哔哩哔哩_bilibili


目录

一、 项目要求

二、项目工程

        1.复制上一小节的4_Key文件并重命名为5_Multitask

        2.修改文件

                1.修改key.c文件

                2.修改led.c文件

                3.修改main.c文件

                4.编译

                5.连接电路

                6.下载并运行


一、 项目要求

        直接运行会导致卡顿,需要引入FreeRTOS多任务系统

二、项目工程

        1.复制上一小节的4_Key文件并重命名为5_Multitask

        2.修改文件

                1.修改key.c文件

#include "key.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"

void key_init(void)
{
    gpio_config_t gpio_cfg = {
        .intr_type = GPIO_INTR_DISABLE,
        .mode = GPIO_MODE_INPUT,
        .pin_bit_mask = (1ull << GPIO_NUM_9),    //仅初始化GPIO9,IO9外接一个按键
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .pull_up_en = GPIO_PULLUP_ENABLE,
    };
   gpio_config (&gpio_cfg);
}

uint8_t key_scan(void)
{
    uint8_t key_num =0;
    if(gpio_get_level(GPIO_NUM_9) == 0)
    {
        vTaskDelay(20);
        while (gpio_get_level(GPIO_NUM_9) == 0);
        vTaskDelay(20);
        key_num = 1;
    }
    return key_num ;
}

                2.修改led.c文件

#include "led.h"
#include "driver/gpio.h"

void led_init(void)
{
    esp_err_t err;
    gpio_config_t gpio_cfg = {
        .intr_type = GPIO_INTR_DISABLE,
        .mode = GPIO_MODE_INPUT_OUTPUT,
         //初始化两个GPIO引脚,分别在IO38,GO39连接LED
        .pin_bit_mask = (1ull << GPIO_NUM_38)|(1ull << GPIO_NUM_39),
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .pull_up_en = GPIO_PULLUP_ENABLE,
    };
    err = gpio_config (&gpio_cfg);
    if(err != ESP_OK)
    {
        printf("gpio init error!\r\n");
    }
    gpio_set_level(GPIO_NUM_38, 1);
    gpio_set_level(GPIO_NUM_39, 1);

}

void gpio_toggle(gpio_num_t gpio_num)
{
    if(gpio_get_level(gpio_num) == 0)
    {
        gpio_set_level(gpio_num, 1);
    }
    else
    {
        gpio_set_level(gpio_num, 0);
    }
}

                3.修改main.c文件

                分别建立两个任务函数,任务函数的编写参数是void *param,任务函数必须是无限循环,在函数xTaskCreatePinnedToCore的原始函数中的第一个入口参数,跳转后可以看到任务函数的原型。使用任务函数的时候必须在函数内部加入延时,才能进行后续的任务调度。

void led_task(void *param)
{
    while (1)
    {
        gpio_toggle(GPIO_NUM_38);        //LED1每隔100ms闪烁一次
        vTaskDelay(100);
    }
}

void key_task(void *param)
{
    uint8_t key_num = 0;
    while(1)
    {
        key_num = key_scan();
        if(key_num == 1)
        {
            gpio_toggle(GPIO_NUM_39);    //检测按键按下后改变LED2的状态
        }
        vTaskDelay(5);
    }
}

调用xTaskCreatePinnedToCore函数使得两个任务能够运行,调用该函数时需要包含头文件

“freertos/FreeRTOS.h”、“freertos/task.h”

void app_main(void)
{
    led_init();
    key_init();

    xTaskCreatePinnedToCore( led_task,"led_task",1024,NULL,1,NULL,0 );
    xTaskCreatePinnedToCore( key_task,"key_task",1024,NULL,1,NULL,0 );
}

xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode,

                                        const char * const pcName,

                                        const configSTACK_DEPTH_TYPE usStackDepth,

                                        void * const pvParameters,

                                        UBaseType_t uxPriority,

                                        TaskHandle_t * const pvCreatedTask,

                                        const BaseType_t xCoreID );

        pxTaskCode:任务函数的名称;

        const pcName:任务名称用于调试;

        usStackDepth:任务占用的堆栈大小,此处分配1024字节;

        pvParameters:给任务函数传入的值,此处不需要传入任何参数,输入NULL;

        uxPriority:该任务函数的优先级,数字越大,任务优先级越高,任务越先执行;

        pvCreatedTask:任务句柄,可用于管理任务(如删除、挂起、恢复)。两个任务函数都没有创建,此处填写NULL;

        xCoreID:任务函数在哪一个内核中执行,ESP32有两个内核,可以填写0或1。

  • 0:固定到 Core 0(PRO_CPU,通常处理Wi-Fi/蓝牙)。

  • 1:固定到 Core 1(APP_CPU,通常处理用户任务)。

  • tskNO_AFFINITY(值为 -1):允许任务在任意核心运行(由调度器决定)。

                4.编译

                5.连接电路

                6.下载并运行

        运行结果:两个任务独立运行,互不干扰

Logo

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

更多推荐