新增:随响度响应的RGB灯组

This commit is contained in:
2023-11-12 22:24:17 +08:00
parent 5b227abc8b
commit 47eb373c63
16 changed files with 306 additions and 10 deletions

31
examples/Makefile Normal file
View File

@@ -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)

View File

@@ -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

View File

@@ -0,0 +1,24 @@
/** @brief 循环输出整个HSV色域
* @author Vergil Wong
* @date 2023-11-11
* @param
* @return
*/
#include "stdint.h"
#include <stdio.h> // 包含基本的输入输出函数
#include <platform.h> // 包含对封装的定义,引用以使用 on tile[] 语法
#include "volume_level.h"
#include "rgb_effect.h"
int main() // 定义主函数
{
par
{
on tile[1]:
{
test_fill_gradient_with_groups();
}
}
return 0; // 返回0表示程序正常结束
}

View File

@@ -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

View File

@@ -0,0 +1,25 @@
/** @brief 循环输出整个HSV色域
* @author Vergil Wong
* @date 2023-11-11
* @param
* @return
*/
#include "stdint.h"
#include <stdio.h> // 包含基本的输入输出函数
#include <platform.h> // 包含对封装的定义,引用以使用 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表示程序正常结束
}

4
lib_rgb/api/misc_utils.h Normal file
View File

@@ -0,0 +1,4 @@
#include <stdint.h>
#include <stddef.h>
void reverse_buf(uint32_t *start, size_t count);

View File

@@ -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

View File

@@ -0,0 +1,5 @@
#include <stdint.h>
unsigned get_volume_level(int loudness_value);
void volume_level_test();

13
lib_rgb/src/misc_utils.xc Normal file
View File

@@ -0,0 +1,13 @@
#include <stdint.h>
#include <stddef.h>
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--;
}
}

View File

@@ -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(&current_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(&current_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代替bool1代表true0代表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");
}
}

View File

@@ -0,0 +1,47 @@
#include <stdint.h>
#include <stdio.h>
#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]));
}
}

View File

@@ -87,7 +87,8 @@ output_rgb_array(rgb_array, 3);
- [ ] 当RGB_MAX等值超限时raise error
- [ ] 为绘制RGB的函数添加可合并选项以减少资源占用
- [ ] 添加更多应用光效
- [ ] 音频响度响应
- [x] 音频响度响应
- [ ] 使用定点/S32以增加`HSV_to_RGB`的计算效率
## 贡献
如果你有任何改进意见或者发现了bug请通过issues或pull requests来提交。