diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 0000000..f18f90a --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,31 @@ +# This variable should contain a space separated list of all +# the directories containing buildable applications (usually +# prefixed with the app_ prefix) +BUILD_SUBDIRS = ./app_rgb_cycle_breathing_example \ + ./app_hsv_cycle_example \ + ./app_volume_level_example \ + ./app_test_fill_gradient_with_groups \ + +# This variable should contain a space separated list of all +# the directories containing buildable plugins (usually +# prefixed with the plugin_ prefix) +PLUGIN_SUBDIRS = + +# This variable should contain a space separated list of all +# the directories containing applications with a 'test' make target +TEST_SUBDIRS = + +# Provided that the above variables are set you shouldn't need to modify +# the targets below here. + +%.all: + cd $* && xmake BUILD_TEST_CONFIGS=1 all + +%.clean: + cd $* && xmake BUILD_TEST_CONFIGS=1 clean + +all: $(foreach x, $(BUILD_SUBDIRS), $x.all) +plugins: $(foreach x, $(PLUGIN_SUBDIRS), $x.all) +clean: $(foreach x, $(BUILD_SUBDIRS), $x.clean) +clean_plugins: $(foreach x, $(PLUGIN_SUBDIRS), $x.clean) +test: $(foreach x, $(TEST_SUBDIRS), $x.test) diff --git a/examples/app_hsv_cycle_example/bin/app_hsv_cycle_example.xe b/examples/app_hsv_cycle_example/bin/app_hsv_cycle_example.xe index c0acbe3..b7cc928 100644 Binary files a/examples/app_hsv_cycle_example/bin/app_hsv_cycle_example.xe and b/examples/app_hsv_cycle_example/bin/app_hsv_cycle_example.xe differ diff --git a/examples/app_rgb_cycle_breathing_example/bin/app_rgb_cycle_breathing_example.xe b/examples/app_rgb_cycle_breathing_example/bin/app_rgb_cycle_breathing_example.xe index 93b50d8..6b92209 100644 Binary files a/examples/app_rgb_cycle_breathing_example/bin/app_rgb_cycle_breathing_example.xe and b/examples/app_rgb_cycle_breathing_example/bin/app_rgb_cycle_breathing_example.xe differ diff --git a/examples/app_test_fill_gradient_with_groups/Makefile b/examples/app_test_fill_gradient_with_groups/Makefile new file mode 100644 index 0000000..9b0f834 --- /dev/null +++ b/examples/app_test_fill_gradient_with_groups/Makefile @@ -0,0 +1,21 @@ +# `TARGET` 变量决定了应用程序编译的目标系统。它可以引用源目录中的一个 XN 文件,或者是在编译时作为 `--target` 选项的一个有效参数。 + +TARGET = XCORE-AI-EXPLORER + +# 编译选项 +# 构建应用程序时传递给 xcc 的参数 +# O2: xcc编译器优化等级2 +# report: 打开编译报告 +# g: 生成调试信息 +# fxscope: 使用 xSCOPE,对代码进行跟踪(默认使用xlink) +BUILD_FLAGS = -O2 -g -DDEBUG_PRINT_ENABLE=1 -report -fxscope + +USED_MODULES = lib_rgb + +XCC_FLAGS = $(BUILD_FLAGS) + +#============================================================================= +# 下面部分的 Makefile 包含了用于编译 XMOS 应用程序的公共构建基础设施。你无需编辑此处以下的内容。 + +XMOS_MAKE_PATH ?= ../.. +include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common \ No newline at end of file diff --git a/examples/app_test_fill_gradient_with_groups/bin/app_test_fill_gradient_with_groups.xe b/examples/app_test_fill_gradient_with_groups/bin/app_test_fill_gradient_with_groups.xe new file mode 100644 index 0000000..22d0fa9 Binary files /dev/null and b/examples/app_test_fill_gradient_with_groups/bin/app_test_fill_gradient_with_groups.xe differ diff --git a/examples/app_test_fill_gradient_with_groups/src/main.xc b/examples/app_test_fill_gradient_with_groups/src/main.xc new file mode 100644 index 0000000..e874bc3 --- /dev/null +++ b/examples/app_test_fill_gradient_with_groups/src/main.xc @@ -0,0 +1,24 @@ +/** @brief 循环输出整个HSV色域 + * @author Vergil Wong + * @date 2023-11-11 + * @param + * @return + */ + +#include "stdint.h" +#include // 包含基本的输入输出函数 +#include // 包含对封装的定义,引用以使用 on tile[] 语法 +#include "volume_level.h" +#include "rgb_effect.h" + +int main() // 定义主函数 +{ + par + { + on tile[1]: + { + test_fill_gradient_with_groups(); + } + } + return 0; // 返回0,表示程序正常结束 +} diff --git a/examples/app_volume_level_example/Makefile b/examples/app_volume_level_example/Makefile new file mode 100644 index 0000000..9b0f834 --- /dev/null +++ b/examples/app_volume_level_example/Makefile @@ -0,0 +1,21 @@ +# `TARGET` 变量决定了应用程序编译的目标系统。它可以引用源目录中的一个 XN 文件,或者是在编译时作为 `--target` 选项的一个有效参数。 + +TARGET = XCORE-AI-EXPLORER + +# 编译选项 +# 构建应用程序时传递给 xcc 的参数 +# O2: xcc编译器优化等级2 +# report: 打开编译报告 +# g: 生成调试信息 +# fxscope: 使用 xSCOPE,对代码进行跟踪(默认使用xlink) +BUILD_FLAGS = -O2 -g -DDEBUG_PRINT_ENABLE=1 -report -fxscope + +USED_MODULES = lib_rgb + +XCC_FLAGS = $(BUILD_FLAGS) + +#============================================================================= +# 下面部分的 Makefile 包含了用于编译 XMOS 应用程序的公共构建基础设施。你无需编辑此处以下的内容。 + +XMOS_MAKE_PATH ?= ../.. +include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common \ No newline at end of file diff --git a/examples/app_volume_level_example/bin/app_volume_level_example.xe b/examples/app_volume_level_example/bin/app_volume_level_example.xe new file mode 100644 index 0000000..6bc8d24 Binary files /dev/null and b/examples/app_volume_level_example/bin/app_volume_level_example.xe differ diff --git a/examples/app_volume_level_example/src/main.xc b/examples/app_volume_level_example/src/main.xc new file mode 100644 index 0000000..9c593f9 --- /dev/null +++ b/examples/app_volume_level_example/src/main.xc @@ -0,0 +1,25 @@ +/** @brief 循环输出整个HSV色域 + * @author Vergil Wong + * @date 2023-11-11 + * @param + * @return + */ + +#include "stdint.h" +#include // 包含基本的输入输出函数 +#include // 包含对封装的定义,引用以使用 on tile[] 语法 +#include "volume_level.h" +#include "rgb_effect.h" + +int main() // 定义主函数 +{ + par + { + on tile[1]: + { + // volume_level_test(); + test_cycleHSV_with_vol_level(); + } + } + return 0; // 返回0,表示程序正常结束 +} diff --git a/lib_rgb/api/misc_utils.h b/lib_rgb/api/misc_utils.h new file mode 100644 index 0000000..1f9e5dc --- /dev/null +++ b/lib_rgb/api/misc_utils.h @@ -0,0 +1,4 @@ +#include +#include + +void reverse_buf(uint32_t *start, size_t count); \ No newline at end of file diff --git a/lib_rgb/api/rgb_effect.h b/lib_rgb/api/rgb_effect.h index da8d30c..fce5b12 100644 --- a/lib_rgb/api/rgb_effect.h +++ b/lib_rgb/api/rgb_effect.h @@ -90,10 +90,11 @@ void cycleRGB_driver(); */ void cycleHSV_driver(); - +void test_cycleHSV_with_vol_level(); /** * 用于测试HSV溢出 */ -void HSV_to_RGB_TEST(); +void test_HSV_to_RGB(); +void test_fill_gradient_with_groups(); #endif // RGB_EFFECT_H \ No newline at end of file diff --git a/lib_rgb/api/volume_level.h b/lib_rgb/api/volume_level.h new file mode 100644 index 0000000..8f06888 --- /dev/null +++ b/lib_rgb/api/volume_level.h @@ -0,0 +1,5 @@ +#include + +unsigned get_volume_level(int loudness_value); + +void volume_level_test(); \ No newline at end of file diff --git a/lib_rgb/src/misc_utils.xc b/lib_rgb/src/misc_utils.xc new file mode 100644 index 0000000..4021e47 --- /dev/null +++ b/lib_rgb/src/misc_utils.xc @@ -0,0 +1,13 @@ +#include +#include + +void reverse_buf(uint32_t *start, size_t count) { + uint32_t *end = start + count - 1; + while (start < end) { + uint32_t temp = *start; + *start = *end; + *end = temp; + start++; + end--; + } +} \ No newline at end of file diff --git a/lib_rgb/src/rgb_effect.xc b/lib_rgb/src/rgb_effect.xc index 33e9bdc..22eef42 100644 --- a/lib_rgb/src/rgb_effect.xc +++ b/lib_rgb/src/rgb_effect.xc @@ -5,12 +5,17 @@ #include "xclib.h" #include "timer.h" #include "rgb_driver.h" +#include "volume_level.h" +#include "misc_utils.h" // RGB灯的数量 #ifndef NUM_RGBS #define NUM_RGBS (12) #endif +#ifndef NUM_RGB_GROUPS +#define NUM_RGB_GROUPS (2) +#endif // 控制RGB亮度的最大值,不超过255 #ifndef RGB_MAX #define RGB_MAX (20) @@ -72,6 +77,7 @@ void is_HSV_valid(uint32_t *hue, uint32_t *sat, uint32_t *value) } // 将HSV颜色值转换为RGB颜色值 +// TODO:使用定点/S32以增加计算效率 uint32_t HSV_to_RGB(uint32_t *hue, uint32_t *sat, uint32_t *value) { @@ -178,24 +184,29 @@ uint32_t cycleHSV(uint32_t *hue) if (*hue < 359) { (*hue) += 1; - printf("hue is: 0x%06X\n", *hue); + // printf("hue is: 0x%06X\n", *hue); } else { (*hue) = 0; - printf("--------hue is: 0x%06X----------\n", *hue); + // printf("--------hue is: 0x%06X----------\n", *hue); } return(HSV_to_RGB(hue, &sat, &value)); } // 将单一颜色填充到整个RGB条中,并控制显示颜色的时间长度 -void fill_gradient(uint32_t *buf, uint32_t color) +void fill_gradient(uint32_t *buf, size_t num_filled_rgb, uint32_t color) { // 遍历缓冲区的每个元素,将其设置为提供的颜色值 - for (int i = 0; i < NUM_RGBS; i++) + for (size_t i = 0; i < num_filled_rgb; i++) { buf[i] = color; } + // 熄灭剩下的RGB灯 + for (size_t i = num_filled_rgb; i < NUM_RGBS; i++) + { + buf[i] = 0x000000; + } // 将缓冲区中的颜色数组输出到RGB条上 output_rgb_array(buf, NUM_RGBS); @@ -203,6 +214,37 @@ void fill_gradient(uint32_t *buf, uint32_t color) delay_milliseconds(DELAY_TIME_RGB); } + + +void fill_gradient_with_groups(uint32_t *buf, uint32_t *colors, size_t *num_filled_rgb, size_t num_groups) +{ + size_t max_leds_per_group = NUM_RGBS / num_groups; + + for (size_t group = 0; group < num_groups; group++) { + // 填充每个组的LED + uint32_t *group_buf = buf + group * max_leds_per_group; + for (size_t i = 0; i < num_filled_rgb[group]; i++) { + *(group_buf + i) = colors[group]; + } + + // 熄灭该组剩余的LED + for (size_t i = num_filled_rgb[group]; i < max_leds_per_group; i++) { + *(group_buf + i) = 0x000000; + } + + // 如果组号为奇数,翻转该组对应的buffer元素 + if (group % 2 != 0) { + reverse_buf(group_buf, max_leds_per_group); + } + } + + // 将缓冲区输出到RGB条 + output_rgb_array(buf, NUM_RGBS); + + // 延迟以控制显示持续时间 + delay_milliseconds(DELAY_TIME_RGB); +} + // TODO:添加可合并选项 // 驱动HSV颜色空间中的颜色循环,以实现连续的颜色渐变效果。 void cycleHSV_driver() @@ -218,7 +260,7 @@ void cycleHSV_driver() while (1) { // 用当前渐变颜色填充RGB数组,然后发送给rgb阵列 - fill_gradient(buf, current_color); + fill_gradient(buf, NUM_RGBS, current_color); // 更改下一个颜色 current_color = cycleHSV(¤t_hue); @@ -242,7 +284,7 @@ void cycleRGB_driver() while (1) { // 用当前渐变颜色填充RGB数组 - fill_gradient(buf, current_color); + fill_gradient(buf, NUM_RGBS, current_color); // 更改下一个渐变的基色 current_color = cycleRGB(current_color, &direction); @@ -250,8 +292,43 @@ void cycleRGB_driver() } } +void test_cycleHSV_with_vol_level() +{ + + uint32_t buf[NUM_RGBS]; // 定义一个用于存储RGB值的缓冲区,大小由NUM_RGBS宏确定 + uint32_t current_hue = 0; // 从红色开始的当前色相值 + // uint32_t current_sat = 100; // 当前饱和度值,初始化为满饱和度 + // uint32_t current_val = 100; // 当前亮度值,初始化为最大亮度 + uint32_t current_color[NUM_RGB_GROUPS] = {0x000000, 0x000000}; + + srand(1); // 初始化随机数种子 + size_t random_levels[NUM_RGB_GROUPS]; + par // 使用par关键词并发执行下面的代码块,这些线程默认在tile[1]上运行 + { + while (1) + { + for (size_t i = 0; i < NUM_RGB_GROUPS; i++) + { + *(random_levels + i) = get_volume_level(rand() % 101 - 100); + } + + // 用当前渐变颜色填充RGB数组,然后发送给rgb阵列 + fill_gradient_with_groups(buf, current_color, random_levels, NUM_RGB_GROUPS); + + // 更改下一个颜色 + for (size_t i = 0; i < NUM_RGB_GROUPS; i++) + { + *(current_color + i) = cycleHSV(¤t_hue); + } + + // 打印出当前的GRB颜色值 + // printf("GRB color is: 0x%06X\n", current_color); + } + } +} + // 测试 HSV_to_RGB,以及饱和处理 -void HSV_to_RGB_TEST() +void test_HSV_to_RGB() { uint32_t hue, sat, value; // HSV值 uint32_t color; // RGB值 @@ -263,3 +340,29 @@ void HSV_to_RGB_TEST() color = HSV_to_RGB(&hue, &sat, &value); printf("GRB color is: 0x%06X\n", color); } + +void test_fill_gradient_with_groups() { + uint32_t buffer[NUM_RGBS]; + uint32_t colors[] = {0xFF0000, 0x00FF00}; // 红,绿 + size_t num_filled_rgb[] = {2, 3}; // 每组填充数量 + size_t num_groups = sizeof(colors) / sizeof(colors[0]); + int success = 1; // 使用int代替bool,1代表true,0代表false + + fill_gradient_with_groups(buffer, colors, num_filled_rgb, num_groups); + + // 验证 + for (size_t i = 0; i < NUM_RGBS; i++) { + size_t group = i / (NUM_RGBS / num_groups); + size_t group_led_start = group * (NUM_RGBS / num_groups); + uint32_t expected_color = (i < group_led_start + num_filled_rgb[group]) ? colors[group] : 0x000000; + if (buffer[i] != expected_color) { + success = 0; // 设置为false + printf("Test failed at LED %zu: expected 0x%06X, got 0x%06X\n", i, expected_color, buffer[i]); + break; + } + } + + if (success) { + printf("Test passed: All LEDs are correctly set.\n"); + } +} diff --git a/lib_rgb/src/volume_level.xc b/lib_rgb/src/volume_level.xc new file mode 100644 index 0000000..83f4847 --- /dev/null +++ b/lib_rgb/src/volume_level.xc @@ -0,0 +1,47 @@ +#include +#include + + +#define VOL_LEVEL_TABLE \ + { 0 , 6 }, \ + { -3 , 5 }, \ + { -9 , 4 }, \ + { -14, 3 }, \ + { -30, 2 }, \ + { -62, 1 }, + +// 定义音量等级结构体 +typedef struct { + int vol; // 响度值 + unsigned level; // 音量等级 +} vol_level_table_t; + +const vol_level_table_t vol_level_table[] = {VOL_LEVEL_TABLE}; +#define VOLUME_LEVELS_COUNT (sizeof(vol_level_table) / sizeof(vol_level_table[0])) + +unsigned get_volume_level(int loudness_value) { + // 默认返回音量等级0 + int level = 0; + + // 从最大响度值开始向下找 + for (int i = 0; i < VOLUME_LEVELS_COUNT; ++i) { + if (loudness_value >= vol_level_table[i].vol) { + level = vol_level_table[i].level; + break; // 找到后立即退出循环 + } + } + + return level; +} + +void volume_level_test() { + // 测试不同的响度值 + uint32_t test_loudness_values[] = {1, 0, -2, -5, -8, -20, -30, -40, -60, -62, -70, }; + int num_tests = sizeof(test_loudness_values) / sizeof(test_loudness_values[0]); + + for (int i = 0; i < num_tests; ++i) { + printf("Loudness: %d dB, Volume Level: %d\n", + test_loudness_values[i], + get_volume_level(test_loudness_values[i])); + } +} \ No newline at end of file diff --git a/readme.md b/readme.md index 87aced2..6484fa4 100644 --- a/readme.md +++ b/readme.md @@ -87,7 +87,8 @@ output_rgb_array(rgb_array, 3); - [ ] 当RGB_MAX等值超限时,raise error - [ ] 为绘制RGB的函数添加可合并选项,以减少资源占用 - [ ] 添加更多应用光效 -- [ ] 音频响度响应 +- [x] 音频响度响应 +- [ ] 使用定点/S32以增加`HSV_to_RGB`的计算效率 ## 贡献 如果你有任何改进意见或者发现了bug,请通过issues或pull requests来提交。