From 784e9cb60060e03f00d6a40ddcab892284925b6a Mon Sep 17 00:00:00 2001 From: Vergil_Wong Date: Sat, 11 Nov 2023 21:00:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86lib=E5=BA=93?= =?UTF-8?q?=E7=9A=84=E4=B8=BB=E8=A6=81=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - HSV颜色循环驱动 - RGB灯条驱动 - 模拟呼吸灯 - 色调循环 - 颜色转换 - 颜色填充 --- lib_rgb/api/rgb_driver.h | 32 +++++ lib_rgb/api/rgb_effect.h | 99 ++++++++++++++ lib_rgb/module_build_info | 10 ++ lib_rgb/src/rgb_driver.xc | 79 ++++++++++++ lib_rgb/src/rgb_effect.xc | 265 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 485 insertions(+) create mode 100644 lib_rgb/api/rgb_driver.h create mode 100644 lib_rgb/api/rgb_effect.h create mode 100644 lib_rgb/module_build_info create mode 100644 lib_rgb/src/rgb_driver.xc create mode 100644 lib_rgb/src/rgb_effect.xc diff --git a/lib_rgb/api/rgb_driver.h b/lib_rgb/api/rgb_driver.h new file mode 100644 index 0000000..22481d3 --- /dev/null +++ b/lib_rgb/api/rgb_driver.h @@ -0,0 +1,32 @@ +#ifndef RGB_DRIVER_H +#define RGB_DRIVER_H + +#include "stdint.h" + +/** 串行输出24位值。 + * + * 此函数接收一个32位无符号整数,并将其作为24位值串行输出。 + * 假设值的最高有效8位不使用。该函数将位顺序反转,然后使用定时器控制 + * 的时间信息逐位串行输出。 + * + * 输出操作在第4个引脚上完成,定时信息由定时器'tmr'提供。该函数会打印 + * 每个位的值和fall_time。 + * TODO: 适配其他类型的引脚和bit口 + * + * \param value 要串行输出为24位的32位值。 + */ +void output_24bit_value_serially(uint32_t value); + +/** 输出RGB值数组。 + * + * 此函数接收一个包含32位RGB值的数组以及要输出的RGB数量。 + * 它调用'output_24bit_value_serially'函数为每个RGB值进行串行输出。 + * + * 每个RGB值都使用'output_24bit_value_serially'函数作为24位值发送。 + * + * \param buf 包含32位RGB值的缓冲区。 + * \param num_rgbs 要输出的RGB值数量。 + */ +void output_rgb_array(uint32_t buf[], uint32_t num_rgbs); + +#endif // RGB_DRIVER_H diff --git a/lib_rgb/api/rgb_effect.h b/lib_rgb/api/rgb_effect.h new file mode 100644 index 0000000..da8d30c --- /dev/null +++ b/lib_rgb/api/rgb_effect.h @@ -0,0 +1,99 @@ +#ifndef RGB_EFFECT_H +#define RGB_EFFECT_H + +#include + +/** + * 定义渐变方向的枚举类型。 + * + * 该枚举用于指定颜色渐变过程中亮度的变化方向,用于控制RGB颜色空间的遍历, + * 实现颜色的平滑过渡,如呼吸灯效果。 + */ +typedef enum +{ + INCREMENTING, ///< 亮度递增:用于指示颜色亮度逐渐增加的渐变方向。 + DECREMENTING ///< 亮度递减:用于指示颜色亮度逐渐减少的渐变方向。 +} GradientDirection; + + +/** 遍历RGB颜色空间以实现呼吸灯效果。 + * + * 此函数通过逐步调整RGB值来模拟呼吸灯效果,根据提供的方向增加或减少颜色亮度。 + * 它更新颜色值,并将新颜色值通过RGB条输出。 + * + * \param buf 指向存储RGB值的缓冲区的指针。 + * \param color 当前颜色值。 + * \param direction 指向当前渐变方向的指针,可以是递增或递减。 + * \return 更新后的颜色值。 + */ +uint32_t cycleRGB(uint32_t color, GradientDirection *direction); + +/** + * 通过HSV颜色空间循环改变色调(Hue)以实现颜色渐变效果。 + * + * 此函数负责在HSV颜色模型中改变色调值,从而在不改变饱和度(Saturation)和亮度(Value)的情况下 + * 遍历不同的颜色。色调值会在0到359之间循环,每次调用函数色调值增加1,当达到359后重置为0。 + * 函数输出当前色调值并将新的RGB值存储在提供的缓冲区中。 + * + * \param buf 指向存储RGB值的缓冲区的指针。此缓冲区将被更新为对应的RGB值。 + * \param hue 指向当前色调值的指针。色调值在0到359之间变化。 + * + * \return 根据当前色调值、饱和度和亮度计算出的RGB颜色值。 + */ +uint32_t cycleHSV(uint32_t *hue); + +/** + * 将HSV颜色值转换为RGB颜色值。 + * + * 此函数接受HSV(色相、饱和度、亮度)颜色空间的值,并将其转换为RGB(红、绿、蓝)颜色空间的值。 + * 转换过程中,可能会执行有效性检查(取决于HSV_VALID_CHECK预处理器变量)。 + * + * \param hue 指向色相值的指针,色相值的范围通常是0-360。 + * \param sat 指向饱和度值的指针,饱和度值的范围通常是0-100。 + * \param value 指向亮度值的指针,亮度值的范围通常是0-100。 + * + * \return 转换后的RGB值,其中G占最高8位,R占中间8位,B占最低8位。 + */ +uint32_t HSV_to_RGB(uint32_t *hue, uint32_t *sat, uint32_t *value); + +/** + * 将单一颜色填充到整个RGB条中,并控制显示颜色的时间长度。 + * + * 此函数遍历RGB条的每个颜色单元,将它们统一设置为提供的颜色值。设置完成后, + * 通过调用输出函数将这些颜色输出到RGB条上。之后,函数会调用延迟函数以保持 + * 当前颜色一段时间,从而控制颜色显示的持续时间,这可以用于创建闪烁效果。 + * + * \param buf 指向存储RGB值的缓冲区的指针,每个元素代表RGB条中一个颜色单元的颜色值。 + * \param color 要填充的统一颜色值。 + */ +void fill_gradient(uint32_t *buf, uint32_t color); + + +/** + * 在tile[1]上启动一个永久循环,该循环会持续更新RGB灯条的颜色。 + * 它初始化一个颜色值,然后在一个无限循环中不断地调用fill_gradient和cycleRGB函数, + * 以实现RGB灯条颜色的渐变效果。颜色的变化方向会根据GradientDirection变量进行调整。 + */ +void cycleRGB_driver(); + +/** + * 驱动HSV颜色空间中的颜色循环,以实现连续的颜色渐变效果。 + * + * 此函数初始化颜色值,并进入一个无限循环,不断地计算新的颜色值并更新LED阵列。 + * 使用并发执行关键字 'par' 来实现循环内部的并行处理。这个函数假定运行环境支持并行关键字 'par'。 + * + * 在此循环中,它首先使用当前颜色填充一个预定义大小的缓冲区,然后调用 `cycleHSV` 函数 + * 来更新当前色相值并获取新的颜色。最后,它打印出当前的GRB颜色值。 + * + * 注意:此函数设计为在嵌入式系统或具有并行处理能力的系统上运行。 + * 它包含一个无限循环,应确保有适当的机制来安全地退出或中断执行。 + */ +void cycleHSV_driver(); + + +/** + * 用于测试HSV溢出 + */ +void HSV_to_RGB_TEST(); + +#endif // RGB_EFFECT_H \ No newline at end of file diff --git a/lib_rgb/module_build_info b/lib_rgb/module_build_info new file mode 100644 index 0000000..848991b --- /dev/null +++ b/lib_rgb/module_build_info @@ -0,0 +1,10 @@ +VERSION = 0.0.1 + +DEPENDENT_MODULES = + +MODULE_XCC_FLAGS = $(XCC_FLAGS) -g -O3 -Wall -Wextra -Werror + +EXPORT_INCLUDE_DIRS = api + +SOURCE_DIRS = src + diff --git a/lib_rgb/src/rgb_driver.xc b/lib_rgb/src/rgb_driver.xc new file mode 100644 index 0000000..6e635fa --- /dev/null +++ b/lib_rgb/src/rgb_driver.xc @@ -0,0 +1,79 @@ +#include // 包含对XCORE资源的操作 +#include // 包含对封装的定义,引用以使用 on tile[] 语法 +#include // 包含基本的输入输出函数 +#include +#include "xclib.h" +#include "stdint.h" + +// 如果灯的显示没有出现问题,不要修改这些宏 +#define MICROSECONDS 100 +#define RT23_RST_DELAY (MICROSECONDS * 200000) // 200 ms 当前没有使用,因为引脚通常自动拉低 +#define T0H_DELAY (33) // 0.3 μs, assuming MICROSECONDS is 100 times the actual microsecond count +#define T1H_DELAY (63) // 0.6 μs +#define T0L_DELAY (93) // 0.9 μs +#define T1L_DELAY (63) // 0.6 μs + + +on tile[1] : out port p_rgb_rgb = XS1_PORT_4A; // 注意:当前代码仅适用于4bit端口 +timer tmr; + +// 向4A3写时序,点亮RT23 +uint32_t output_bit_on_4th_pin(uint32_t bit, uint32_t fall_time) +{ + if (bit == 1) + { + p_rgb_rgb<:0xff; // 输出到4位端口 + tmr when timerafter(fall_time + T1H_DELAY):> fall_time; // 等待T1H时长 + // printf("[x]fall_time: %u\n", fall_time); + p_rgb_rgb<:0x00; // 将第4位设置为低电平 + tmr when timerafter(fall_time + T1L_DELAY):> fall_time; // 等待T1L时长 + // printf("[x]fall_time: %u\n", fall_time); + } + else if (bit == 0) + { + p_rgb_rgb<:0xff; // 输出到4位端口 + tmr when timerafter(fall_time + T0H_DELAY):> fall_time; // 等待T0H时长 + // printf("[x]fall_time: %u\n", fall_time); + p_rgb_rgb<:0x00; // 将第4位设置为低电平 + tmr when timerafter(fall_time + T0L_DELAY):> fall_time; // 等待T0L时长 + // printf("[x]fall_time: %u\n", fall_time); + } + else + { + printf("[x]ERROR, ILLEGAL INPUT\n"); + } + + return fall_time; +} + +// 串行输出24位值 +void output_24bit_value_serially(uint32_t value) +{ + uint32_t fall_time = 0; + tmr:> fall_time; + // // 重置 RT23, + // p_rgb_rgb <: 0x000000; + // tmr when timerafter(fall_time + RT23_RST_DELAY):> fall_time; + + value = value << 8; + value = bitrev(value); // 这里会占用时间。 + + // printf("[x]value: %u\n", value); + // Write a 24bit code + for (int i = 0; i < 24; i++) + { + uint32_t bit = (value >> i) & 0x1; // 获取当前位 + tmr:> fall_time; + fall_time = output_bit_on_4th_pin(bit, fall_time); // 通过第4位输出 + // printf("[x]fall_time: %u\n", fall_time); + } +} + +// 输出RGB值数组 +void output_rgb_array(uint32_t buf[], uint32_t num_rgbs) +{ + for (uint32_t rgb = 0; rgb < num_rgbs; ++rgb) + { + output_24bit_value_serially(buf[rgb]); + } +} diff --git a/lib_rgb/src/rgb_effect.xc b/lib_rgb/src/rgb_effect.xc new file mode 100644 index 0000000..96ac6a0 --- /dev/null +++ b/lib_rgb/src/rgb_effect.xc @@ -0,0 +1,265 @@ +#include // 包含对XCORE资源的操作 +#include "rgb_driver.h" +#include "xclib.h" +#include "timer.h" +#include +#include +#include + +// RGB灯的数量 +#ifndef NUM_RGBS +#define NUM_RGBS (12) +#endif + +// 控制RGB亮度的最大值,不超过255 +#ifndef RGB_MAX +#define RGB_MAX (10) +#endif + +// 开关饱和检查 +#ifndef HSV_VALID_CHECK +#define HSV_VALID_CHECK (0) +#endif + +// 控制HUE的最大值,不超过360° +#ifndef HSV_HUE_MAX +#define HSV_HUE_MAX (360) +#endif + +// 控制饱和度的最大值,不超过100 +#ifndef HSV_SATURATION_MAX +#define HSV_SATURATION_MAX (100) +#endif + +// 控制VALUE,不超过100 +#ifndef HSV_VALUE_MAX +#define HSV_VALUE_MAX (100) +#endif + +// 微秒,定义每次颜色更新的延迟,在cycleRGB下, +// (1000/RGB_MAX)代表每个B/R/G值的爬升/缓降时间约为1000ms +#ifndef DELAY_TIME_RGB +#define DELAY_TIME_RGB (1000 / RGB_MAX) +#endif + +// TODO: 当RGB_MAX等值超限时,raise error +// 定义一个枚举来表示渐变方向 +typedef enum +{ + INCREMENTING, // 亮度递增 + DECREMENTING // 亮度递减 +} GradientDirection; + + +// 检查HSV值是否在有效范围内,如果溢出则将值设为最大值,并打印报错 +void is_HSV_valid(uint32_t *hue, uint32_t *sat, uint32_t *value) +{ + if (*hue >= HSV_HUE_MAX) + { + printf("[x]hue overflow, current: %u\n", *hue); + *hue = HSV_HUE_MAX - 1; + } + if (*sat > HSV_SATURATION_MAX) + { + printf("[x]sat overflow, current: %u\n", *sat); + *sat = HSV_SATURATION_MAX; + } + if (*value > HSV_VALUE_MAX) + { + printf("[x]value overflow, current: %u\n", *value); + *value = HSV_VALUE_MAX; + } +} + +// 将HSV颜色值转换为RGB颜色值 +uint32_t HSV_to_RGB(uint32_t *hue, uint32_t *sat, uint32_t *value) +{ + +#ifdef HSV_VALID_CHECK + #if HSV_VALID_CHECK == 0 + (is_HSV_valid(hue, sat, value)); + #endif +#endif + + uint32_t g; // 现在G是最高8位 + uint32_t r; // 然后是R + uint32_t b; // B是最低8位 + + float H_prime = *hue / 60.0f; + float S_prime = *sat / 100.0f; + float V_prime = *value / 100.0f; + + int i = (int)(H_prime); + float f = H_prime - (float)i; + float p = V_prime * (1 - S_prime); + float q = V_prime * (1 - S_prime * f); + float t = V_prime * (1 - S_prime * (1 - f)); + + switch (i) + { + case 0: + r = (uint32_t)(V_prime * RGB_MAX); + g = (uint32_t)(t * RGB_MAX); + b = (uint32_t)(p * RGB_MAX); + break; + case 1: + r = (uint32_t)(q * RGB_MAX); + g = (uint32_t)(V_prime * RGB_MAX); + b = (uint32_t)(p * RGB_MAX); + break; + case 2: + r = (uint32_t)(p * RGB_MAX); + g = (uint32_t)(V_prime * RGB_MAX); + b = (uint32_t)(t * RGB_MAX); + break; + case 3: + r = (uint32_t)(p * RGB_MAX); + g = (uint32_t)(q * RGB_MAX); + b = (uint32_t)(V_prime * RGB_MAX); + break; + case 4: + r = (uint32_t)(t * RGB_MAX); + g = (uint32_t)(p * RGB_MAX); + b = (uint32_t)(V_prime * RGB_MAX); + break; + default: // for cases 5 and 6 + r = (uint32_t)(V_prime * RGB_MAX); + g = (uint32_t)(p * RGB_MAX); + b = (uint32_t)(q * RGB_MAX); + break; + } + + return (g << 16) | (r << 8) | b; +} + + +// 逐步遍历RGB颜色空间,实现呼吸灯效果 +uint32_t cycleRGB(uint32_t color, GradientDirection *direction) +{ + uint32_t g = (color >> 16) & 0xFF; // 现在G是最高8位 + uint32_t r = (color >> 8) & 0xFF; // 然后是R + uint32_t b = color & 0xFF; // B是最低8位 + + // 根据方向调整颜色值 + if (*direction == INCREMENTING) + { + if (b < RGB_MAX) + b++; + else if (r < RGB_MAX) + r++; + else if (g < RGB_MAX) + g++; + else + *direction = DECREMENTING; // 达到最亮,改变方向 + } + else + { // DECREMENTING + if (b > 0) + b--; + else if (r > 0) + r--; + else if (g > 0) + g--; + else + { + *direction = INCREMENTING; // 达到最暗,改变方向 + } + } + + return ((uint32_t)g << 16) | ((uint32_t)r << 8) | (uint32_t)b; +} + +// 通过HSV颜色空间循环改变色调(Hue)以实现颜色渐变效果 +uint32_t cycleHSV(uint32_t *hue) +{ + // Assuming sat and value should be initialized to 100 for full color + uint32_t sat = 100; + uint32_t value = 100; + if (*hue < 359) + { + (*hue) += 1; + printf("hue is: 0x%06X\n", *hue); + } + else + { + (*hue) = 0; + printf("--------hue is: 0x%06X----------\n", *hue); + } + return(HSV_to_RGB(hue, &sat, &value)); +} + +// 将单一颜色填充到整个RGB条中,并控制显示颜色的时间长度 +void fill_gradient(uint32_t *buf, uint32_t color) +{ + // 遍历缓冲区的每个元素,将其设置为提供的颜色值 + for (int i = 0; i < NUM_RGBS; i++) + { + buf[i] = color; + } + // 将缓冲区中的颜色数组输出到RGB条上 + output_rgb_array(buf, NUM_RGBS); + + // 调用延迟函数以控制颜色显示的时间,从而控制RGB条的闪烁速度 + delay_milliseconds(DELAY_TIME_RGB); +} + +// TODO:添加可合并选项 +// 驱动HSV颜色空间中的颜色循环,以实现连续的颜色渐变效果。 +void cycleHSV_driver() +{ + + 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 = HSV_to_RGB(¤t_hue, ¤t_sat, ¤t_val); + par // 使用par关键词并发执行下面的代码块,这些线程默认在tile[1]上运行 + { + while (1) + { + // 用当前渐变颜色填充RGB数组,然后发送给rgb阵列 + fill_gradient(buf, current_color); + + // 更改下一个颜色 + current_color = cycleHSV(¤t_hue); + + // 打印出当前的GRB颜色值 + // printf("GRB color is: 0x%06X\n", current_color); + } + } +} + +// 持续更新RGB灯条的颜色 +void cycleRGB_driver() +{ + + uint32_t buf[NUM_RGBS]; + uint32_t current_color = 0x000000; // Start from black + GradientDirection direction = INCREMENTING; // 开始时设置为递增亮度 + + par // 使用par关键词并发执行下面的代码块,这些线程默认在tile[1]上运行 + { + while (1) + { + // 用当前渐变颜色填充RGB数组 + fill_gradient(buf, current_color); + + // 更改下一个渐变的基色 + current_color = cycleRGB(current_color, &direction); + } + } +} + +// 测试 HSV_to_RGB,以及饱和处理 +void HSV_to_RGB_TEST() +{ + uint32_t hue, sat, value; // HSV值 + uint32_t color; // RGB值 + + // 测试转换 + hue = 999; + sat = 999; + value = 999; + color = HSV_to_RGB(&hue, &sat, &value); + printf("GRB color is: 0x%06X\n", color); +}