添加RGB灯

This commit is contained in:
OPTOC
2025-08-20 11:31:55 +08:00
parent c704bbd24b
commit 0853287c7c
9 changed files with 426 additions and 2 deletions

View File

@@ -30,6 +30,9 @@ list(APPEND srcs "utils/sb_aes.c")
list(APPEND srcs "drivers/sertrf/sertrf.c")
list(APPEND srcs "drivers/sertrf/device.c")
list(APPEND srcs "drivers/led_strip/led_strip.c")
list(APPEND srcs "drivers/led_strip/led_strip_encoder.c")
if(CONFIG_BUILD_BLE)
list(APPEND srcs "drivers/data_port/ble_spp/ble_spp_server.c")
list(APPEND srcs "drivers/data_port/ble_spp/ble_spp_server_shell.c")

View File

@@ -0,0 +1,103 @@
#include "led_strip.h"
rmt_channel_handle_t led_chan = NULL;
rmt_encoder_handle_t led_encoder = NULL;
rmt_transmit_config_t tx_config = {
.loop_count = 0, // no transfer loop
};
static uint8_t led_strip_pixels[EXAMPLE_LED_NUMBERS * 3];
uint16_t toggle_cycle = 1000;
static uint8_t rgb_color_index = RGB_COLOR_RAD;
rgb_color_t rgb_color_rad = {0,255,0,0,0};
rgb_color_t rgb_color_green = {0,0,255,0,0};
rgb_color_t rgb_color_blue = {0,0,0,255,0};
void led_strip_init(void)
{
// ESP_LOGI(TAG, "Create RMT TX channel");
rmt_tx_channel_config_t tx_chan_config = {
.clk_src = RMT_CLK_SRC_DEFAULT, // select source clock
.gpio_num = RMT_LED_STRIP_GPIO_NUM,
.mem_block_symbols = 64, // increase the block size can make the LED less flickering
.resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ,
.trans_queue_depth = 4, // set the number of transactions that can be pending in the background
};
ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &led_chan));
// ESP_LOGI(TAG, "Install led strip encoder");
led_strip_encoder_config_t encoder_config = {
.resolution = RMT_LED_STRIP_RESOLUTION_HZ,
};
ESP_ERROR_CHECK(rmt_new_led_strip_encoder(&encoder_config, &led_encoder));
// ESP_LOGI(TAG, "Enable RMT TX channel");
ESP_ERROR_CHECK(rmt_enable(led_chan));
// ESP_LOGI(TAG, "Start LED rainbow chase");
}
void led_strip_set_pixel(uint8_t pin, uint8_t index, uint8_t green, uint8_t blue, uint8_t red)
{
led_strip_pixels[0 + index * 3] = green;
led_strip_pixels[1 + index * 3] = red;
led_strip_pixels[2 + index * 3] = blue;
ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, sizeof(led_strip_pixels), &tx_config));
ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY));
}
void work_rgb_led_start(void)
{
led_strip_init();
/* 创建 shell 的接收任务 _work_sh() */
static os_work_t work_handler_rgb_led;
os_work_create(&work_handler_rgb_led, "work-rgb-led", _work_rgb_led, NULL, OS_PRIORITY_NORMAL);
os_work_submit(default_os_work_q_hdl, &work_handler_rgb_led, toggle_cycle * 0.5);
}
void _work_rgb_led(void *arg)
{
static rgb_color_t* expression;
switch (rgb_color_index)
{
case RGB_COLOR_RAD:
expression = &rgb_color_rad;
break;
case RGB_COLOR_GREEN:
expression = &rgb_color_green;
break;
case RGB_COLOR_BLUE:
expression = &rgb_color_blue;
break;
default:
break;
}
rgb_toggle(expression);
os_work_later(toggle_cycle * 0.5);
}
void rgb_update_cyle(uint16_t cyle)
{
toggle_cycle = cyle;
}
void rgb_toggle(rgb_color_t* rgb_color)
{
if(rgb_color->toggle_flag == 0)
led_strip_set_pixel(0,rgb_color->index,rgb_color->green,rgb_color->blue,rgb_color->red);
else
led_strip_set_pixel(0,rgb_color->index,0,0,0);
rgb_color->toggle_flag = !rgb_color->toggle_flag;
}
void rgb_color_change(uint8_t index, uint8_t color)
{
rgb_color_index = color;
}

View File

@@ -0,0 +1,48 @@
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include "led_strip_encoder.h"
#include "esp_log.h"
#include "driver/rmt_tx.h"
#include "freertos/FreeRTOS.h"
#include "os/os.h"
#include "../../config/board_config.h"
#define RMT_LED_STRIP_RESOLUTION_HZ 10000000 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution)
// #define RMT_LED_STRIP_GPIO_NUM g_cfg_board->rgb_led_pin
#define RMT_LED_STRIP_GPIO_NUM 8
#define EXAMPLE_LED_NUMBERS 2
#define EXAMPLE_CHASE_SPEED_MS 10
// static const char *TAG = "example";
extern rmt_channel_handle_t led_chan;
extern rmt_encoder_handle_t led_encoder;
extern rmt_transmit_config_t tx_config;
typedef struct rgb_color_s
{
uint8_t index;
uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t toggle_flag;
}rgb_color_t;
typedef enum
{
RGB_COLOR_RAD = 0,
RGB_COLOR_GREEN,
RGB_COLOR_BLUE,
}RGB_COLOR;
void led_strip_init(void);
void led_strip_set_pixel(uint8_t pin, uint8_t index, uint8_t green, uint8_t blue, uint8_t red);
void work_rgb_led_start(void);
void _work_rgb_led(void *arg);
void rgb_update_cyle(uint16_t cyle);
void rgb_toggle(rgb_color_t* rgb_color);
void rgb_color_change(uint8_t index, uint8_t color);

View File

@@ -0,0 +1,125 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_check.h"
#include "led_strip_encoder.h"
static const char *TAG = "led_encoder";
typedef struct {
rmt_encoder_t base;
rmt_encoder_t *bytes_encoder;
rmt_encoder_t *copy_encoder;
int state;
rmt_symbol_word_t reset_code;
} rmt_led_strip_encoder_t;
static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder;
rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder;
rmt_encode_state_t session_state = RMT_ENCODING_RESET;
rmt_encode_state_t state = RMT_ENCODING_RESET;
size_t encoded_symbols = 0;
switch (led_encoder->state) {
case 0: // send RGB data
encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
led_encoder->state = 1; // switch to next state when current encoding session finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space for encoding artifacts
}
// fall-through
case 1: // send reset code
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code,
sizeof(led_encoder->reset_code), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
led_encoder->state = RMT_ENCODING_RESET; // back to the initial encoding session
state |= RMT_ENCODING_COMPLETE;
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space for encoding artifacts
}
}
out:
*ret_state = state;
return encoded_symbols;
}
static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_del_encoder(led_encoder->bytes_encoder);
rmt_del_encoder(led_encoder->copy_encoder);
free(led_encoder);
return ESP_OK;
}
static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_encoder_reset(led_encoder->bytes_encoder);
rmt_encoder_reset(led_encoder->copy_encoder);
led_encoder->state = RMT_ENCODING_RESET;
return ESP_OK;
}
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
rmt_led_strip_encoder_t *led_encoder = NULL;
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
led_encoder = rmt_alloc_encoder_mem(sizeof(rmt_led_strip_encoder_t));
ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder");
led_encoder->base.encode = rmt_encode_led_strip;
led_encoder->base.del = rmt_del_led_strip_encoder;
led_encoder->base.reset = rmt_led_strip_encoder_reset;
// different led strip might have its own timing requirements, following parameter is for WS2812
rmt_bytes_encoder_config_t bytes_encoder_config = {
.bit0 = {
.level0 = 1,
.duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us
.level1 = 0,
.duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us
},
.bit1 = {
.level0 = 1,
.duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us
.level1 = 0,
.duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us
},
.flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0
};
ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
rmt_copy_encoder_config_t copy_encoder_config = {};
ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(&copy_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed");
uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us
led_encoder->reset_code = (rmt_symbol_word_t) {
.level0 = 0,
.duration0 = reset_ticks,
.level1 = 0,
.duration1 = reset_ticks,
};
*ret_encoder = &led_encoder->base;
return ESP_OK;
err:
if (led_encoder) {
if (led_encoder->bytes_encoder) {
rmt_del_encoder(led_encoder->bytes_encoder);
}
if (led_encoder->copy_encoder) {
rmt_del_encoder(led_encoder->copy_encoder);
}
free(led_encoder);
}
return ret;
}

View File

@@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "driver/rmt_encoder.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Type of led strip encoder configuration
*/
typedef struct {
uint32_t resolution; /*!< Encoder resolution, in Hz */
} led_strip_encoder_config_t;
/**
* @brief Create RMT encoder for encoding LED strip pixels into RMT symbols
*
* @param[in] config Encoder configuration
* @param[out] ret_encoder Returned encoder handle
* @return
* - ESP_ERR_INVALID_ARG for any invalid arguments
* - ESP_ERR_NO_MEM out of memory when creating led strip encoder
* - ESP_OK if creating encoder successfully
*/
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,100 @@
#include "led_strip_shell.h"
#include "../pin_io/pin_io.h"
static int32_t s_value = 0;
SH_CMD_FN(set);
SH_CMD_FN(start);
SH_CMD_FN(clr);
//设置子命令
SH_DEF_SUB_CMD(
sub_led,
SH_SETUP_CMD("set", "点亮灯珠 <引脚号> <灯珠号> [红] [绿] [蓝]", set, NULL), //
SH_SETUP_CMD("start", "开启按键检测 1:初始化 2:检测", start, NULL), //
SH_SETUP_CMD("clr", "熄灭全部灯珠 <引脚号>", clr, NULL), //
);
//设置主命令
SH_DEF_CMD(
_register_cmd,
SH_SETUP_CMD("led", "操作灯带驱动", NULL, sub_led), //
);
//设置存储解析到的数据
static int _set_value(const char *argv[]) { return SET_VAR(&s_value, 0, 0x100); }
void led_strip_shell_register(void)
{
sh_register_cmd(&_register_cmd);
}
void led_strip_shell_unregister(void)
{
}
SH_CMD_FN(set)
{
uint32_t pin = 0, index = 0, red = 0, green = 0, blue = 0;
if (argc < 5)
{
sh_echo(sh_hdl, "输入少于 5 个参数\r\n");
return -1;
}
if (argc >= 1 && _set_value(&argv[0]))
return -1;
pin = *(volatile __typeof(s_value) *)&s_value;
if (argc >= 2 && _set_value(&argv[1]))
return -1;
index = *(volatile __typeof(s_value) *)&s_value;
if (argc >= 3 && _set_value(&argv[2]))
return -1;
red = *(volatile __typeof(s_value) *)&s_value;
if (argc >= 4 && _set_value(&argv[3]))
return -1;
green = *(volatile __typeof(s_value) *)&s_value;
if (argc >= 5 && _set_value(&argv[4]))
return -1;
blue = *(volatile __typeof(s_value) *)&s_value;
led_strip_set_pixel(pin,index,green,red,blue);
return 0;
}
SH_CMD_FN(start)
{
static uint32_t start_flag;
if (argc < 1)
{
sh_echo(sh_hdl, "输入少于 1 个参数\r\n");
return -1;
}
if (argc >= 1 && _set_value(&argv[0]))
return -1;
start_flag = *(volatile __typeof(s_value) *)&s_value;
if (start_flag == 1)
{
// pin_cfg_input(&g_cfg_board->key_reset);
}
else if (start_flag == 2)
{
// bool data_flag = pin_get_valid(&g_cfg_board->key_reset);
// sh_echo(sh_hdl, "数据 %d\r\n", data_flag);
}
return 0;
}
SH_CMD_FN(clr)
{
if (argc < 1)
{
sh_echo(sh_hdl, "输入少于 1 个参数\r\n");
return -1;
}
return 0;
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include "led_strip.h"
#include "shell/sh.h"
#include "sh_vset.h"
void led_strip_shell_register(void);
void led_strip_shell_register(void);

View File

@@ -10,7 +10,8 @@ void sertrf_init(void)
{
SYS_LOG_WRN("device init error");
}
//RGB灯
work_rgb_led_start();
sertrf_start();
}
void sertrf_start(void)

View File

@@ -1,7 +1,7 @@
#pragma once
#include "device.h"
#include "../led_strip/led_strip.h"
typedef struct
{