LED闪烁 + PWM呼吸灯
LED灯闪烁实验
FreeRTOS操作系统
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"#define LED_Pin GPIO_NUM_2// 定义一个任务
void led_flashing_task()
{int gpio_pin = 0;while(1){vTaskDelay(pdMS_TO_TICKS(500));gpio_pin = gpio_pin ? 0 : 1;gpio_set_level(LED_Pin, gpio_pin);}
}
void app_main(void)
{// 初始化gpio管脚// 首先定义一个结构体// 然后往结构体里面添加成员// 然后这个结构体就成为了一个配置项// 将这个配置通过一个API设置到底层里面去gpio_config_t led_config = {.pin_bit_mask = (1 << LED_Pin),.mode = GPIO_MODE_OUTPUT,.pull_up_en = GPIO_PULLUP_DISABLE,.pull_down_en = GPIO_PULLDOWN_DISABLE,.intr_type = GPIO_INTR_DISABLE,};gpio_config(&led_config);xTaskCreatePinnedToCore(led_flashing_task, "led", 2048, NULL, 3, NULL, 1);}
esp32-wroom-32开发板自带的led灯是GPIO2号管脚。
PWM波形实验
deepseek给出的参考,可以实现呼吸灯效果
/*LED+PWM呼吸灯效果*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/ledc.h"#define LED_Pin GPIO_NUM_2 // 2号管脚
#define PWM_TIMER LEDC_TIMER_0 // 定时器0-
#define PWM_MODE LEDC_LOW_SPEED_MODE // 低速模式
#define PWM_CHANNEL LEDC_CHANNEL_0 // 8个通道 选择通道0// 定义PWM呼吸灯任务
void led_breathing_task()
{// pwm配置结构体ledc_timer_config_t timer_config = {.speed_mode = PWM_MODE,.duty_resolution = LEDC_TIMER_13_BIT, // 13位分辨率(0-8191).timer_num = PWM_TIMER,.freq_hz = 5000, // pwm频率设置为5000hz.clk_cfg = LEDC_AUTO_CLK};ledc_timer_config(&timer_config);// 通道配置ledc_channel_config_t channel_config = {.channel = PWM_CHANNEL,.duty = 0,.gpio_num = LED_Pin,.hpoint = 0,.speed_mode = PWM_MODE,.timer_sel = PWM_TIMER};ledc_channel_config(&channel_config);// 设置渐变功能ledc_fade_func_install(0); // 不使用中断int direction = 1; // 设置亮灭标志位uint16_t duty = 0;const uint32_t max_duty = 8191; // 13位最大占空比while(1){// 设置新的占空比并渐变ledc_set_fade_with_time(PWM_MODE,PWM_CHANNEL,duty, 200); // 200ms内完成渐变ledc_fade_start(PWM_MODE,PWM_CHANNEL,LEDC_FADE_NO_WAIT);// 更新占空比值duty += direction * (max_duty / 20);// 改变方向if (duty >= max_duty){duty = max_duty;direction = -1;}else if (duty <= 0){duty = 0;direction = 1;}// 等待渐变完成vTaskDelay(pdMS_TO_TICKS(200));}
}void app_main(void)
{// 创建呼吸灯任务xTaskCreatePinnedToCore(led_breathing_task, "breathing_led", 2048, NULL, 3, NULL, 1);
}
根据官网和课程编写的如下,效果可以实现
#if 1
// 这段代码实现了基于事件驱动的呼吸灯效果,充分利用了FreeRTOS的事件组和LEDC的渐变功能,避免了在任务中轮询或延时,提高了效率。
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/ledc.h"#define LED_Pin GPIO_NUM_2// 定义一个事件组句柄
static EventGroupHandle_t ledc_event_handel;
// 定义两个事件标志位
#define FULL_EV_BIT0 BIT0
#define EMPTY_EV_BIT BIT1// 函数指针 回调函数,提示渐变已经完成 添加了一个IRAM_ATTR宏
bool IRAM_ATTR ledc_cb_t0(const ledc_cb_param_t *param, void *user_arg)
{BaseType_t taskWoken;// 渐变 0- 满 满-0if (param->duty){xEventGroupSetBitsFromISR(ledc_event_handel, FULL_EV_BIT0, &taskWoken); }else{xEventGroupSetBitsFromISR(ledc_event_handel,EMPTY_EV_BIT, &taskWoken);}return taskWoken;}// 定义PWM呼吸灯任务
void led_breathing_task()
{// 设置新的占空比并渐变EventBits_t ev;while(1){ev = xEventGroupWaitBits(ledc_event_handel, FULL_EV_BIT0 | EMPTY_EV_BIT, pdTRUE, pdFALSE, pdMS_TO_TICKS(5000));if (ev & FULL_EV_BIT0){ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0, 2000); // 2000ms内完成渐变// LEDC_FADE_NO_WAIT不用等渐变完成,这个函数立刻返回,不用阻塞ledc_fade_start(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0,LEDC_FADE_NO_WAIT);}if (ev & EMPTY_EV_BIT){ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 8191, 2000); // 2000ms内完成渐变// LEDC_FADE_NO_WAIT不用等渐变完成,这个函数立刻返回,不用阻塞ledc_fade_start(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0,LEDC_FADE_NO_WAIT);}}
}void app_main(void)
{// GPIO结构体配置gpio_config_t led_config = {// 掩码.pin_bit_mask = (1 << LED_Pin),// GPIO的模式.mode = GPIO_MODE_OUTPUT,// 配置上拉使能.pull_up_en = GPIO_PULLUP_DISABLE,// 配置下拉使能.pull_down_en = GPIO_PULLDOWN_DISABLE,// 配置终端类型.intr_type = GPIO_INTR_DISABLE,};// 配置项传递给配置结构体,配置结构体通过地址映射设置到对应的寄存器gpio_config(&led_config);// pwm配置结构体ledc_timer_config_t timer_config = {.speed_mode = LEDC_LOW_SPEED_MODE,.duty_resolution = LEDC_TIMER_13_BIT, // 占空比的分辨率 13位分辨率(0-8191).timer_num = LEDC_TIMER_0, // 定时器0.freq_hz = 5000, // pwm频率设置为5000hz.clk_cfg = LEDC_AUTO_CLK};ledc_timer_config(&timer_config);// 通道配置ledc_channel_config_t channel_config = {.channel = LEDC_CHANNEL_0,.duty = 0, // 占空比.gpio_num = LED_Pin,.speed_mode = LEDC_LOW_SPEED_MODE,.timer_sel = LEDC_TIMER_0};ledc_channel_config(&channel_config);// 设置渐变功能ledc_fade_func_install(0); // 不使用中断ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 8191, 2000); // 2000ms内完成渐变// LEDC_FADE_NO_WAIT不用等渐变完成,这个函数立刻返回,不用阻塞ledc_fade_start(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0,LEDC_FADE_NO_WAIT);// 什么时候知道渐变完成呢? 设置一个渐变完成的回调函数ledc_cbs_t cbs = {.fade_cb = ledc_cb_t0};ledc_cb_register(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, &cbs, NULL);ledc_event_handel = xEventGroupCreate();xTaskCreatePinnedToCore(led_breathing_task, "led", 2048, NULL, 3, NULL, 1);}
#endif
上述代码需要熟悉FreeRTOS事件组和中断回调函数 相关知识