FastLED可以实现二维点阵LED的显示效果

[复制链接]
 楼主| keer_zu 发表于 2025-5-13 22:31 | 显示全部楼层 |阅读模式

FastLED 完全可以实现二维点阵(矩阵)LED的显示效果!虽然 FastLED 原生设计主要用于一维 LED 灯带控制,但通过合理的 坐标映射逻辑处理,可以轻松将一维灯带数据转换为二维矩阵的显示效果。以下是具体实现方法和示例:


1. 硬件连接与布局

二维点阵的 LED 通常以网格形式排列(如 8x8、16x16 等),常见连接方式有两种:

  • 蛇形排列(Snake Layout): LED 灯带在行间交替方向(例如,第一行从左到右,第二行从右到左),以缩短走线。
  • 逐行排列(Row-by-Row): 每行 LED 独立连接,方向一致。

需要根据实际硬件布局编写 坐标映射函数


2. 核心步骤

(1) 定义二维矩阵参数

#define MATRIX_WIDTH  16  // 矩阵宽度(列数)
#define MATRIX_HEIGHT 8   // 矩阵高度(行数)
#define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT) // LED总数
CRGB leds[NUM_LEDS];

(2) 坐标映射函数

将二维坐标 (x, y) 转换为一维 LED 索引。 示例代码(蛇形排列)

cpp

复制

下载

uint16_t XY(uint8_t x, uint8_t y) {
  if (y % 2 == 0) {
    // 偶数行:从左到右
    return y * MATRIX_WIDTH + x;
  } else {
    // 奇数行:从右到左
    return y * MATRIX_WIDTH + (MATRIX_WIDTH - 1 - x);
  }
}

(3) 控制二维点阵

通过 XY(x, y) 函数直接操作指定坐标的 LED:

// 在坐标 (3, 5) 显示红色
leds[XY(3, 5)] = CRGB::Red;

// 在坐标 (0, 0) 到 (4, 4) 绘制绿色方块
for (int x = 0; x < 5; x++) {
  for (int y = 0; y < 5; y++) {
    leds[XY(x, y)] = CRGB::Green;
  }
}

3. 示例效果实现

(1) 滚动文字/图案

通过偏移坐标实现水平或垂直滚动:

void loop() {
  static int offset = 0;
  for (int x = 0; x < MATRIX_WIDTH; x++) {
    for (int y = 0; y < MATRIX_HEIGHT; y++) {
      // 计算滚动后的坐标(水平滚动)
      int shiftedX = (x + offset) % MATRIX_WIDTH;
      // 根据图案显示颜色(示例:间隔点亮)
      leds[XY(shiftedX, y)] = (x % 2 == 0) ? CRGB::Blue : CRGB::Black;
    }
  }
  FastLED.show();
  offset++;
  delay(100);
}

(2) 动态波纹效果

结合二维坐标计算动态亮度:

void loop() {
  static uint8_t wave = 0;
  for (int x = 0; x < MATRIX_WIDTH; x++) {
    for (int y = 0; y < MATRIX_HEIGHT; y++) {
      // 计算距离中心的波纹强度
      float dx = x - MATRIX_WIDTH/2;
      float dy = y - MATRIX_HEIGHT/2;
      uint8_t brightness = 255 * (sin8(sqrt(dx*dx + dy*dy) + wave) / 255;
      leds[XY(x, y)] = CHSV(128, 255, brightness);
    }
  }
  FastLED.show();
  wave += 5;
  delay(30);
}

4. 高级技巧

(1) 使用二维数组缓存

为简化逻辑,可先将颜色数据存储在二维数组,再批量写入 LED:

CRGB buffer[MATRIX_WIDTH][MATRIX_HEIGHT];

// 更新缓冲区
buffer[3][2] = CRGB::Purple;

// 将缓冲区写入实际 LED
for (int x = 0; x < MATRIX_WIDTH; x++) {
  for (int y = 0; y < MATRIX_HEIGHT; y++) {
    leds[XY(x, y)] = buffer[x][y];
  }
}
FastLED.show();

(2) 优化性能

  • 并行刷新:如果使用多个 LED 控制器(如多个 WS2812B 灯带),可分割矩阵并并行驱动。
  • 颜色预计算:对动态效果预先计算颜色值,减少实时计算量。

5. 完整示例:8x8 矩阵显示彩虹波浪

#include <FastLED.h>
#define MATRIX_WIDTH  8
#define MATRIX_HEIGHT 8
#define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT)
CRGB leds[NUM_LEDS];

// 坐标映射(蛇形排列)
uint16_t XY(uint8_t x, uint8_t y) {
  return (y % 2 == 0) ? (y * MATRIX_WIDTH + x) : (y * MATRIX_WIDTH + (MATRIX_WIDTH - 1 - x));
}

void setup() {
  FastLED.addLeds<WS2812B, 6>(leds, NUM_LEDS);
}

void loop() {
  static uint8_t hue = 0;
  for (int x = 0; x < MATRIX_WIDTH; x++) {
    for (int y = 0; y < MATRIX_HEIGHT; y++) {
      // 根据坐标生成色相和明度波浪
      uint8_t ledHue = hue + x * 10 + y * 5;
      uint8_t brightness = sin8(x * 20 + y * 20 + hue);
      leds[XY(x, y)] = CHSV(ledHue, 255, brightness);
    }
  }
  FastLED.show();
  hue += 2;
  delay(20);
}

注意事项

  • 硬件布局:务必确认 LED 的物理排列方式(蛇形/逐行),否则坐标会错乱。
  • 性能限制:大型矩阵(如 32x32)可能因刷新率不足导致卡顿,需优化代码或使用更高性能控制器(如 ESP32)。

通过 FastLED 的灵活性和二维坐标映射,你可以轻松实现复杂的动态图案、游戏甚至低分辨率动画!

 楼主| keer_zu 发表于 2025-5-19 21:56 | 显示全部楼层
  1. static uint8_t wave = 0;
  2.   for (int x = 0; x < MATRIX_WIDTH; x++) {
  3.     for (int y = 0; y < MATRIX_HEIGHT; y++) {
  4.       // 计算距离中心的波纹强度
  5.       float dx = x - MATRIX_WIDTH/2;
  6.       float dy = y - MATRIX_HEIGHT/2;
  7.       uint8_t brightness = 255 * (sin8(sqrt(dx*dx + dy*dy) + wave) / 255);
  8.       leds[XY(x, y)] = CHSV(128, 255, brightness);
  9.     }
  10.   }
  11.   FastLED.show();
  12.   wave += 5;
  13.   delay(300);


 楼主| keer_zu 发表于 2025-5-20 11:07 | 显示全部楼层
彩红效果:

  1. static uint8_t hue = 0;
  2.   for (int x = 0; x < MATRIX_WIDTH; x++) {
  3.     for (int y = 0; y < MATRIX_HEIGHT; y++) {
  4.       // 根据坐标生成色相和明度波浪
  5.       uint8_t ledHue = hue + x * 10 + y * 5;
  6.       uint8_t brightness = sin8(x * 20 + y * 20 + hue);
  7.       leds[XY(x, y)] = CHSV(ledHue, 255, brightness);
  8.     }
  9.   }
  10.   FastLED.show();
  11.   hue += 2;
  12.   delay(20);


 楼主| keer_zu 发表于 2025-5-20 14:41 | 显示全部楼层
  1. #include <BluetoothSerial.h>
  2. #include <FastLED.h>
  3. #include <math.h>
  4. struct Polar { float radius; float angle_radians; };

  5. Polar cartesianToPolar(float x, float y) {
  6.     return {
  7.         sqrt(x*x + y*y),
  8.         atan2(y, x)
  9.     };
  10. }

  11. #define MATRIX_WIDTH  30  // 矩阵宽度(列数)
  12. #define MATRIX_HEIGHT 15   // 矩阵高度(行数)
  13. #define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT) // LED总数

  14. #define LED_PIN     15   // 数据线连接的GPIO引脚
  15. //#define NUM_LEDS    450  // LED数量
  16. #define BRIGHTNESS 100  // 亮度(0-255)
  17. CRGB leds[NUM_LEDS];
  18. CRGB red_c   = CRGB(255, 0, 0);    // 红色
  19. CRGB green_c   = CRGB(0, 255, 0);    // 绿色
  20. CRGB blue_c   = CRGB(0, 0, 255);    // 蓝色
  21. CRGB black_c   = CRGB(0, 0, 0);      // 黑色(关闭LED)
  22. CRGB white_c   = CRGB(255, 255, 255);// 白色(全亮度)

  23. CRGB yellow_c   = CRGB(255, 255, 0);  // 黄色
  24. CRGB qing_c   = CRGB(0, 255, 255);  // 青色
  25. CRGB pin_c   = CRGB(255, 0, 255);  // 品红
  26. CRGB cheng_c   = CRGB(255, 165, 0);  // 橙色
  27. CRGB zi_c   = CRGB(128, 0, 128);  // 紫色
  28. CRGB fen_c   = CRGB(255, 192, 203);// 粉色
  29. int flag=0;

  30. //===================================================
  31. // 定义主色和辅助色的HSV范围(H:0-255对应0-360度)
  32. const uint8_t MAIN_HUE = 0;     // 主色Hue(例如红色)
  33. const uint8_t ACCENT_HUE = 32;  // 辅助色Hue(例如橙色)
  34. const uint8_t HUE_RANGE = 16;   // 主辅色之间的过渡范围

  35. // 动态参数
  36. uint8_t baseBrightness = 128;   // 基础亮度
  37. uint8_t brightnessJitter = 50;  // 亮度波动范围
  38. uint8_t saturation = 200;       // 饱和度(0-255)
  39. uint8_t spreadRatio = 50;       // 主色占比(%)

  40. //===================================================

  41. #define FILL_LEDS(value) do { \
  42.     for (size_t i = 0; i < NUM_LEDS; ++i) { \
  43.         (leds)[i] = (value); \
  44.     } \
  45. } while(0)

  46. #if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
  47. #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
  48. #endif

  49. #if !defined(CONFIG_BT_SPP_ENABLED)
  50. #error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
  51. #endif

  52. uint16_t XY(uint8_t x, uint8_t y) {
  53.   return (y % 2 == 0) ? (y * MATRIX_WIDTH + x) : (y * MATRIX_WIDTH + (MATRIX_WIDTH - 1 - x));
  54. }

  55. BluetoothSerial SerialBT;
  56. #define BUFFER_SIZE 1024
  57. uint8_t buffer[BUFFER_SIZE];
  58. int write_idx = 0;
  59. int read_idx = 0;
  60. unsigned long total_bytes = 0;
  61. unsigned long last_time = 0;

  62. #define BT_DISCOVER_TIME 10000

  63. static bool btScanAsync = true;
  64. static bool btScanSync = true;

  65. void btAdvertisedDeviceFound(BTAdvertisedDevice *pDevice) {
  66.   Serial.printf("Found a device asynchronously: %s\n", pDevice->toString().c_str());
  67. }

  68. void setup() {
  69.   FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  70.   FastLED.setBrightness(BRIGHTNESS);
  71.   randomSeed(analogRead(0));    // 初始化随机种子
  72.   
  73.   Serial.begin(115200);
  74.   SerialBT.begin("ESP32-liuyan");  //Bluetooth device name
  75.   Serial.println("The device started, now you can pair it with bluetooth!");
  76.   // SerialBT.setMTU(1024);

  77.   if (btScanAsync) {
  78.     Serial.print("Starting asynchronous discovery... ");
  79.     if (SerialBT.discoverAsync(btAdvertisedDeviceFound)) {
  80.       Serial.println("Findings will be reported in "btAdvertisedDeviceFound"");
  81.       delay(10000);
  82.       Serial.print("Stopping discoverAsync... ");
  83.       SerialBT.discoverAsyncStop();
  84.       Serial.println("stopped");
  85.     } else {
  86.       Serial.println("Error on discoverAsync f.e. not working after a "connect"");
  87.     }
  88.   }

  89.   if (btScanSync) {
  90.     Serial.println("Starting synchronous discovery... ");
  91.     BTScanResults *pResults = SerialBT.discover(BT_DISCOVER_TIME);
  92.     if (pResults) {
  93.       pResults->dump(&Serial);
  94.     } else {
  95.       Serial.println("Error on BT Scan, no result!");
  96.     }
  97.   }
  98. }

  99. void fill_shape( struct CRGB * targetArray, int numToFill,
  100.                   uint8_t initialhue,
  101.                   uint8_t deltahue )
  102. {
  103.     CHSV hsv;
  104.     hsv.hue = initialhue;
  105.     hsv.val = 255;
  106.     hsv.sat = 240;
  107.     for( int i = 0; i < numToFill; ++i) {
  108.         targetArray[i] = hsv;
  109.         hsv.hue += deltahue;
  110.     }
  111. }

  112. void breath_light()
  113. {
  114. static uint8_t brightness = 0;
  115.   // 使用正弦波生成明度值(0-255)
  116.   brightness = beatsin8(10, 50, 255); // 参数:频率(Hz), 最小值, 最大值
  117.   fill_solid(leds, NUM_LEDS, CHSV(96, 255, brightness)); // 固定色相(如绿色)
  118.   FastLED.show();
  119. }

  120. void loop() {
  121. #if 0
  122.   int index;
  123.   static uint8_t hue = 0;
  124.     // 非阻塞读取蓝牙数据
  125.   while (SerialBT.available()) {
  126.     int bytes_to_read = SerialBT.available();
  127.     bytes_to_read = min(bytes_to_read, BUFFER_SIZE - write_idx);

  128.     // 写入缓冲区
  129.     if (bytes_to_read > 0) {
  130.       flag = 1;
  131.       SerialBT.readBytes(&buffer[write_idx], bytes_to_read);
  132.       if(buffer[write_idx] == 'r' || buffer[write_idx] == 'R'){
  133.         FILL_LEDS(red_c);
  134.       } else if(buffer[write_idx] == 'g' || buffer[write_idx] == 'G'){
  135.         FILL_LEDS(green_c);
  136.       } else if(buffer[write_idx] == 'b' || buffer[write_idx] == 'B'){
  137.         FILL_LEDS(blue_c);
  138.       } else if(buffer[write_idx] == 'w' || buffer[write_idx] == 'W'){
  139.         FILL_LEDS(white_c);
  140.       } else if(buffer[write_idx] == 'y' || buffer[write_idx] == 'Y'){
  141.         FILL_LEDS(yellow_c);
  142.       } else if(buffer[write_idx] == 's' || buffer[write_idx] == 'S'){
  143.         FILL_LEDS(black_c);
  144.         flag = 0;
  145.       } else if(buffer[write_idx] == 'q' || buffer[write_idx] == 'Q'){
  146.         FILL_LEDS(qing_c);
  147.       } else if(buffer[write_idx] == 'p' || buffer[write_idx] == 'P'){
  148.         FILL_LEDS(pin_c);
  149.       } else if(buffer[write_idx] == 'c' || buffer[write_idx] == 'C'){
  150.         FILL_LEDS(cheng_c);
  151.       } else if(buffer[write_idx] == 'z' || buffer[write_idx] == 'Z'){
  152.         FILL_LEDS(zi_c);
  153.       } else if(buffer[write_idx] == 'f' || buffer[write_idx] == 'F'){
  154.         FILL_LEDS(fen_c);
  155.       } else if(buffer[write_idx] == 'v' || buffer[write_idx] == 'V'){
  156.         FILL_LEDS(fen_c);
  157.       }
  158.       
  159.       FastLED.show();
  160.         
  161.       for(index = 0;index < bytes_to_read;index ++)
  162.       Serial.printf("%c",buffer[write_idx + index]);
  163.       write_idx = (write_idx + bytes_to_read) % BUFFER_SIZE;
  164.       total_bytes += bytes_to_read;
  165.     } else {
  166.       
  167.     }

  168.     // 缓冲区切换检查(防止覆盖未读数据)
  169.     if (write_idx >= BUFFER_SIZE / 2 && read_idx < BUFFER_SIZE / 2) {
  170.       read_idx = BUFFER_SIZE / 2;  // 切换到后半缓冲区
  171.     }
  172.   }

  173.   // 计算实时带宽
  174.   unsigned long current_time = millis();
  175.   if (current_time - last_time >= 1000) {
  176.     float rate = (total_bytes * 8) / 1000.0;  // 转换为Kbps
  177.     //Serial.printf("当前接收速率: %.2f Kbps\n", rate);
  178.     total_bytes = 0;
  179.     last_time = current_time;
  180.   }
  181.   
  182.   //if(!flag) {
  183.     fill_shape(leds, NUM_LEDS, hue++, 10);
  184.     FastLED.show();
  185.     //Serial.printf("%d\n",hue);
  186.     //delay(1000);
  187.     //FILL_LEDS(black_c);
  188.     //FastLED.show();
  189.     //delay(1000);
  190.     //delay(10);
  191.     //flag = !flag;
  192.   //}
  193. #else
  194. static uint8_t hue = 0;
  195.   for (int x = 0; x < MATRIX_WIDTH; x++) {
  196.     for (int y = 0; y < MATRIX_HEIGHT; y++) {
  197.       // 根据坐标生成色相和明度波浪
  198.       uint8_t ledHue = hue + x * 10 + y * 5;
  199.       uint8_t brightness = sin8(x * 20 + y * 20 + hue);
  200.       leds[XY(x, y)] = CHSV(ledHue, 255, brightness);
  201.     }
  202.   }
  203.   FastLED.show();
  204.   hue += 2;
  205.   delay(20);
  206. //breath_light();
  207. #endif
  208. }
 楼主| keer_zu 发表于 2025-5-20 19:12 | 显示全部楼层
  1. #if 1
  2. void optim_vision()
  3. {
  4. float global_brightness = breathe(20.0);  // 20秒呼吸周期
  5.   rotation_angle += ROTATION_SPEED * (millis() % 20) / 1000.0;
  6.   
  7.   for(int i=0; i<NUM_LEDS; i++) {
  8.     float r = led_r[i];
  9.     float theta = led_theta[i] + rotation_angle;
  10.    
  11.     // 添加角度扰动
  12.     theta += randomGaussian();
  13.    
  14.     CRGB color;
  15.     if(r < 0.15) {  // 核心层
  16.       float layerBrightness = 0.8 + 0.2 * sin(millis()/500.0);  // 动态亮度
  17.       color = colorBlend(coreColor1, coreColor2, layerBrightness);
  18.     }
  19.     else if(r < 0.4) {  // 过渡层
  20.       color = colorBlend(mainColor, coreColor2, 0.3);
  21.     }
  22.     else {  // 背景层
  23.       color = bgColor;
  24.     }
  25.    
  26.     // 应用全局亮度
  27.     color.fadeToBlackBy(255 * (1 - global_brightness));
  28.     leds[i] = color;
  29.   }
  30.   
  31.   FastLED.show();
  32.   FastLED.delay(20);  // 控制刷新率
  33. }
  34. #endif
 楼主| keer_zu 发表于 2025-5-20 19:14 | 显示全部楼层
  1. #include "led_functions.h"

  2. #define NOISE_STRENGTH 0.3   // 扰动强度

  3. CRGB leds[NUM_LEDS]; // 实际定义LED数组

  4. // 极坐标系统
  5. float led_r[NUM_LEDS];      // 半径(归一化 0-1)
  6. float led_theta[NUM_LEDS];  // 初始角度(弧度)
  7. float rotation_angle = 0;   // 当前旋转角度


  8. // 高斯噪声生成
  9. float randomGaussian() {
  10.   // 使用Box-Muller转换生成高斯分布
  11.   static float z0, z1;
  12.   static bool generate = false;
  13.   generate = !generate;
  14.   
  15.   if (!generate) return z1 * NOISE_STRENGTH;
  16.   
  17.   float u1, u2;
  18.   do {
  19.     u1 = random(1, 1000) / 1000.0;
  20.     u2 = random(1, 1000) / 1000.0;
  21.   } while (u1 <= 0.0001);
  22.   
  23.   z0 = sqrt(-2.0 * log(u1)) * cos(TWO_PI * u2);
  24.   z1 = sqrt(-2.0 * log(u1)) * sin(TWO_PI * u2);
  25.   return z0 * NOISE_STRENGTH;
  26. }

  27. // 呼吸效果生成器
  28. float breathe(float periodSeconds) {
  29.   static unsigned long lastUpdate;
  30.   float cycle = (millis() - lastUpdate) / (periodSeconds * 1000);
  31.   return (sin(cycle * TWO_PI) * 0.5 + 0.5);  // 输出0-1
  32. }

  33. // 极坐标初始化
  34. void initPolarCoords() {
  35.   // 假设LED排列在圆形区域(需要根据实际布局调整)
  36.   for(int i=0; i<NUM_LEDS; i++) {
  37.     // 转换为虚拟坐标(示例用圆形布局)
  38.     float x = (i % MATRIX_WIDTH) / MATRIX_WIDTH - 0.5;  // 假设50x10的布局
  39.     float y = (i / MATRIX_WIDTH) / MATRIX_HEIGHT - 0.5;
  40.    
  41.     led_r[i] = sqrt(x*x + y*y) * 2;    // 归一化半径
  42.     led_theta[i] = atan2(y, x);        // 初始角度
  43.   }
  44. }

  45. // 颜色混合函数
  46. CRGB colorBlend(CRGB color1, CRGB color2, float weight) {
  47.   return CRGB(
  48.     color1.r * (1-weight) + color2.r * weight,
  49.     color1.g * (1-weight) + color2.g * weight,
  50.     color1.b * (1-weight) + color2.b * weight
  51.   );
  52. }

  53. uint16_t XY(uint8_t x, uint8_t y)
  54. {
  55.   return (y % 2 == 0) ? (y * MATRIX_WIDTH + x) : (y * MATRIX_WIDTH + (MATRIX_WIDTH - 1 - x));
  56. }


  57. void leds_setup()
  58. {
  59.   FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  60.   FastLED.setBrightness(BRIGHTNESS);
  61.   initPolarCoords();
  62. }
 楼主| keer_zu 发表于 2025-5-24 00:48 | 显示全部楼层
显示“祝你生日快乐”

  1. #include <FastLED.h>

  2. #define LED_PIN     15
  3. #define COLOR_ORDER GRB
  4. #define CHIPSET     WS2815
  5. #define NUM_LEDS    450
  6. CRGB leds[NUM_LEDS];

  7. #define MATRIX_WIDTH  30
  8. #define MATRIX_HEIGHT 15

  9. #define BITMAP_WIDTH 96

  10. #define BITMAP_INDEX(x,y) ((14-y)*12 + (x/8) - 1)
  11. #define BITMMAP_POSITION(x) (x%8)


  12. // 颜色定义
  13. const CRGB BACKGROUND_COLOR = CRGB(0x0, 0x0, 0x100); //
  14. const CRGB TEXT_COLOR = CRGB(0xFF, 0x0, 0x00);       //

  15. // 点阵数据(已转换格式)
  16. /*96 x 15*/
  17. static const unsigned char textBitmap[] = {
  18.     0x33, 0xfc, 0x08, 0x80, 0x11, 0x00, 0x1f, 0xf0, 0x10, 0x40, 0x00, 0xf0,
  19.     0x13, 0xfc, 0x08, 0x80, 0x11, 0x00, 0x1f, 0xf0, 0x10, 0x40, 0x1f, 0xf0,
  20.     0xfa, 0x04, 0x19, 0xfe, 0x11, 0x00, 0x10, 0x10, 0x13, 0xf8, 0x1f, 0x00,
  21.     0xfa, 0x04, 0x11, 0xfe, 0x3f, 0xfc, 0x10, 0x10, 0x1b, 0xf8, 0x11, 0x00,
  22.     0x1a, 0x04, 0x33, 0x06, 0x3f, 0xfc, 0x10, 0x10, 0x5c, 0x48, 0x31, 0x00,
  23.     0x13, 0xfc, 0x36, 0x24, 0x61, 0x00, 0x10, 0x10, 0x54, 0x48, 0x21, 0x00,
  24.     0x3b, 0xfc, 0x74, 0x20, 0xc1, 0x00, 0x1f, 0xf0, 0x50, 0x48, 0x3f, 0xfc,
  25.     0x7c, 0x90, 0xd1, 0x28, 0x81, 0x00, 0x1f, 0xf0, 0xd7, 0xfe, 0x3f, 0xfc,
  26.     0xd4, 0x90, 0x91, 0x2c, 0x3f, 0xf8, 0x10, 0x10, 0x97, 0xfe, 0x09, 0x20,
  27.     0x94, 0x90, 0x13, 0x24, 0x3f, 0xf8, 0x10, 0x10, 0x10, 0xe0, 0x09, 0x30,
  28.     0x11, 0x92, 0x12, 0x26, 0x01, 0x00, 0x10, 0x10, 0x10, 0xa0, 0x19, 0x18,
  29.     0x11, 0x12, 0x16, 0x22, 0x01, 0x00, 0x10, 0x10, 0x11, 0xb0, 0x31, 0x0c,
  30.     0x13, 0x12, 0x14, 0x22, 0x01, 0x00, 0x10, 0x10, 0x11, 0x10, 0x61, 0x04,
  31.     0x16, 0x1e, 0x10, 0xa0, 0xff, 0xfe, 0x1f, 0xf0, 0x13, 0x18, 0x45, 0x04,
  32.     0x1c, 0x0e, 0x10, 0xe0, 0xff, 0xfe, 0x1f, 0xf0, 0x16, 0x0e, 0x07, 0x00
  33. };

  34. int scrollOffset = 0;

  35. // 蛇形布局坐标转换
  36. int getLedIndex(int x, int y) {
  37.   if (x < 0 || x >= MATRIX_WIDTH || y < 0 || y >= MATRIX_HEIGHT) return -1;
  38.   if (y % 2 == 0) return y * MATRIX_WIDTH + x;
  39.   else return y * MATRIX_WIDTH + (MATRIX_WIDTH - 1 - x);
  40. }

  41. void setup() {
  42.   FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
  43.   FastLED.setBrightness(50);
  44. }

  45. void loop() {
  46.   static unsigned long lastUpdate = 0;
  47.   if (millis() - lastUpdate > 100) {
  48.     lastUpdate = millis();
  49.    
  50.     fill_solid(leds, NUM_LEDS, BACKGROUND_COLOR);

  51.     for (int x = 0; x < MATRIX_WIDTH; x++) {
  52.       int bitmapX = (scrollOffset + x) % BITMAP_WIDTH;
  53.       for (int y = 0; y < MATRIX_HEIGHT; y++) {
  54.         if ((textBitmap[BITMAP_INDEX(bitmapX,y)] << BITMMAP_POSITION(bitmapX)) &0x80) {
  55.           int ledIndex = getLedIndex(x, y);
  56.           if (ledIndex != -1) leds[ledIndex] = TEXT_COLOR;
  57.         }
  58.       }
  59.     }

  60.     FastLED.show();
  61.     scrollOffset = (scrollOffset + 1) % BITMAP_WIDTH;
  62.   }
  63. }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:qq群:49734243 Email:zukeqiang@gmail.com

1477

主题

12909

帖子

55

粉丝
快速回复 在线客服 返回列表 返回顶部