HSV颜色空间转RGB(C语言代码),ESP32使用RMT驱动WS2812B,七彩流光灯光效果

HSV(Hue, Saturation, Value) 模型中,颜色的参数分别是:色调(H)饱和度(S)明度(V)。它更类似于人类感觉颜色的方式,颜色?深浅?明暗?通过这种方式可以很直观的改变渲染效果。

在这里插入图片描述

RGB在生活最为常用,显示屏RGB-LED等发光显示器件,最后都会用RGB的方式去表现。但RGB在使用过程中却有许多麻烦,例如明明两种颜色相近,但RGB的参数有时却天差地别。并且更改RGB参数时很容易影响亮度。

1. 计算机应用中的HSV色轮

HSV表达颜色有3个参数:

  • 色调(Hue):单位°,范围0~360。(负责调整颜色,0°-红色,120°-绿色,240°-蓝色,以此类推)
  • 饱和度(Saturation):单位%,范围0~100。(饱和度高,颜色深而艳;饱和度低,颜色浅而发白)
  • 明度(Value):单位%,范围0~100。(控制明暗,明度越高直观感受亮度越亮,越低亮度越低甚至发黑)

注意:HSV(色调(H)饱和度(S)明度(V))有别于HSL(色调(H)饱和度(S)亮度(L)
在这里插入图片描述

2. Hue色调

通常在编写代码中,饱和度明度大多不是重点,一般直接拉到最高,或者保持一个固定的值。时常需要变动的是Hue色调,也就是直观的颜色。用 0~360°来表示各种颜色。
在这里插入图片描述
在这里插入图片描述

3. HSV转RGB(C语言代码)

ESP32完整工程:easyio库 中的Demo - 20_RMT_1WIRE_WS2812B

下面这段代码摘自乐鑫ESP32的SDK-Demo led_strip,简洁易用。
不足的地方是输入输出都是整形,如需浮点,请自行将里面的参数都改为floatdouble

/**
 * @brief 将HSV颜色空间转换为RGB颜色空间
 *      - 因为HSV使用起来更加直观、方便,所以代码逻辑部分使用HSV。但WS2812B RGB-LED灯珠的驱动使用的是RGB,所以需要转换。
 * 
 * @param  h HSV颜色空间的H:色调。单位°,范围0~360。(Hue 调整颜色,0°-红色,120°-绿色,240°-蓝色,以此类推)
 * @param  s HSV颜色空间的S:饱和度。单位%,范围0~100。(Saturation 饱和度高,颜色深而艳;饱和度低,颜色浅而发白)
 * @param  v HSV颜色空间的V:明度。单位%,范围0~100。(Value 控制明暗,明度越高亮度越亮,越低亮度越低)
 * @param  r RGB-R值的指针
 * @param  g RGB-G值的指针
 * @param  b RGB-B值的指针
 *
 * Wiki: https://en.wikipedia.org/wiki/HSL_and_HSV
 *
 */
void led_strip_hsv2rgb(uint32_t h, uint32_t s, uint32_t v, uint32_t *r, uint32_t *g, uint32_t *b)
{
    h %= 360; // h -> [0,360]
    uint32_t rgb_max = v * 2.55f;
    uint32_t rgb_min = rgb_max * (100 - s) / 100.0f;

    uint32_t i = h / 60;
    uint32_t diff = h % 60;

    // RGB adjustment amount by hue
    uint32_t rgb_adj = (rgb_max - rgb_min) * diff / 60;

    switch (i) {
    case 0:
        *r = rgb_max;
        *g = rgb_min + rgb_adj;
        *b = rgb_min;
        break;
    case 1:
        *r = rgb_max - rgb_adj;
        *g = rgb_max;
        *b = rgb_min;
        break;
    case 2:
        *r = rgb_min;
        *g = rgb_max;
        *b = rgb_min + rgb_adj;
        break;
    case 3:
        *r = rgb_min;
        *g = rgb_max - rgb_adj;
        *b = rgb_max;
        break;
    case 4:
        *r = rgb_min + rgb_adj;
        *g = rgb_min;
        *b = rgb_max;
        break;
    default:
        *r = rgb_max;
        *g = rgb_min;
        *b = rgb_max - rgb_adj;
        break;
    }
}

4. 七彩流光灯光效果

ESP32完整工程代码:easyio库 中的Demo - 20_RMT_1WIRE_WS2812B
easyio的使用介绍:ESP32开源驱动库Easyio的使用
在这里插入图片描述



ESP32开发板开源计划


  现已开源一款ESP32物联网开发板,支持WIFI、蓝牙、以太网、RS485、CAN通信。板载6轴IMU、温湿度传感器、38K红外遥控收/发、独立RTC、TF卡座。USB和18650双电源供电,有2.0寸单点电容屏可用,配套各外设驱动和LVGL源码。Github、立创EDA、CSDN全云端同步更新。

  详情可见:

打样免费的时代,速去JLC白嫖PCB。

开源学习交流Q群:827686418
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 10
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
好的,以下是基于STM32单片机控制WS2812实现10种灯光效果代码,仅供参考: ``` #include "stm32f10x.h" /*********** WS2812灯带控制IO口配置 ***********/ #define WS2812_GPIO_PORT GPIOB #define WS2812_GPIO_PIN GPIO_Pin_0 /*********** WS2812灯带控制参数配置 ***********/ #define LED_NUM 10 // 灯珠数量 #define COLOR_NUM 3 // 颜色数量 #define LED_TOTAL (LED_NUM * COLOR_NUM) // 灯总数 #define RESET_TIME 300 // 重置时间(单位:us) /*********** 颜色定义 ***********/ #define RED 0xFF0000 // 红色 #define GREEN 0x00FF00 // 绿色 #define BLUE 0x0000FF // 蓝色 #define YELLOW 0xFFFF00 // 黄色 #define MAGENTA 0xFF00FF // 品红 #define CYAN 0x00FFFF // 青色 #define WHITE 0xFFFFFF // 白色 #define BLACK 0x000000 // 黑色 /*********** 函数声明 ***********/ void delay_us(uint32_t us); void WS2812_SendData(uint32_t data); void WS2812_SendColor(uint32_t color); void WS2812_SendDataArray(uint32_t *array, uint16_t len); void WS2812_SetAllColor(uint32_t color); void WS2812_Rainbow(); void WS2812_FadeInOut(uint32_t c, uint8_t wait); void WS2812_TheaterChaseRainbow(uint8_t wait); void WS2812_RainbowCycle(uint8_t wait); void WS2812_TheaterChase(uint32_t c, uint8_t wait); /*********** 主函数 ***********/ int main(void) { uint32_t color; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 使能GPIOB时钟 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = WS2812_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(WS2812_GPIO_PORT, &GPIO_InitStructure); // 配置GPIO口 while (1) { WS2812_SetAllColor(RED); // 灯带全亮红色 delay_us(RESET_TIME); // 重置时间 WS2812_SetAllColor(GREEN); // 灯带全亮绿色 delay_us(RESET_TIME); // 重置时间 WS2812_SetAllColor(BLUE); // 灯带全亮蓝色 delay_us(RESET_TIME); // 重置时间 color = YELLOW; WS2812_FadeInOut(color, 50); // 呼吸黄色 WS2812_FadeInOut(color, 50); WS2812_FadeInOut(color, 50); WS2812_Rainbow(); // 彩虹效果 color = CYAN; WS2812_TheaterChase(color, 50); // 彩虹跑道 color = MAGENTA; WS2812_TheaterChase(color, 50); color = YELLOW; WS2812_TheaterChase(color, 50); WS2812_RainbowCycle(20); // 彩虹循环 WS2812_TheaterChaseRainbow(50); // 彩虹跑道 } } /*********** 延时函数 ***********/ void delay_us(uint32_t us) { while(us--) { __NOP(); __NOP(); } } /*********** 发送数据函数 ***********/ void WS2812_SendData(uint32_t data) { uint8_t i; for(i = 0; i < 24; i++) { if(data & 0x800000) { WS2812_GPIO_PORT->BSRR = WS2812_GPIO_PIN; delay_us(0.7); WS2812_GPIO_PORT->BRR = WS2812_GPIO_PIN; delay_us(0.6); } else { WS2812_GPIO_PORT->BSRR = WS2812_GPIO_PIN; delay_us(0.35); WS2812_GPIO_PORT->BRR = WS2812_GPIO_PIN; delay_us(0.8); } data <<= 1; } } /*********** 发送颜色函数 ***********/ void WS2812_SendColor(uint32_t color) { uint8_t i; for(i = 0; i < 8; i++) { if(color & 0x80) { WS2812_GPIO_PORT->BSRR = WS2812_GPIO_PIN; delay_us(0.7); WS2812_GPIO_PORT->BRR = WS2812_GPIO_PIN; delay_us(0.6); } else { WS2812_GPIO_PORT->BSRR = WS2812_GPIO_PIN; delay_us(0.35); WS2812_GPIO_PORT->BRR = WS2812_GPIO_PIN; delay_us(0.8); } color <<= 1; } } /*********** 发送数据数组函数 ***********/ void WS2812_SendDataArray(uint32_t *array, uint16_t len) { uint16_t i; for(i = 0; i < len; i++) { WS2812_SendColor(array[i]); } } /*********** 设置所有灯珠颜色函数 ***********/ void WS2812_SetAllColor(uint32_t color) { uint32_t array[LED_TOTAL]; uint16_t i; for(i = 0; i < LED_NUM; i++) { array[i * COLOR_NUM] = color; array[i * COLOR_NUM + 1] = color; array[i * COLOR_NUM + 2] = color; } WS2812_SendDataArray(array, LED_TOTAL); } /*********** 彩虹效果函数 ***********/ void WS2812_Rainbow() { uint32_t array[LED_TOTAL]; uint16_t i, j; uint8_t r, g, b; for(j = 0; j < 256; j++) // hue { for(i = 0; i < LED_NUM; i++) { HsvToRgb(j, 255, 255, &r, &g, &b); array[i * COLOR_NUM] = (uint32_t)g << 16 | (uint32_t)r << 8 | b; HsvToRgb(j + 128, 255, 255, &r, &g, &b); array[i * COLOR_NUM + 1] = (uint32_t)g << 16 | (uint32_t)r << 8 | b; HsvToRgb(j + 64, 255, 255, &r, &g, &b); array[i * COLOR_NUM + 2] = (uint32_t)g << 16 | (uint32_t)r << 8 | b; } WS2812_SendDataArray(array, LED_TOTAL); delay_us(20000); } } /*********** 呼吸效果函数 ***********/ void WS2812_FadeInOut(uint32_t c, uint8_t wait) { uint8_t r, g, b; uint16_t i, j; for(j = 0; j < 256; j++) { r = (c & 0xFF0000) >> 16; g = (c & 0x00FF00) >> 8; b = (c & 0x0000FF); for(i = 0; i < LED_NUM; i++) { WS2812_SendColor(((uint32_t)r * j / 255) << 16 | ((uint32_t)g * j / 255) << 8 | ((uint32_t)b * j / 255)); } delay_us(wait * 1000 / 256); } for(j = 255; j > 0; j--) { r = (c & 0xFF0000) >> 16; g = (c & 0x00FF00) >> 8; b = (c & 0x0000FF); for(i = 0; i < LED_NUM; i++) { WS2812_SendColor(((uint32_t)r * j / 255) << 16 | ((uint32_t)g * j / 255) << 8 | ((uint32_t)b * j / 255)); } delay_us(wait * 1000 / 256); } } /*********** 彩虹跑道函数 ***********/ void WS2812_TheaterChaseRainbow(uint8_t wait) { uint32_t array[LED_TOTAL]; uint16_t i, j; uint8_t r, g, b; for(j = 0; j < 256; j++) // hue { for(i = 0; i < LED_NUM; i += 3) { HsvToRgb(j, 255, 255, &r, &g, &b); array[i] = (uint32_t)g << 16 | (uint32_t)r << 8 | b; HsvToRgb(j + 128, 255, 255, &r, &g, &b); array[i + 1] = (uint32_t)g << 16 | (uint32_t)r << 8 | b; HsvToRgb(j + 64, 255, 255, &r, &g, &b); array[i + 2] = (uint32_t)g << 16 | (uint32_t)r << 8 | b; } WS2812_SendDataArray(array, LED_TOTAL); delay_us(wait * 1000); } } /*********** 彩虹循环函数 ***********/ void WS2812_RainbowCycle(uint8_t wait) { uint32_t array[LED_TOTAL]; uint16_t i, j; uint8_t r, g, b; for(j = 0; j < 256 * 5; j++) // 5 cycles of all colors on wheel { for(i = 0; i < LED_NUM; i++) { HsvToRgb(((i * 256 / LED_NUM) + j) & 255, 255, 255, &r, &g, &b); array[i * COLOR_NUM] = (uint32_t)g << 16 | (uint32_t)r << 8 | b; HsvToRgb(((i * 256 / LED_NUM) + j + 128) & 255, 255, 255, &r, &g, &b); array[i * COLOR_NUM + 1] = (uint32_t)g << 16 | (uint32_t)r << 8 | b; HsvToRgb(((i * 256 / LED_NUM) + j + 64) & 255, 255, 255, &r, &g, &b); array[i * COLOR_NUM + 2] = (uint32_t)g << 16 | (uint32_t)r << 8 | b; } WS2812_SendDataArray(array, LED_TOTAL); delay_us(wait * 1000); } } /*********** 彩虹跑道函数 ***********/ void WS2812_TheaterChase(uint32_t c, uint8_t wait) { uint32_t array[LED_TOTAL]; uint16_t i, j; for(j = 0; j < 10; j++) // do 10 cycles of chasing { for(i = 0; i < LED_NUM; i += 3) { array[i * COLOR_NUM] = c; array[i * COLOR_NUM + 1] = c; array[i * COLOR_NUM + 2] = c; } WS2812_SendDataArray(array, LED_TOTAL); delay_us(wait * 1000); for(i = 0; i < LED_NUM; i += 3) { array[i * COLOR_NUM] = 0; array[i * COLOR_NUM + 1] = 0; array[i * COLOR_NUM + 2] = 0; } WS2812_SendDataArray(array, LED_TOTAL); } } /*********** HSVRGB函数 ***********/ void HsvToRgb(uint16_t h, uint8_t s, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b) { uint8_t region, remainder, p, q, t; if(s == 0) { *r = v; *g = v; *b = v; return; } region = h / 43; remainder = (h - (region * 43)) * 6; p = (v * (255 - s)) >> 8; q = (v * (255 - ((s * remainder) >> 8))) >> 8; t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8; switch(region) { case 0: *r = v; *g = t; *b = p; break; case 1: *r = q; *g = v; *b = p; break; case 2: *r = p; *g = v; *b = t; break; case 3: *r = p; *g = q; *b = v; break; case 4: *r = t; *g = p; *b = v; break; default: *r = v; *g = p; *b = q; break; } } ``` 由于代码较长,注释也比较详细,这里就不做过多解释了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值