tag 标签: 呼吸灯

相关帖子
相关博文
  • 热度 3
    2025-6-4 09:07
    459 次阅读|
    2 个评论
    10. ESP32开发之LED闪烁和呼吸的实现
    硬件电路介绍 GPIO输出模式 GPIO配置过程 闪烁灯的源码 LED PWM的控制器(LEDC)概述 LEDC配置过程及现象 整体流程 硬件电路介绍 电路图如下: 只要有硬件基础的应该都知道上图中,当GPIO4的输出电平为高时,LED灯亮,反之则熄灭。如果每间隔一段时间进行一次电平的反转,则将使LED产生闪烁的效果。 GPIO模式 在进行GPIO控制之前,需要熟悉一下ESP32的GPIO几种模式: GPIO模式 模式宏定义 说明 输入模式 GPIO_MODE_INPUT 可以通过配置项pull_up_en或pull_down_en配置上拉或者下拉 推挽输出模式 GPIO_MODE_OUTPUT 高低电平输出 开漏输出模式 GPIO_MODE_OUTPUT_OD 通常用于I2C 中断 可通过intr_type配置项配置触发方式:上升沿/下降沿/双沿/电平触发等 禁用 GPIO_MODE_DISABLE 禁用GPIO,不作为输入也不作为输出 输入输出模式 GPIO_MODE_INPUT_OUTPUT 输入及开漏输出 GPIO_MODE_INPUT_OUTPUT_OD 注意: 使用中断时,将GPIO模式设置为输入模式 如果GPIO用于I2C的SDA,设置模式为 GPIO_MODE_INPUT_OUTPUT_OD ,且需要配置上拉,也可在芯片相关引脚增加上拉电路 GPIO配置过程 配置GPIO 使用结构体gpio_config_t对GPIO相关参数进行配置 注册GPIO 通过函数 gpio_config 函数将以上配置注册进系统 通过GPIO相关API函数对GPIO进行控制 比如此次实验是控制LED闪烁,那么则是使用 gpio_set_level 函数进行输出电平控制 闪烁灯的源码 /** * Copyright (C) 2024-2034 HalfMoon2. * All rights reserved. * * @file Filename without the absolute path * @brief Brief description * @author HalfMoon2 * @date 2025-05-20 * @version v0.1 * * @revision history: * 2025-05-20 - Initial version. */ # include stdio.h # include "freertos/FreeRTOS.h" # include "freertos/task.h" # include "driver/gpio.h" # include "esp_log.h" # define LED_GPIO GPIO_NUM_4 //根据实际的连接方式更改 void ledCtlTask ( void *pvParam) { while ( 1 ){ gpio_set_level (LED_GPIO, 1 ); // 设置为高电平(点亮 LED) vTaskDelay ( pdMS_TO_TICKS ( 500 )); // 延时 0.5 秒 gpio_set_level (LED_GPIO, 0 ); // 设置为低电平(熄灭 LED) vTaskDelay ( pdMS_TO_TICKS ( 500 )); // 延时 0.5 秒 } } void app_main ( void ) { // 配置 GPIO gpio_config_t io_conf = { .pin_bit_mask = ( 1ULL LED_GPIO), // 选择 GPIO .mode = GPIO_MODE_OUTPUT, // 设置为输出模式 .pull_up_en = GPIO_PULLUP_DISABLE, // 不启用上拉 .pull_down_en = GPIO_PULLDOWN_DISABLE, // 不启用下拉 .intr_type = GPIO_INTR_DISABLE // 不启用中断 }; gpio_config (io_conf); xTaskCreatePinnedToCore (ledCtlTask, "ledCtlTask" , 2048 , NULL , 3 , NULL , 1 ); } LED PWM的控制器(LEDC)概述 从以上案例可以看出,对于通用GPIO的控制要么是高电平,要么是低电平。所以只能控制LED的闪烁现象。而对于ESP32-S3却有专用控制LED的控制器,称之LED PWM。它有8路低速通道。专用于控制LED。当然也可以产生PWM控制电机等。ESP32有两组LED PWM控制器,一组为8路高速通道,另一组为8路低速通道。 LED PWM 控制器可在无需 CPU 干预的情况下自动改变占空比,实现亮度渐变,如果是RGB LED,还能实现颜色的渐变。 LEDC的配置过程及现象 1. 定时器的配置过程 创建定时器配置结构体 typedef struct { ledc_mode_t speed_mode; /* LEDC速度模式, high-speed mode (only exists on esp32) or low-speed mode */ ledc_timer_bit_t duty_resolution; /* LEDC占空比分辨率 */ ledc_timer_t timer_num; /* The timer source of channel (0 - LEDC_TIMER_MAX-1) */ uint32_t freq_hz; /* LEDC 的时钟频率 */ ledc_clk_cfg_t clk_cfg; /*配置LEDC的时钟源. */ bool deconfigure; /*是否取消此配置之前的配置,取消之前先要关闭定时器 */ } ledc_timer_config_t 使用相关函数将结构体完成配置 esp_err_t ledc_timer_config ( const ledc_timer_config_t *timer_conf) ; //参数为以上定义的结构体 /*返回值: * ESP_OK 成功 * ESP_ERR_INVALID_ARG 参数错误 * ESP_FAIL 无法根据给定频率和当前占空比分辨率找到合适的预分频器编号 *ESP_ERR_INVALID_STATE 定时器未配置或未暂停 */ 2. 配置通道以及指定GPIO 创建配置通道结构体 typedef struct { int gpio_num; /* LEDC的输出GPIO*/ ledc_mode_t speed_mode; /* LEDC 速度模式,ESP32S3只能配置为低速 */ ledc_channel_t channel; /*LED PWM的控制器(LEDC) LEDC的通道 */ ledc_intr_type_t intr_type; /*是否开启渐变中断 */ ledc_timer_t timer_sel; /*选择定时器l (0 - LEDC_TIMER_MAX-1) */ uint32_t duty; /*! LEDC 通道占空比*/ int hpoint; /*! LEDC channel hpoint value, the range is */ struct { unsigned int output_invert: 1 ; /*! Enable (1) or disable (0) gpio output invert */ } flags; /*! LEDC 标志 */ } ledc_channel_config_t ; 使用函数完成配置 esp_err_t ledc_channel_config ( const ledc_channel_config_t *ledc_conf) ; 3. 配置占空比改变PWM信号 使能硬件PWM //参数intr_alloc_flags为分配的中断优先级 esp_err_t ledc_fade_func_install ( int intr_alloc_flags) 配置渐变参数 /* 参数: speed_mode:LEDC的速度模式,只有ESP32有高速模式 channel:通道,0-7 target_duty:占空比,取值范围 max_fade_time_ms:最大的渐变时间 */ esp_err_t ledc_set_fade_with_time ( ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, int max_fade_time_ms) 开启渐变 /* 参数: speed_mode:LEDC的速度模式 channel:通道,0-7 fade_mode:是否阻塞直到渐变完成,如果设置成LEDC_FADE_WAIT_DONE模式,则不渐变到预定值则不返回 */ esp_err_t ledc_fade_start ( ledc_mode_t speed_mode, ledc_channel_t channel, ledc_fade_mode_t fade_mode) 4. 第一阶段实例:实现LED缓慢亮灯 /** * Copyright (C) 2024-2034 HalfMoon2. * All rights reserved. * * @file Filename without the absolute path * @brief Brief description * @author HalfMoon2 * @date 2025-05-27 * @version v0.1 * * @revision history: * 2025-05-27 - Initial version. */ # include stdio.h # include "freertos/FreeRTOS.h" # include "freertos/task.h" # include "driver/gpio.h" # include "esp_log.h" # include driver/ledc.h # define LEDC_MODE LEDC_LOW_SPEED_MODE # define LEDC_DUTY_RES LEDC_TIMER_13_BIT # define LEDC_TIMER_NUM LEDC_TIMER_0 # define LEDC_FREQ 5000 # define LEDC_CHANNEL LEDC_CHANNEL_0 # define LEDC_GPIO GPIO_NUM_4 # define LEDC_DUTY 4095 //2^13-1 void ledc_init ( void ) { ledc_timer_config_t timer_config={ .speed_mode= LEDC_MODE, .duty_resolution= LEDC_DUTY_RES, .timer_num= LEDC_TIMER_NUM, .clk_cfg=LEDC_AUTO_CLK, .freq_hz=LEDC_FREQ }; ledc_timer_config (timer_config); ledc_channel_config_t ledc_channel={ .speed_mode = LEDC_MODE, .channel = LEDC_CHANNEL, .gpio_num = LEDC_GPIO, .intr_type = LEDC_INTR_DISABLE, .duty = 0 , .hpoint = 0 }; ledc_channel_config (ledc_channel); } void app_main ( void ) { ledc_init (); ledc_fade_func_install ( 0 ); ledc_set_fade_with_time (LEDC_MODE,LEDC_CHANNEL, 4095 , 10000 ); ledc_fade_start (LEDC_MODE,LEDC_CHANNEL,LEDC_FADE_NO_WAIT); } 波形说明:可以明显的看到PWM的占空比的变化,LED也缓慢的亮起。 那么接下来就是实现从亮起再缓慢的熄灭,以此循环则实现了LED呼吸的效果。 5. 渐变回调函数 LEDC控制器在使能渐变后,每个通道都可以有一个回调函数,通过ledc_cb_register()进行注册 esp_err_t ledc_cb_register ( ledc_mode_t speed_mode, ledc_channel_t channel, ledc_cbs_t *cbs, void *user_arg) /*参数: speed_mode:速度模式,只有ESP32有高速模式 channel: LEDC通道,低速模式有8个通道 cbs:回调函数原型定义在 ledc_cbs_t 结构体中 user_arg:用户注册时的数据,用于给回调函数传参 */ 6. 通过事件组的方式将此时LED的状态发送出去,即设置事件值 在中断中避免处理复杂的内容,所以在渐变回调函数中只使用事件组方式发送相关事件。不了解这块的知识可以参考我之前的文章 《ESP32开发之freeRTOS的事件组》 bool IRAM_ATTR ledc_fade_cb ( const ledc_cb_param_t *param, void *user_arg) { BaseType_t pxHigherPriorityTaskWoken; //如果当前LEDC占空比最大,说明此时LED为开灯状态,反之为关灯状态 if (param-duty){ xEventGroupSetBitsFromISR (s_ledc_ev,LED_ON_EV,pxHigherPriorityTaskWoken); } else { xEventGroupSetBitsFromISR (s_ledc_ev,LED_OFF_EV,pxHigherPriorityTaskWoken); } return pxHigherPriorityTaskWoken; } 7. 创建一个任务来接收事件并做渐变过程的改变 void ledc_fade_task ( void * param) { EventBits_t ev; while ( 1 ){ ev= xEventGroupWaitBits (s_ledc_ev,LED_OFF_EV|LED_ON_EV,pdTRUE,pdFALSE,portMAX_DELAY); if (ev){ if (evLED_OFF_EV){ ledc_set_fade_with_time (LEDC_MODE,LEDC_CHANNEL,LEDC_DUTY, 1000 ); ledc_fade_start (LEDC_MODE,LEDC_CHANNEL,LEDC_FADE_NO_WAIT); } if (evLED_ON_EV){ ledc_set_fade_with_time (LEDC_MODE,LEDC_CHANNEL, 0 , 1000 ); ledc_fade_start (LEDC_MODE,LEDC_CHANNEL,LEDC_FADE_NO_WAIT); } } //处理完成需要再次注册回调函数,产生循环 ledc_cbs_t cbs={.fade_cb=ledc_fade_cb}; ledc_cb_register (LEDC_MODE,LEDC_CHANNEL,cbs, NULL ); } } 8. 第二阶段实例:完整实现渐变的循环 /** * Copyright (C) 2024-2034 HalfMoon2. * All rights reserved. * * @file Filename without the absolute path * @brief Brief description * @author HalfMoon2 * @date 2025-05-27 * @version v0.1 * * @revision history: * 2025-05-27 - Initial version. */ # include stdio.h # include "freertos/FreeRTOS.h" # include "freertos/task.h" # include "driver/gpio.h" # include "esp_log.h" # include driver/ledc.h # define LEDC_MODE LEDC_LOW_SPEED_MODE # define LEDC_DUTY_RES LEDC_TIMER_13_BIT # define LEDC_TIMER_NUM LEDC_TIMER_0 # define LEDC_FREQ 5000 # define LEDC_CHANNEL LEDC_CHANNEL_0 # define LEDC_GPIO GPIO_NUM_4 # define LEDC_DUTY 4095 //2^13-1 //通知渐变完成 static EventGroupHandle_t s_ledc_ev = NULL ; //此时为关灯状态 # define LED_OFF_EV (10) //事件组bit0设置为关灯事件 //此时为开灯状态 # define LED_ON_EV (11) //事件组bit1设置为开灯事件 /** * @brief 渐变结束回调函数 * @param *param:LEDC callback parameter * @param *user_arg:User registered data * @return 返回是否唤醒高优先级任务 * @note 此函数为中断服务函数,所以不应处理过多的操作,那么在此函数中通过发送事件的方式,由渐变任务函数处理事件 */ bool IRAM_ATTR ledc_fade_cb ( const ledc_cb_param_t *param, void *user_arg) { BaseType_t pxHigherPriorityTaskWoken; //如果当前LEDC占空比最大,说明此时LED为开灯状态,反之为关灯状态 if (param-duty){ xEventGroupSetBitsFromISR (s_ledc_ev,LED_ON_EV,pxHigherPriorityTaskWoken); } else { xEventGroupSetBitsFromISR (s_ledc_ev,LED_OFF_EV,pxHigherPriorityTaskWoken); } return pxHigherPriorityTaskWoken; } /** * @brief led渐变任务 * @param 任务参数 * @note 接收事件并做LED操作 */ void ledc_fade_task ( void * param) { EventBits_t ev; while ( 1 ){ ev= xEventGroupWaitBits (s_ledc_ev,LED_OFF_EV|LED_ON_EV,pdTRUE,pdFALSE,portMAX_DELAY); if (ev){ if (evLED_OFF_EV){ ledc_set_fade_with_time (LEDC_MODE,LEDC_CHANNEL,LEDC_DUTY, 1000 ); ledc_fade_start (LEDC_MODE,LEDC_CHANNEL,LEDC_FADE_NO_WAIT); } if (evLED_ON_EV){ ledc_set_fade_with_time (LEDC_MODE,LEDC_CHANNEL, 0 , 1000 ); ledc_fade_start (LEDC_MODE,LEDC_CHANNEL,LEDC_FADE_NO_WAIT); } } //处理完成需要再次注册回调函数,产生循环 ledc_cbs_t cbs={.fade_cb=ledc_fade_cb}; ledc_cb_register (LEDC_MODE,LEDC_CHANNEL,cbs, NULL ); } } void ledc_init ( void ) { ledc_timer_config_t timer_config={ .speed_mode= LEDC_MODE, .duty_resolution= LEDC_DUTY_RES, .timer_num= LEDC_TIMER_NUM, .clk_cfg=LEDC_AUTO_CLK, .freq_hz=LEDC_FREQ }; ledc_timer_config (timer_config); ledc_channel_config_t ledc_channel={ .speed_mode = LEDC_MODE, .channel = LEDC_CHANNEL, .gpio_num = LEDC_GPIO, .intr_type = LEDC_INTR_DISABLE, .duty = 0 , .hpoint = 0 }; ledc_channel_config (ledc_channel); //创建事件组,用于接收和发送渐变事件 s_ledc_ev = xEventGroupCreate (); //开启硬件PWM ledc_fade_func_install ( 0 ); //设置渐变参数 ledc_set_fade_with_time (LEDC_MODE,LEDC_CHANNEL,LEDC_DUTY, 1000 ); //启动渐变 ledc_fade_start (LEDC_MODE,LEDC_CHANNEL,LEDC_FADE_NO_WAIT); //注册渐变回调函数 ledc_cbs_t cbs={.fade_cb=ledc_fade_cb,}; ledc_cb_register (LEDC_MODE,LEDC_CHANNEL,cbs, NULL ); xTaskCreatePinnedToCore (ledc_fade_task, "ledc_fade_task" , 2048 , NULL , 3 , NULL , 1 ); } void app_main ( void ) { ledc_init (); } 整体流程
  • 热度 6
    2022-3-17 10:58
    4340 次阅读|
    2 个评论
    用ESP32在Arduino IDE环境下控制多路LED调光
    本项目将在Arduino IDE环境下,利用ESP32产生的PWM信号控制多个LED。项目所需物料如下: ESP32 DOIT DEVKIT V1板 3x 5mm LED 3x 330欧姆电阻器 面包板 跳线若干 ESP32带一个包含16通道LED PWM控制器,可配置以产生不同特性的PWM信号。项目开始之前需要先安装Arduino IDE,连接妥当后就可以把ESP32 DOIT DEVKIT V1板用作LED PWM控制器了。 使用Arduino IDE进行LED调光的步骤如下: 1. 从0 to 15选择PWM通道。 2. 设置PWM频率,LED频率选择5000Hz较好。 3. 选择信号的占空比:,其分表率范围1-16bits。本项目使用8bit,这样可控制的LED亮度等级值为0-255。 4. 指定信号出现的GPIO or GPIOs:其函数为ledcAttachPin(GPIO, channel)。该函数具有两个变量,第一个GPIO用来输出信号,第二个表示产生信号的通道。 5. 使用PWM控制LED亮度,函数为ledcWrite(channel, dutycycle)。其中,第一个变量产生PWM信号,第一个变量是占空比。 一个LED调光控制 点亮一个LED并调光时,应将LED连接于GPIO 16引脚。 ESP32 DEVKIT V1模块有30个GPIOs,只要能用作输出,就可用作PWM引脚以连接LED。 请打开并拷入如下代码: const int ledPin = 16; const int freq = 5000; const int ledChannel = 0; const int resolution = 8; void setup(){ ledcSetup(ledChannel, freq, resolution); ledcAttachPin(ledPin, ledChannel);} void loop(){ for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){ ledcWrite(ledChannel, dutyCycle); delay(15); } = 0; dutyCycle--){ ledcWrite(ledChannel, dutyCycle); delay(15); }} 这些代码的含义是,设定的PWM信号频率为5000Hz,选择通道 0 来产生信号,信号的分辨率为8bits。 当然,也可以设置为其他参数,获得不同的PWM信号,例如: const int freq = 5000; const int ledChannel = 0; const int resolution = 8; 接下来,选择信号的GPIO引脚,函数为ledcAttachPin(ledPin, ledChannel); 增加LED亮度的占空比为0-255, for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){ ledcWrite(ledChannel, dutyCycle); delay(15); } 然后,从255-0自减,就降低了LED的亮度。 = 0; dutyCycle--){ ledcWrite(ledChannel, dutyCycle); delay(15); } 调节LED亮度,须使用 ledcWrite() 函数。该函数有两个参数:产生信号的通道、duty cycle。注意,这里的 ledcWrite() 函数中产生信号的变量是通道,而不是GPIO。 把代码上传到 ESP32,确定板子和COM端口选择正确,再对照下单路,就可以测试调光效果了。 多个LED调光控制 也可以从相同通道的不同GPIO取得同样的信号,这需要将这些GPIOs连接到 setup() 的相同通道。以下我们对上述操作稍作改动,来通过相同通道的相同PWN信号对3个LED进行调光控制。 我们的目标是通过30 GPIOs的ESP32 DEVKIT V1模块来控制三个LED。 首先,将下列代码拷贝到Arduino IDE中。 // the number of the LED pin const int ledPin = 16; const int ledPin2 = 17; const int ledPin3 = 5; // setting PWM properties const int freq = 5000; const int ledChannel = 0; const int resolution = 8; void setup(){ // configure LED PWM functionalitites ledcSetup(ledChannel, freq, resolution); // attach the channel to the GPIO to be controlled ledcAttachPin(ledPin, ledChannel); ledcAttachPin(ledPin2, ledChannel); ledcAttachPin(ledPin3, ledChannel); } void loop(){ // increase the LED brightness for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){ // changing the LED brightness with PWM ledcWrite(ledChannel, dutyCycle); delay(15); } // decrease the LED brightness = 0; dutyCycle--){ // changing the LED brightness with PWM ledcWrite(ledChannel, dutyCycle); delay(15); } } 这些代码在前面基础上有一些改动:为两个新的LED增加了多个变量,具体参考 GPIO 17 和 GPIO 5。 const int ledPin2 = 17; // 17 corresponds to GPIO17 const int ledPin3 = 5; // 5 corresponds to GPIO5 然后,在 setup() 中,添加如下两行代码,将这两个 GPIOs 指派给通道0。这表示,在两个GPIO的通道0上产生了相同个信号。 ledcAttachPin(ledPin2, ledChannel); ledcAttachPin(ledPin3, ledChannel); 把修改后的代码上传到 ESP32,确定板子和COM端口选择正确后,就可以测试者三个LED调光效果了。 由于所有GPIOs 输出了相同PWM信号,所有三个LED亮度的增加与减少是同时进行的,这样就产生了一个非常美妙的同步效果。 本项目演示了如何在Arduino IDE环境下,使用ESP32的LED PWM控制器进行调光控制。通过设置正确的信号属性,这种方法可用来控制其他PWM输出,如马达、LED 呼吸灯等。
  • 热度 26
    2013-4-26 10:35
    4136 次阅读|
    2 个评论
    呼吸灯是手机上的一个小东西,一个灯由明变暗再由暗变明,象是一个人在呼吸一样。可以用硬件实现这个呼吸灯,但体积会比较大。这里用软件做了一个: #define BREATHLEVEL 6*256 void BreathLED(void){   static uint16_t cnt=0,illu=0,rep=0,stt=1;   rep++;   cnt++;   if(cnt illu) LED2OFF();   else LED2ON();   if(rep == BREATHLEVEL){     rep = 0;     cnt = 0;     if(stt){       illu++;       if(illu = BREATHLEVEL){         stt = 0;       }      }       else{              illu--;       if(illu 1){         stt = 1;       }         }     } }   把这个函数中的点灯灭灯的宏指向板子上的硬件LED。在定时中断里调用这个函数就能实现呼吸灯。
  • 热度 22
    2011-10-30 20:51
    2274 次阅读|
    0 个评论
     这是一个简单而有趣的开源项目,硬件制作极简单,又有一定的趣味性,既适合初学者入门学习使用,也适合于做教学项目。 打开:七彩灯视频(http://edures.lyvec.net/Item/73.aspx)可以看到3组视频。     先看第1段视频,猜一猜怎么做的?然后看第2段视频和第3段视频,里里外外看个够!只有1个8脚集成电路,3个按钮和1个LED灯。片中的USB纯粹用于供电。 所使用的芯片是STC15系列,这是与80C51在指令级兼容的高速单片机芯片,仅有8个引脚。 原理图如下:   本打算将程序全贴上,但系统不让发,说是超过4000字了?其实肯定没有4000字,,,,没办法,给个链接啦。 http://edures.lyvec.net/Item/74.aspx  
相关资源