ws2812b效果研究之一 cylon

2024-08-30 21:28
文章标签 效果 研究 ws2812b cylon

本文主要是介绍ws2812b效果研究之一 cylon,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

效果

  • ws2812b效果研究之一 cylon
    • 简单的版本(跑马灯)
    • 好看的版本(梦幻)

ws2812b效果研究之一 cylon

名字来源于经典科幻系列《太空堡垒卡拉狄加》中机器人的眼部扫描效果。这个效果通常表现为灯光在LED灯带上来回移动,像一只眼睛在扫描一样。其实感觉就是流水灯的效果
平台是atmega 2560,三个引脚分别是vcc,gnd和信号引脚
对应于arduino中的fastled库中的cylon例子

简单的版本(跑马灯)

#include <FastLED.h>#define NUM_LEDS 100      // LED灯数量
#define DATA_PIN 2       // 连接到LED数据引脚的Arduino引脚CRGB leds[NUM_LEDS];     // 定义LED数组void setup() {//FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);  // 初始化LED灯带FastLED.addLeds<WS2812,DATA_PIN,RGB>(leds,NUM_LEDS);
}void loop() {cylonEffect(255, 0, 0, 10);  // 红色的Cylon效果,亮度255,延时50ms
}void cylonEffect(uint8_t r, uint8_t g, uint8_t b, uint8_t wait) {// 从左到右逐个点亮LEDfor (int i = 2; i < NUM_LEDS-2; i++) {leds[i-2] = CRGB(r/3, g, b);leds[i-1] = CRGB(r/2, g, b);leds[i] = CRGB(r, g, b);  // 设置当前LED的颜色leds[i+1] = CRGB(r/2, g, b);leds[i+2] = CRGB(r/3, g, b);FastLED.show();           // 更新显示delay(wait);              // 延时以控制移动速度leds[i-2] = CRGB(0, 0, 0);leds[i-1] = CRGB(0, 0, 0);leds[i] = CRGB(0, 0, 0);  // 关闭当前LED以实现“流动”效果leds[i+1] = CRGB(0, 0, 0);leds[i+2] = CRGB(0, 0, 0);}
#if 1// 从右到左逐个点亮LEDfor (int i = NUM_LEDS - 1; i >= 0; i--) {leds[i] = CRGB(r, g, b);FastLED.show();delay(wait);leds[i] = CRGB(0, 0, 0);}#endif
}

上述其实可以实现两个效果,如果单程那就是“发射”或者“流水”,如果加上反向那就是“循环”或者“震动”

好看的版本(梦幻)


/// @file    Cylon.ino
/// @brief   实现一个单个LED来回移动的动画效果(Larson扫描器效果)
/// @example Cylon.ino#include <FastLED.h>  // 包含FastLED库,用于控制LED灯带// 定义灯带上的LED数量
#define NUM_LEDS 108 // 定义数据引脚(DATA_PIN)和时钟引脚(CLOCK_PIN)
// 对于像WS2812这样的LED芯片,只需要定义DATA_PIN;
// 如果使用SPI协议的LED芯片(如LPD8806),还需要定义CLOCK_PIN。
#define DATA_PIN 2
#define CLOCK_PIN 13  // 这里CLOCK_PIN不适用于WS2812,但定义在此方便解释// 定义LED数组,用于存储灯带中每个LED的颜色状态
CRGB leds[NUM_LEDS];void setup() { // 初始化LED灯带// 使用FastLED库中的addLeds函数来设置灯带类型(WS2812)、数据引脚(DATA_PIN)和颜色顺序(RGB)FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS);// 设置灯带的亮度,范围为0到255,这里设置为最大亮度255FastLED.setBrightness(255);
}// 定义一个函数fadeall,用于逐渐减弱所有LED的亮度,产生淡出效果
void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250);  // 使用nscale8函数将LED亮度缩放到原亮度的250/255} 
}void loop() { static uint8_t hue = 0;  // 定义一个静态变量hue,表示色调值(0到255),用于控制颜色变化// 第一部分:LED从左到右逐个点亮for(int i = 0; i < NUM_LEDS; i++) {// 设置第i个LED的颜色为当前色调hue(使用HSV颜色空间),并将色调值hue递增// CHSV函数的参数依次为色调(hue)、饱和度(255)、亮度(255)leds[i] = CHSV(hue++, 255, 255);// 更新LED显示,将颜色数据发送到灯带FastLED.show(); // 将所有LED的亮度逐渐减弱,形成淡出效果fadeall();// 延时10毫秒,用于控制LED移动的速度delay(10);}// 第二部分:LED从右到左逐个点亮for(int i = NUM_LEDS - 1; i >= 0; i--) {// 设置第i个LED的颜色为当前色调hue(使用HSV颜色空间),并将色调值hue递增leds[i] = CHSV(hue++, 255, 255);(此处通过算数符号重载,将CHSV类转换成了RGB然后给到了leds[i],注意leds[i]的数据类型为CRGB类)// 更新LED显示,将颜色数据发送到灯带FastLED.show();// 将所有LED的亮度逐渐减弱,形成淡出效果fadeall();// 延时10毫秒,用于控制LED移动的速度delay(10);}
}

这个效果算法的核心是:每次通过hsv色彩空间点亮下一个灯,注意灯的hue值增加,这样的话,可以使得每个灯的颜色变化没那么突然,然后把所有的灯的亮度都降低(其实只处理当前点亮的灯可以节省一些处理时间,算法才是最优的)

算法逻辑再次解释:
处理第i个灯数据最高亮度,饱和度增加,也就是CHSV(hue++, 255, 255);
发送亮灯命令,使其亮灯。
所有灯的亮度均降低一些(缩放到原亮度的250/255)此处并不会再次发送命令让其亮,待到下次循环处理下一个灯的饱和度时候才会再次亮灯。

这里提供一个hsv转rgb的参考函数

#include <stdint.h>void hsv_to_rgb(uint8_t hue, uint8_t saturation, uint8_t value, uint8_t* red, uint8_t* green, uint8_t* blue) {uint8_t region, remainder, p, q, t;if (saturation == 0) {// 如果饱和度为0,颜色为灰色(无色),即 R = G = B = V*red = value;*green = value;*blue = value;return;}// 计算色调所在的区域(色环被分为6个区域)region = hue / 43;remainder = (hue - (region * 43)) * 6;// 计算中间值p = (value * (255 - saturation)) >> 8;q = (value * (255 - ((saturation * remainder) >> 8))) >> 8;t = (value * (255 - ((saturation * (255 - remainder)) >> 8))) >> 8;// 根据当前的色调区域,计算最终的 RGB 值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;}
}

后续考虑到这个函数使用极其频繁, 于是乎考虑到使用内嵌汇编和查找表进行函数优化

#include <stdint.h>// 函数原型
void hsv_to_rgb(uint8_t hue, uint8_t saturation, uint8_t value, uint8_t* red, uint8_t* green, uint8_t* blue);// 查找表定义:每个条目包含三个字段,分别是 RGB 通道的分配顺序
const uint8_t lookup_table[6][3] = {{0, 1, 2}, // case 0: red = value, green = t, blue = p{1, 0, 2}, // case 1: red = q, green = value, blue = p{2, 0, 1}, // case 2: red = p, green = value, blue = t{2, 1, 0}, // case 3: red = p, green = q, blue = value{1, 2, 0}, // case 4: red = t, green = p, blue = value{0, 2, 1}  // case default: red = value, green = p, blue = q
};void hsv_to_rgb(uint8_t hue, uint8_t saturation, uint8_t value, uint8_t* red, uint8_t* green, uint8_t* blue) {uint8_t region, remainder, p, q, t;// 优化:直接用位移操作代替除法region = hue >> 5;  // hue / 32 (接近于原始代码中的 hue / 43)remainder = (hue & 31) << 3;  // hue % 32 * 8,原始 remainder 计算优化// 计算中间值p = (value * (255 - saturation)) >> 8;// 使用内嵌汇编优化 q 和 t 的计算__asm__ volatile ("mul %[temp1], %[sat], %[rem]\n\t" // temp1 = saturation * remainder"mul %[temp2], %[sat], %[comp_rem]\n\t" // temp2 = saturation * (255 - remainder)"rsb %[temp3], %[value], #255\n\t" // temp3 = 255 - value"mla %[q], %[temp1], %[temp3], %[value]\n\t" // q = value - (temp1 * temp3) / 256"mla %[t], %[temp2], %[temp3], %[value]\n\t" // t = value - (temp2 * temp3) / 256: [q] "=r" (q), [t] "=r" (t): [value] "r" (value), [sat] "r" (saturation), [rem] "r" (remainder), [comp_rem] "r" (255 - remainder): "cc", "memory");// 从查找表中获取 RGB 分量的分配顺序const uint8_t* lookup = lookup_table[region];uint8_t rgb[3];rgb[lookup[0]] = value;rgb[lookup[1]] = t;rgb[lookup[2]] = p;*red = rgb[0];*green = rgb[1];*blue = rgb[2];
}

那么大体上这个效果相关的技术细节就都处理完成了。后续将其移植到stm32上面去。

这篇关于ws2812b效果研究之一 cylon的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1121972

相关文章

Vue项目的甘特图组件之dhtmlx-gantt使用教程和实现效果展示(推荐)

《Vue项目的甘特图组件之dhtmlx-gantt使用教程和实现效果展示(推荐)》文章介绍了如何使用dhtmlx-gantt组件来实现公司的甘特图需求,并提供了一个简单的Vue组件示例,文章还分享了一... 目录一、首先 npm 安装插件二、创建一个vue组件三、业务页面内 引用自定义组件:四、dhtmlx

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

关于Java内存访问重排序的研究

《关于Java内存访问重排序的研究》文章主要介绍了重排序现象及其在多线程编程中的影响,包括内存可见性问题和Java内存模型中对重排序的规则... 目录什么是重排序重排序图解重排序实验as-if-serial语义内存访问重排序与内存可见性内存访问重排序与Java内存模型重排序示意表内存屏障内存屏障示意表Int

基于Python实现PDF动画翻页效果的阅读器

《基于Python实现PDF动画翻页效果的阅读器》在这篇博客中,我们将深入分析一个基于wxPython实现的PDF阅读器程序,该程序支持加载PDF文件并显示页面内容,同时支持页面切换动画效果,文中有详... 目录全部代码代码结构初始化 UI 界面加载 PDF 文件显示 PDF 页面页面切换动画运行效果总结主

React实现原生APP切换效果

《React实现原生APP切换效果》最近需要使用Hybrid的方式开发一个APP,交互和原生APP相似并且需要IM通信,本文给大家介绍了使用React实现原生APP切换效果,文中通过代码示例讲解的非常... 目录背景需求概览技术栈实现步骤根据 react-router-dom 文档配置好路由添加过渡动画使用

使用Python实现生命之轮Wheel of life效果

《使用Python实现生命之轮Wheeloflife效果》生命之轮Wheeloflife这一概念最初由SuccessMotivation®Institute,Inc.的创始人PaulJ.Meyer... 最近看一个生命之轮的视频,让我们珍惜时间,因为一生是有限的。使用python创建生命倒计时图表,珍惜时间

防近视护眼台灯什么牌子好?五款防近视效果好的护眼台灯推荐

在家里,灯具是属于离不开的家具,每个大大小小的地方都需要的照亮,所以一盏好灯是必不可少的,每个发挥着作用。而护眼台灯就起了一个保护眼睛,预防近视的作用。可以保护我们在学习,阅读的时候提供一个合适的光线环境,保护我们的眼睛。防近视护眼台灯什么牌子好?那我们怎么选择一个优秀的护眼台灯也是很重要,才能起到最大的护眼效果。下面五款防近视效果好的护眼台灯推荐: 一:六个推荐防近视效果好的护眼台灯的

一种改进的red5集群方案的应用、基于Red5服务器集群负载均衡调度算法研究

转自: 一种改进的red5集群方案的应用: http://wenku.baidu.com/link?url=jYQ1wNwHVBqJ-5XCYq0PRligp6Y5q6BYXyISUsF56My8DP8dc9CZ4pZvpPz1abxJn8fojMrL0IyfmMHStpvkotqC1RWlRMGnzVL1X4IPOa_  基于Red5服务器集群负载均衡调度算法研究 http://ww

生信圆桌x生信分析平台:助力生物信息学研究的综合工具

介绍 少走弯路,高效分析;了解生信云,访问 【生信圆桌x生信专用云服务器】 : www.tebteb.cc 生物信息学的迅速发展催生了众多生信分析平台,这些平台通过集成各种生物信息学工具和算法,极大地简化了数据处理和分析流程,使研究人员能够更高效地从海量生物数据中提取有价值的信息。这些平台通常具备友好的用户界面和强大的计算能力,支持不同类型的生物数据分析,如基因组、转录组、蛋白质组等。