增加了语音抽签控制屏幕显示

增加了校准和财位控制电机旋转
This commit is contained in:
CSBOOK\44744
2026-07-01 15:07:59 +08:00
parent aab45b3ec5
commit 5d7c3f91d4
14 changed files with 467 additions and 17 deletions
+2
View File
@@ -10,6 +10,7 @@ set(platform_srcs
"src/runtime/platform_lcd_runtime.c"
"src/platform_stepper_driver.c"
"src/platform_digital_input_driver.c"
"src/platform_io_effects.c"
"src/lcd_direct.c"
"src/lcd_direct_assets.c"
"src/multimodal/audio_pipeline.c"
@@ -27,6 +28,7 @@ set(platform_priv_requires
esp_driver_gpio
esp_driver_i2c
esp_driver_i2s
esp_driver_rmt
esp_driver_spi
esp_event
esp_app_format
@@ -16,5 +16,6 @@ esp_err_t platform_stepper_driver_rotate_angle_with_accel(float angle,
int timeout_ms);
void platform_stepper_driver_power_off(void);
void platform_power_hold_init(void);
esp_err_t platform_io_effects_init(void);
esp_err_t platform_digital_input_driver_configure(const platform_digital_input_config_t *config);
bool platform_digital_input_driver_is_active(const platform_digital_input_config_t *config);
@@ -0,0 +1,313 @@
/*
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "platform_internal.h"
#include <stddef.h>
#include <stdint.h>
#include "driver/gpio.h"
#include "driver/rmt_tx.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#ifndef CONFIG_TQ_LOCAL_TASK_CORE
#define CONFIG_TQ_LOCAL_TASK_CORE 1
#endif
#if CONFIG_TQ_LOCAL_TASK_CORE < 0
#define PLATFORM_IO_EFFECTS_TASK_CORE tskNO_AFFINITY
#else
#define PLATFORM_IO_EFFECTS_TASK_CORE ((BaseType_t)CONFIG_TQ_LOCAL_TASK_CORE)
#endif
#define PLATFORM_RMT_GPIO GPIO_NUM_4
#define PLATFORM_PULSE_GPIO GPIO_NUM_5
#define PLATFORM_PULSE_HIGH_MS 500
#define PLATFORM_PULSE_LOW_MS 200
#define PLATFORM_RMT_LED_COUNT 22
#define PLATFORM_RMT_LED_BYTES_PER_PIXEL 3
#define PLATFORM_RMT_RESOLUTION_HZ 10000000
#define PLATFORM_RMT_FRAME_MS 30
#define PLATFORM_RMT_WAIT_DONE_MS 100
#define PLATFORM_RMT_BRIGHTNESS_MIN 8
#define PLATFORM_RMT_BRIGHTNESS_MAX 180
static const char *TAG = "platform_io_effects";
static TaskHandle_t s_pulse_task;
static TaskHandle_t s_rmt_task;
static const rmt_symbol_word_t s_ws2812_zero = {
.level0 = 1,
.duration0 = PLATFORM_RMT_RESOLUTION_HZ / 10000000 * 3,
.level1 = 0,
.duration1 = PLATFORM_RMT_RESOLUTION_HZ / 10000000 * 9,
};
static const rmt_symbol_word_t s_ws2812_one = {
.level0 = 1,
.duration0 = PLATFORM_RMT_RESOLUTION_HZ / 10000000 * 9,
.level1 = 0,
.duration1 = PLATFORM_RMT_RESOLUTION_HZ / 10000000 * 3,
};
static const rmt_symbol_word_t s_ws2812_reset = {
.level0 = 0,
.duration0 = PLATFORM_RMT_RESOLUTION_HZ / 1000000 * 25,
.level1 = 0,
.duration1 = PLATFORM_RMT_RESOLUTION_HZ / 1000000 * 25,
};
static size_t platform_ws2812_encoder_callback(const void *data,
size_t data_size,
size_t symbols_written,
size_t symbols_free,
rmt_symbol_word_t *symbols,
bool *done,
void *arg)
{
(void)arg;
if (symbols_free < 8U) {
return 0U;
}
size_t data_pos = symbols_written / 8U;
const uint8_t *data_bytes = (const uint8_t *)data;
if (data_pos < data_size) {
size_t symbol_pos = 0U;
for (uint8_t bitmask = 0x80U; bitmask != 0U; bitmask >>= 1U) {
symbols[symbol_pos++] =
(data_bytes[data_pos] & bitmask) ? s_ws2812_one : s_ws2812_zero;
}
return symbol_pos;
}
symbols[0] = s_ws2812_reset;
*done = true;
return 1U;
}
static uint8_t scale_u8(uint8_t value, uint8_t scale)
{
return (uint8_t)(((uint16_t)value * (uint16_t)scale) / 255U);
}
static void hsv_to_rgb(uint8_t hue, uint8_t value, uint8_t *red, uint8_t *green, uint8_t *blue)
{
uint8_t region = hue / 43U;
uint8_t remainder = (uint8_t)((hue - (region * 43U)) * 6U);
uint8_t p = 0U;
uint8_t q = (uint8_t)(((uint16_t)value * (255U - remainder)) / 255U);
uint8_t t = (uint8_t)(((uint16_t)value * remainder) / 255U);
switch (region) {
case 0:
*red = value;
*green = t;
*blue = p;
break;
case 1:
*red = q;
*green = value;
*blue = p;
break;
case 2:
*red = p;
*green = value;
*blue = t;
break;
case 3:
*red = p;
*green = q;
*blue = value;
break;
case 4:
*red = t;
*green = p;
*blue = value;
break;
default:
*red = value;
*green = p;
*blue = q;
break;
}
}
static uint8_t breathing_brightness(uint16_t phase)
{
uint16_t wave = phase & 0x01FFU;
if (wave > 255U) {
wave = 511U - wave;
}
return (uint8_t)(PLATFORM_RMT_BRIGHTNESS_MIN +
((wave * (PLATFORM_RMT_BRIGHTNESS_MAX - PLATFORM_RMT_BRIGHTNESS_MIN)) / 255U));
}
static void fill_breathing_pixels(uint8_t *pixels, size_t pixel_len, uint8_t hue_base, uint8_t brightness)
{
if (pixel_len < (PLATFORM_RMT_LED_COUNT * PLATFORM_RMT_LED_BYTES_PER_PIXEL)) {
return;
}
for (size_t led = 0; led < PLATFORM_RMT_LED_COUNT; ++led) {
uint8_t red = 0U;
uint8_t green = 0U;
uint8_t blue = 0U;
uint8_t hue = (uint8_t)(hue_base + ((led * 256U) / PLATFORM_RMT_LED_COUNT));
hsv_to_rgb(hue, 255U, &red, &green, &blue);
pixels[(led * 3U) + 0U] = scale_u8(green, brightness);
pixels[(led * 3U) + 1U] = scale_u8(red, brightness);
pixels[(led * 3U) + 2U] = scale_u8(blue, brightness);
}
}
static void platform_pulse_task(void *arg)
{
(void)arg;
while (true) {
gpio_set_level(PLATFORM_PULSE_GPIO, 1);
vTaskDelay(pdMS_TO_TICKS(PLATFORM_PULSE_HIGH_MS));
gpio_set_level(PLATFORM_PULSE_GPIO, 0);
vTaskDelay(pdMS_TO_TICKS(PLATFORM_PULSE_LOW_MS));
}
}
static void platform_rmt_led_task(void *arg)
{
(void)arg;
uint8_t pixels[PLATFORM_RMT_LED_COUNT * PLATFORM_RMT_LED_BYTES_PER_PIXEL] = {0};
rmt_channel_handle_t led_channel = NULL;
rmt_encoder_handle_t led_encoder = NULL;
rmt_tx_channel_config_t tx_channel_config = {
.gpio_num = PLATFORM_RMT_GPIO,
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = PLATFORM_RMT_RESOLUTION_HZ,
.mem_block_symbols = 64,
.trans_queue_depth = 4,
.flags = {
.invert_out = false,
.with_dma = false,
.io_loop_back = false,
.io_od_mode = false,
},
};
esp_err_t err = rmt_new_tx_channel(&tx_channel_config, &led_channel);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Create RMT TX channel failed: %s", esp_err_to_name(err));
s_rmt_task = NULL;
vTaskDelete(NULL);
return;
}
rmt_simple_encoder_config_t encoder_config = {
.callback = platform_ws2812_encoder_callback,
.min_chunk_size = 64,
};
err = rmt_new_simple_encoder(&encoder_config, &led_encoder);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Create RMT encoder failed: %s", esp_err_to_name(err));
rmt_del_channel(led_channel);
s_rmt_task = NULL;
vTaskDelete(NULL);
return;
}
err = rmt_enable(led_channel);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Enable RMT channel failed: %s", esp_err_to_name(err));
rmt_del_encoder(led_encoder);
rmt_del_channel(led_channel);
s_rmt_task = NULL;
vTaskDelete(NULL);
return;
}
ESP_LOGI(TAG, "GPIO4 RMT breathing effect started for %u LEDs", (unsigned)PLATFORM_RMT_LED_COUNT);
rmt_transmit_config_t tx_config = {
.loop_count = 0,
};
uint8_t hue_base = 0U;
uint16_t phase = 0U;
while (true) {
fill_breathing_pixels(pixels, sizeof(pixels), hue_base, breathing_brightness(phase));
err = rmt_transmit(led_channel, led_encoder, pixels, sizeof(pixels), &tx_config);
if (err == ESP_OK) {
err = rmt_tx_wait_all_done(led_channel, pdMS_TO_TICKS(PLATFORM_RMT_WAIT_DONE_MS));
}
if (err != ESP_OK) {
ESP_LOGW(TAG, "RMT LED frame failed: %s", esp_err_to_name(err));
}
hue_base++;
phase += 4U;
vTaskDelay(pdMS_TO_TICKS(PLATFORM_RMT_FRAME_MS));
}
}
esp_err_t platform_io_effects_init(void)
{
gpio_config_t pulse_config = {
.pin_bit_mask = BIT64(PLATFORM_PULSE_GPIO),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
esp_err_t err = gpio_config(&pulse_config);
if (err != ESP_OK) {
return err;
}
gpio_set_level(PLATFORM_PULSE_GPIO, 0);
if (s_pulse_task == NULL) {
BaseType_t created = xTaskCreatePinnedToCore(platform_pulse_task,
"platform_pulse",
2048,
NULL,
2,
&s_pulse_task,
PLATFORM_IO_EFFECTS_TASK_CORE);
if (created != pdPASS) {
s_pulse_task = NULL;
return ESP_ERR_NO_MEM;
}
}
if (s_rmt_task == NULL) {
BaseType_t created = xTaskCreatePinnedToCore(platform_rmt_led_task,
"platform_rmt_led",
4096,
NULL,
2,
&s_rmt_task,
PLATFORM_IO_EFFECTS_TASK_CORE);
if (created != pdPASS) {
s_rmt_task = NULL;
return ESP_ERR_NO_MEM;
}
}
ESP_LOGI(TAG,
"GPIO5 pulse output started (%ums high, %ums low); GPIO4 RMT task starting",
(unsigned)PLATFORM_PULSE_HIGH_MS,
(unsigned)PLATFORM_PULSE_LOW_MS);
return ESP_OK;
}
@@ -118,6 +118,11 @@ esp_err_t platform_init(void)
platform_power_hold_init();
esp_err_t io_effects_err = platform_io_effects_init();
if (io_effects_err != ESP_OK) {
ESP_LOGW(TAG, "IO effects init failed: %s", esp_err_to_name(io_effects_err));
}
#if CONFIG_TQ_STEPPER_ENABLE
esp_err_t err = platform_stepper_driver_init();
if (err != ESP_OK) {