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

相关文章

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

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

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

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

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

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

开题报告中的研究方法设计:AI能帮你做什么?

AIPaperGPT,论文写作神器~ https://www.aipapergpt.com/ 大家都准备开题报告了吗?研究方法部分是不是已经让你头疼到抓狂? 别急,这可是大多数人都会遇到的难题!尤其是研究方法设计这一块,选定性还是定量,怎么搞才能符合老师的要求? 每次到这儿,头脑一片空白。 好消息是,现在AI工具火得一塌糊涂,比如ChatGPT,居然能帮你在研究方法这块儿上出点主意。是不

研究人员在RSA大会上演示利用恶意JPEG图片入侵企业内网

安全研究人员Marcus Murray在正在旧金山举行的RSA大会上公布了一种利用恶意JPEG图片入侵企业网络内部Windows服务器的新方法。  攻击流程及漏洞分析 最近,安全专家兼渗透测试员Marcus Murray发现了一种利用恶意JPEG图片来攻击Windows服务器的新方法,利用该方法还可以在目标网络中进行特权提升。几天前,在旧金山举行的RSA大会上,该Marcus现场展示了攻击流程,

Science Robotics 首尔国立大学研究团队推出BBEX外骨骼,实现多维力量支持!

重复性举起物体可能会对脊柱和背部肌肉造成损伤,由此引发的腰椎损伤是工业环境等工作场所中一个普遍且令人关注的问题。为了减轻这类伤害,有研究人员已经研发出在举起任务中为工人提供辅助的背部支撑装置。然而,现有的这类装置通常无法在非对称性的举重过程中提供多维度的力量支持。此外,针对整个人体脊柱的设备安全性验证也一直是一个缺失的环节。 据探索前沿科技边界,传递前沿科技成果的X-robot投稿,来自首尔国立

代码随想录训练营day37|52. 携带研究材料,518.零钱兑换II,377. 组合总和 Ⅳ,70. 爬楼梯

52. 携带研究材料 这是一个完全背包问题,就是每个物品可以无限放。 在一维滚动数组的时候规定了遍历顺序是要从后往前的,就是因为不能多次放物体。 所以这里能多次放物体只需要把遍历顺序改改就好了 # include<iostream># include<vector>using namespace std;int main(){int n,m;cin>>n>>m;std::vector<i

【Godot4.3】多边形的斜线填充效果基础实现

概述 图案(Pattern)填充是一个非常常见的效果。其中又以斜线填充最为简单。本篇就探讨在Godot4.3中如何使用Geometry2D和CanvasItem的绘图函数实现斜线填充效果。 基础思路 Geometry2D类提供了多边形和多边形以及多边形与折线的布尔运算。按照自然的思路,多边形的斜线填充应该属于“多边形与折线的布尔运算”范畴。 第一个问题是如何获得斜线,这条斜线应该满足什么样

UniApp实现漂亮的音乐歌词滚动播放效果

在现代的音乐播放应用中,歌词的展示和滚动播放已经成为了一个非常常见的功能。今天,我们将通过UniApp来实现一个漂亮的歌词滚动播放功能。我们将使用UniApp提供的组件和API来完成这个任务。 页面结构 在页面的模板部分,我们需要创建一个音频播放器和歌词展示区域。使用<scroll-view>组件来实现歌词的滚动效果。 <template><view class="audio-co