[开发板与模块] 【ESK32-30519 + ESK32-21001测评】+SPI驱动WS2812B

[复制链接]
 楼主| 袁胜富 发表于 2022-9-13 19:04 | 显示全部楼层 |阅读模式
<
本帖最后由 eltonchang2001 于 2022-11-9 13:53 编辑

一、概述     

      最近得到合泰的HT32F54253开发板,恰好手里有一个WS2812B的RGB灯模块,那就点灯吧。一开始决定用SPI+PDMA的方式点亮的,奈何加了PDMA后代码跑死了,一直看手册和官方别的PMDA例程也没得到解决,索性不发SPI+PDMA驱动WS2812B,那就发一个不带PDMA的吧。

二、WS2812B的理论学习

    数据传输时间
   数据传输时间.png
   时序和级联使用
    数据表示.png
     数据传输方法和数据组成
    传输方式.png       通过以上图片和参考数据手册得知,WS2812B的数据传输速率是800KHZ。1s/800KHZ=1.25us。WS2812B有VCC、GND、DIN,DOUT四个引脚,数据从DIN流入从DOUT流出,使用多颗灯的时候需要以级联的方式使用。WS2812B由RGB三原色的比例可以显示很多中颜色。其一包数据由24bit构成,绿色(Green)占8位,红色(Red)占8位,蓝色(Blue)占8位,要显示要想显示的颜色只需要改变R、G、B值。其中G排最高位,R中间,B最低位。

三、HT32F54253的SPI知识和如何驱动ws2812B讲解

   本次实验选择的是SPI0,由于只用到发送引脚,我只初始化了MOSI引脚(PA5),PA5要使用复用功能5才能作为SPI0的MOSI功能。用过芯片的用户手册查得SPI0外设挂载时钟总线AHB频率为60MHZ,经过8分频后为7.5MHZ给SPI0使用。由于分频之后SPI0的工作频率为7.5MHZ,所在SPI0在发送1bit数据就得花费1s/7.5MHZ≈133ns,经过计算发送一字节数据就得花费8*133ns=1.06us.从WS2812B资料中得知,266ns的0码高电平时间符合,800ns的1码高电平时间也符合。所以SPI在8分频的情况下发送8位数据,其中2位用来代表0码的高电平时间,6位用来表示1码的高电平时间。通过这样的模拟,成功点亮了WS2812B。
四、代码实践

      头文件
  1. #ifndef __SPI_DMA_WS2812_H
  2. #define __SPI_DMA_WS2812_H

  3. #include "ht32.h"
  4. #include "ht32_board.h"
  5. #include "stdint.h"
  6. #include "bsp_sys.h"

  7. /*
  8. 要将系统时钟设置为60M,SPI分频数设置为8,则SPI的通信频率为7.5M,1s/7.5≈133ns 即传输一位数据的时间约为55纳秒(ns)8*133 =1.06us 符合WS2812

  9. 2*133 = 266ns   6*133 = 799ns  符合WS281X芯片的通信时序。

  10. 1111 1100high level  (十六进制:0XFC)表示WS281X的1码

  11. 1100 0000  low level   (十六进制:0XC0)表示WS281X的0码
  12. 程序头文件部分: 通过宏的方式定义了灯珠个数和WS281X的0码和1码。
  13. */

  14. //  _____   

  15. // |     |___|    1111 1100 high level

  16. //  ___         

  17. // |   |_____|   1111 0000   low level


  18. #define Delay_ms(wait)  delay_ms(wait)

  19. #define WS2812B   //选择WS2812B
  20. #define PIXEL_NUM1  2     //RGB灯的数量                                         //灯带1灯数(组数)
  21. #define PIXEL_NUM2  2                                                          //灯带2灯数(组数)
  22. #define PIXEL_NUM3  2                                                          //灯带3灯数(组数)
  23. #define PIXEL_NUM4  2                                                          //灯带4灯数(组数)

  24. #define PIXEL_NUM  (PIXEL_NUM1+PIXEL_NUM2+PIXEL_NUM3+PIXEL_NUM4)//灯数统计
  25. #define GRB  24   //3*8 //Red8位 Green8位 Blue8位 加起来24位

  26. #ifdef WS2812B
  27. #define WS_HIGH 0xFC
  28. #endif
  29. #define WS_LOW  0xC0
  30. /*   
  31.       R      G      B
  32. 红: 255     0      0
  33. 黄: 255    255     0
  34. 绿:  0     255     0
  35. 青:  0     255    255
  36. 蓝:  0      0     255
  37. 紫: 255     0     255
  38. 白: 255    255    255
  39. */

  40. typedef union _rgbPixelBuffer
  41. {
  42.     struct
  43.     {
  44.                         uint8_t PixelBuffer1[PIXEL_NUM1][GRB];
  45.                         uint8_t PixelBuffer2[PIXEL_NUM2][GRB];
  46.                         uint8_t PixelBuffer3[PIXEL_NUM3][GRB];
  47.                         uint8_t PixelBuffer4[PIXEL_NUM4][GRB];
  48.     }buff;
  49.     uint8_t All_Buffer[PIXEL_NUM][GRB];
  50.                 uint8_t Buffer[PIXEL_NUM*GRB];
  51. }RGB_PixelBuffer,*PRGB_PixelBuffer;



  52. void WS281x_Init(void);
  53. void WS281x_CloseAll(void);
  54. uint32_t WS281x_Color(uint8_t red, uint8_t green, uint8_t blue);
  55. void WS281x_SetPixelColor(uint16_t n, uint32_t GRBColor);
  56. void WS281x_SetPixelRGB(uint16_t n ,uint8_t red, uint8_t green, uint8_t blue);
  57. void WS281x_Show(void);

  58. void WS281x_RainbowCycle(uint8_t wait);
  59. void WS281x_TheaterChase(uint32_t c, uint8_t wait);
  60. void WS281x_ColorWipe(uint32_t c, uint8_t wait);
  61. void WS281x_Rainbow(uint8_t wait);
  62. void WS281x_TheaterChaseRainbow(uint8_t wait);


  63. void RGB_DEBUG_TEST(void);
  64. #endif













源文件,由于没有调通PDMA,故代码中屏蔽了PDMA部分代码
  1. #include "spi_dma_ws2812.h"
  2. #include "string.h"
  3. RGB_PixelBuffer pixelBuffer;
  4. uint32_t SPI_clock;
  5.         
  6. void WS281x_Init(void)
  7. {
  8.   SPI_InitTypeDef  SPI_InitStructure;
  9. //  PDMACH_InitTypeDef PDMACH_InitStructure;
  10.   CKCU_PeripClockConfig_TypeDef CKCUClock = {{0}};
  11.   CKCUClock.Bit.SPI0   = 1;//打开SPI0的时钟
  12.   CKCUClock.Bit.PA     = 1;//打开GPIOA的时钟
  13.   CKCUClock.Bit.AFIO   = 1;//打开复用时钟
  14. //        CKCUClock.Bit.PDMA   = 1;//外设DMA时钟
  15.   CKCU_PeripClockConfig(CKCUClock, ENABLE);//使能
  16.         AFIO_GPxConfig(GPIO_PA,AFIO_PIN_5,AFIO_MODE_5);//GPIOA 的PA5复用为SPI0的MOSI
  17.   /* Configure the GPIO pin*/
  18.   GPIO_PullResistorConfig(HT_GPIOA, GPIO_PIN_5, GPIO_PR_DOWN);//配置下拉
  19.   GPIO_DriveConfig(HT_GPIOA, GPIO_PIN_5,GPIO_DV_4MA);
  20.   GPIO_DirectionConfig(HT_GPIOA, GPIO_PIN_5, GPIO_DIR_OUT);
  21.         
  22. //        PDMACH_InitStructure.PDMACH_DstAddr = (uint32_t)&HT_SPI0->DR;
  23. //        PDMACH_InitStructure.PDMACH_SrcAddr = (uint32_t)&pixelBuffer;
  24. //        PDMACH_InitStructure.PDMACH_AdrMod  = SRC_ADR_LIN_INC  | DST_ADR_FIX;
  25. //        PDMACH_InitStructure.PDMACH_DataSize = WIDTH_8BIT;
  26. //        PDMACH_InitStructure.PDMACH_Priority =  VH_PRIO;
  27. //        PDMACH_InitStructure.PDMACH_BlkCnt   =  1;
  28. //        PDMACH_InitStructure.PDMACH_BlkLen   =  24;
  29. //        PDMA_Config(PDMA_CH1, &PDMACH_InitStructure);
  30. //        PDMA_EnaCmd(PDMA_CH1, ENABLE);
  31. //        PDMA_ClearFlag(PDMA_CH1, PDMA_FLAG_TC | PDMA_INT_GE);
  32. //        PDMA_IntConfig(PDMA_CH1, (PDMA_INT_GE | PDMA_INT_TC), ENABLE);

  33.   /*  SPI Configuration*/
  34.         SPI_DeInit(HT_SPI0);
  35.   SPI_InitStructure.SPI_Mode = SPI_MASTER;
  36.   SPI_InitStructure.SPI_FIFO = SPI_FIFO_DISABLE;
  37.   SPI_InitStructure.SPI_DataLength = SPI_DATALENGTH_8;
  38.   SPI_InitStructure.SPI_SELMode = SPI_SEL_SOFTWARE;
  39.   SPI_InitStructure.SPI_SELPolarity = SPI_SELPOLARITY_HIGH;
  40.   SPI_InitStructure.SPI_FirstBit = SPI_FIRSTBIT_MSB;
  41.   SPI_InitStructure.SPI_CPOL = SPI_CPOL_HIGH;
  42.   SPI_InitStructure.SPI_CPHA = SPI_CPHA_SECOND;
  43.   SPI_InitStructure.SPI_TxFIFOTriggerLevel = 0;
  44.   SPI_InitStructure.SPI_ClockPrescaler = 8;
  45.   SPI_Init(HT_SPI0, &SPI_InitStructure);
  46.         SPI_SoftwareSELCmd(HT_SPI0,SPI_SEL_ACTIVE);
  47. //        SPI_PDMACmd(HT_SPI0,SPI_PDMAREQ_TX,ENABLE);
  48.         SPI_Cmd(HT_SPI0,ENABLE);
  49.         WS281x_CloseAll();  //关闭全部的灯

  50.   delay_ms(100); //关闭全部的灯需要一定的时间  
  51.         
  52. }

  53. //uint16_t dATA;
  54. //更新颜色显示(在设定颜色后将颜色数据存入缓存只有执行该函数后才会进行显示)
  55. void WS281x_Show(void)
  56. {
  57. //        //关闭通道 才能重新写入传输值
  58. //  PDMA_EnaCmd(PDMA_CH1, DISABLE);
  59. //        SPI_Cmd(HT_SPI0,DISABLE);
  60. //        PDMA_TranSizeConfig(PDMA_CH1,1,24);
  61. //  //开启通道
  62. //        SPI_Cmd(HT_SPI0,ENABLE);
  63. //  PDMA_EnaCmd(PDMA_CH1, ENABLE);
  64. //        PDMA_SwTrigCmd(PDMA_CH1, ENABLE);
  65. //        SPI_SoftwareSELCmd(HT_SPI0,SPI_SEL_ACTIVE);
  66. //  while (PDMA_GetFlagStatus(PDMA_CH1, PDMA_FLAG_TC) != SET);
  67. //  PDMA_ClearFlag(PDMA_CH1, PDMA_FLAG_GE|PDMA_FLAG_TC);
  68. //        dATA=SPI_ReceiveData(HT_SPI0);
  69.         int i = 0,k=0;
  70. //        for(i=0;i<PIXEL_NUM;i++)
  71. //        {
  72. //                for(j=0;j<GRB;j++)
  73. //                {
  74. //                        SPI_SendData(HT_SPI0,(u32)pixelBuffer.All_Buffer[i][j]);
  75. //                        for(k=0;k<10;k++)
  76. //                        {
  77. //                                __NOP();
  78. //                        }
  79. //                }
  80. //        }
  81.         for(i=0;i<PIXEL_NUM*GRB;i++)
  82.         {
  83.                 SPI_SendData(HT_SPI0,(u32)pixelBuffer.Buffer[i]);
  84.                 for(k=0;k<10;k++)
  85.                 {
  86.                         __NOP();
  87.                 }
  88.         }
  89.         
  90. }
  91. //配置完成之后便可以构思底层控制函数了,为了方便多个LED灯珠的可控制首先要定义一个缓冲区pixelBuffer[PIXEL_NUM][24]\
  92. 通过设定颜色将数据填入缓冲区再通过更新函数将数据传入到LED灯珠上。
  93. //关闭所有灯珠
  94. void WS281x_CloseAll(void)
  95. {
  96.   uint16_t i;
  97.   uint8_t j;
  98.   
  99.   for(i = 0; i < PIXEL_NUM; ++i)
  100.   {
  101.     for(j = 0; j < GRB; ++j)
  102.     {
  103.       pixelBuffer.All_Buffer[i][j] = WS_LOW;
  104.     }
  105.   }
  106.   WS281x_Show();
  107. }


  108. uint32_t WS281x_Color(uint8_t red, uint8_t green, uint8_t blue)
  109. {
  110.   return green << 16 | red << 8 | blue;
  111. }

  112. void WS281x_SetPixelColor(uint16_t n, uint32_t GRBColor)
  113. {
  114.   uint8_t i;
  115.   if(n < PIXEL_NUM)
  116.   {
  117.     for(i = 0; i < GRB; i++)
  118.     {
  119.       pixelBuffer.All_Buffer[n][i] = ((GRBColor << i) & 0x800000) ? WS_HIGH : WS_LOW;
  120.     }
  121.   }
  122. }

  123. void WS281x_SetPixelRGB(uint16_t n ,uint8_t red, uint8_t green, uint8_t blue)
  124. {
  125.   uint8_t i;
  126.   
  127.   if(n < PIXEL_NUM)
  128.   {
  129.     for(i = 0; i < GRB; ++i)
  130.     {
  131.       pixelBuffer.All_Buffer[n][i] = (((WS281x_Color(red,green,blue) << i) & 0X800000) ? WS_HIGH : WS_LOW);
  132.     }
  133.   }
  134. }

  135. // Input a value 0 to 255 to get a color value.
  136. // The colours are a transition r - g - b - back to r.
  137. uint32_t WS281x_Wheel(uint8_t wheelPos) {
  138.   wheelPos = 255 - wheelPos;
  139.   if(wheelPos < 85) {
  140.     return WS281x_Color(255 - wheelPos * 3, 0, wheelPos * 3);
  141.   }
  142.   if(wheelPos < 170) {
  143.     wheelPos -= 85;
  144.     return WS281x_Color(0, wheelPos * 3, 255 - wheelPos * 3);
  145.   }
  146.   wheelPos -= 170;
  147.   return WS281x_Color(wheelPos * 3, 255 - wheelPos * 3, 0);
  148. }

  149. // Fill the dots one after the other with a color
  150. void WS281x_ColorWipe(uint32_t c, uint8_t wait) {
  151.   for(uint16_t i=0; i<PIXEL_NUM; i++) {
  152.     WS281x_SetPixelColor(i, c);
  153.     WS281x_Show();
  154.     Delay_ms(wait);
  155.   }
  156. }

  157. void WS281x_Rainbow(uint8_t wait) {
  158.   uint16_t i, j;

  159.   for(j=0; j<256; j++) {
  160.     for(i=0; i<PIXEL_NUM; i++) {
  161.       WS281x_SetPixelColor(i, WS281x_Wheel((i+j) & 255));
  162.     }
  163.     WS281x_Show();
  164.     Delay_ms(wait);
  165.   }
  166. }

  167. // Slightly different, this makes the rainbow equally distributed throughout
  168. void WS281x_RainbowCycle(uint8_t wait) {
  169.   uint16_t i, j;

  170.   for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
  171.     for(i=0; i< PIXEL_NUM; i++) {
  172.       WS281x_SetPixelColor(i,WS281x_Wheel(((i * 256 / PIXEL_NUM) + j) & 255));
  173.     }
  174.     WS281x_Show();
  175.     Delay_ms(wait);
  176.   }
  177. }

  178. //Theatre-style crawling lights.
  179. void WS281x_TheaterChase(uint32_t c, uint8_t wait) {
  180.   for (int j=0; j<10; j++) {  //do 10 cycles of chasing
  181.     for (int q=0; q < 3; q++) {
  182.       for (uint16_t i=0; i < PIXEL_NUM; i=i+3) {
  183.         WS281x_SetPixelColor(i+q, c);    //turn every third pixel on
  184.       }
  185.       WS281x_Show();

  186.       Delay_ms(wait);

  187.       for (uint16_t i=0; i < PIXEL_NUM; i=i+3) {
  188.         WS281x_SetPixelColor(i+q, 0);        //turn every third pixel off
  189.       }
  190.     }
  191.   }
  192. }

  193. //Theatre-style crawling lights with rainbow effect
  194. void WS281x_TheaterChaseRainbow(uint8_t wait) {
  195.   for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
  196.     for (int q=0; q < 3; q++) {
  197.       for (uint16_t i=0; i < PIXEL_NUM; i=i+3) {
  198.         WS281x_SetPixelColor(i+q, WS281x_Wheel( (i+j) % 255));    //turn every third pixel on
  199.       }
  200.       WS281x_Show();

  201.       Delay_ms(wait);

  202.       for (uint16_t i=0; i < PIXEL_NUM; i=i+3) {
  203.         WS281x_SetPixelColor(i+q, 0);        //turn every third pixel off
  204.       }
  205.     }
  206.   }
  207. }


  208. // Slightly different, this makes the rainbow equally distributed throughout
  209. void WS2812_RainbowRotate(uint16_t wait) {
  210.         uint16_t i, j;

  211.         for (j = 0; j < 256 * 5; j++) { // 5 cycles of all colors on wheel
  212.                 for (i = 0; i < PIXEL_NUM; i++) {
  213.                         WS281x_SetPixelColor(i,  WS281x_Wheel(((i * 256 / PIXEL_NUM) + j) & 255));
  214.                 }
  215.                 WS281x_Show();
  216.     Delay_ms(wait);
  217.         }
  218. }
  219. //hsv和rgb互相转
  220. float retmax(float a, float b, float c)                            //求最大值
  221. {
  222.         float max = 0;
  223.         max = a;
  224.         if (max < b)
  225.                 max = b;
  226.         if (max < c)
  227.                 max = c;
  228.         return max;
  229. }
  230. float retmin(float a, float b, float c)                            //求最小值
  231. {
  232.         float min = 0;
  233.         min = a;
  234.         if (min > b)
  235.                 min = b;
  236.         if (min > c)
  237.                 min = c;
  238.         return min;
  239. }
  240. //R,G,B参数传入范围(0~100)
  241. //转换结果h(0~360),s(0~100),v(0~100)
  242. void rgb_to_hsv(uint16_t *H, uint16_t *S, uint16_t *V, uint8_t r, uint8_t g, uint8_t b) {
  243.         float max = 0, min = 0;
  244.         float R = (float)r;
  245.         float G = (float)g;
  246.         float B = (float)b;
  247.         float h, s, v;

  248.         R = R / 255.0;
  249.         G = G / 255.0;
  250.         B = B / 255.0;

  251.         max = retmax(R, G, B);
  252.         min = retmin(R, G, B);
  253.         v = max;
  254.         if (max == 0)
  255.                 s = 0;
  256.         else
  257.                 s = 1 - (min / max);

  258.         if (max == min)
  259.                 h = 0;
  260.         else if (max == R && G >= B)
  261.                 h = 60 * ((G - B) / (max - min));
  262.         else if (max == R && G < B)
  263.                 h = 60 * ((G - B) / (max - min)) + 360;
  264.         else if (max == G)
  265.                 h = 60 * ((B - R) / (max - min)) + 120;
  266.         else if (max == B)
  267.                 h = 60 * ((R - G) / (max - min)) + 240;

  268.         v = v * 100;
  269.         s = s * 100;

  270.         *H = (int) h;
  271.         *S = (int) s;
  272.         *V = (int) v;
  273. }

  274. //参数入参范围h(0~360),s(0~100),v(0~100),这里要注意,要把s,v缩放到0~1之间
  275. //转换结果R(0~100),G(0~100),B(0~100),如需转换到0~255,只需把后面的乘100改成乘255
  276. void hsv_to_rgb(int h, int s, int v, uint8_t *r, uint8_t *g, uint8_t *b) {
  277.         float C = 0, X = 0, Y = 0, Z = 0;
  278.         int i = 0;
  279.         float H = (float) (h);
  280.         float S = (float) (s) / 100.0;
  281.         float V = (float) (v) / 100.0;
  282.         float R, G, B;
  283.         if (S == 0)
  284.                 R = G = B = V;
  285.         else {
  286.                 H = H / 60;
  287.                 i = (int) H;
  288.                 C = H - i;

  289.                 X = V * (1 - S);
  290.                 Y = V * (1 - S * C);
  291.                 Z = V * (1 - S * (1 - C));
  292.                 switch (i) {
  293.                 case 0:
  294.                         R = V;
  295.                         G = Z;
  296.                         B = X;
  297.                         break;
  298.                 case 1:
  299.                         R = Y;
  300.                         G = V;
  301.                         B = X;
  302.                         break;
  303.                 case 2:
  304.                         R = X;
  305.                         G = V;
  306.                         B = Z;
  307.                         break;
  308.                 case 3:
  309.                         R = X;
  310.                         G = Y;
  311.                         B = V;
  312.                         break;
  313.                 case 4:
  314.                         R = Z;
  315.                         G = X;
  316.                         B = V;
  317.                         break;
  318.                 case 5:
  319.                         R = V;
  320.                         G = X;
  321.                         B = Y;
  322.                         break;
  323.                 }
  324.         }
  325.         R = R * 255;
  326.         G = G * 255;
  327.         B = B * 255;
  328.         *r = (int) R;
  329.         *g = (int) G;
  330.         *b = (int) B;
  331. }




  332. void RGB_DEBUG_TEST(void)
  333. {
  334.         int i,j;
  335.         for(i=0;i<3;i++)
  336.         {
  337.                
  338.                 for(j=0;j<8;j++)
  339.                 {
  340.                         if(i==0)
  341.                         {
  342.                                 WS281x_ColorWipe(WS281x_Color(255, 0, 255), 10); // Red
  343.                         }
  344.                         else if(i==1)
  345.                         {
  346.                                 WS281x_ColorWipe(WS281x_Color(0, 255, 255), 10); // Green
  347.                         }
  348.                         else
  349.                         {
  350.                                 WS281x_ColorWipe(WS281x_Color(255, 255, 0), 10); // Blue
  351.                         }
  352.                 }
  353.         }
  354.                 for(i=0;i<3;i++)
  355.         {
  356.                
  357.                 for(j=0;j<8;j++)
  358.                 {
  359.                         if(i==0)
  360.                         {
  361.                                 WS281x_ColorWipe(WS281x_Color(255, 0, 0), 10); // Red
  362.                         }
  363.                         else if(i==1)
  364.                         {
  365.                                 WS281x_ColorWipe(WS281x_Color(0, 255, 0), 10); // Green
  366.                         }
  367.                         else
  368.                         {
  369.                                 WS281x_ColorWipe(WS281x_Color(0, 0, 255), 10); // Blue
  370.                         }
  371.                 }
  372.         }
  373.                 for(i=0;i<3;i++)
  374.         {
  375.                
  376.                 for(j=0;j<8;j++)
  377.                 {
  378.                         if(i==0)
  379.                         {
  380.                                 WS281x_ColorWipe(WS281x_Color(255, 0, 0), 10); // Red
  381.                                 Delay_ms(100);
  382.                                 WS281x_ColorWipe(WS281x_Color(0, 255, 0), 10); // Green
  383.                         }
  384.                         else if(i==1)
  385.                         {
  386.                                 WS281x_ColorWipe(WS281x_Color(0, 255, 0), 10); // Green
  387.                                 Delay_ms(100);
  388.                                 WS281x_ColorWipe(WS281x_Color(255, 0, 0), 10); // Red
  389.                         }
  390.                         else
  391.                         {
  392.                                 WS281x_ColorWipe(WS281x_Color(0, 0, 255), 10); // Blue
  393.                                 Delay_ms(100);
  394.                                 WS281x_ColorWipe(WS281x_Color(0, 255, 0), 10); // Green
  395.                                 Delay_ms(100);
  396.                                 WS281x_ColorWipe(WS281x_Color(0, 0, 255), 10); // Blue
  397.                                 Delay_ms(100);
  398.                                 WS281x_ColorWipe(WS281x_Color(255, 0, 0), 10); // Red
  399.                         }
  400.                 }
  401.         }
  402.         WS2812_RainbowRotate(2);
  403.         // Some example procedures showing how to display to the pixels:
  404.         WS281x_ColorWipe(WS281x_Color(255, 0, 0), 10); // Red
  405.         WS281x_ColorWipe(WS281x_Color(0, 255, 0), 10); // Green
  406.         WS281x_ColorWipe(WS281x_Color(0, 0, 255), 10); // Blue


  407.         WS281x_TheaterChase(WS281x_Color(127, 127, 127), 10); // White
  408.         WS281x_TheaterChase(WS281x_Color(127, 0, 0), 10); // Red
  409.         WS281x_TheaterChase(WS281x_Color(0, 0, 127), 10); // Blue

  410.         WS281x_Rainbow(10);
  411.         WS281x_RainbowCycle(10);
  412.         WS281x_TheaterChaseRainbow(10);
  413.         WS281x_CloseAll();

  414. }

五、实物效果展示



效果展示.jpg





51xlf 发表于 2023-1-5 11:14 | 显示全部楼层
spi+dma的形式驱动的。              
plsbackup 发表于 2023-1-5 11:42 | 显示全部楼层
这个对电流的要求很大吗?              
kkzz 发表于 2023-1-5 17:43 | 显示全部楼层
直接定时器延时就能实现的吧。              
jimmhu 发表于 2023-1-6 15:21 | 显示全部楼层
不使用dma,那就是得占用非常多的时间了?
robincotton 发表于 2023-1-6 19:16 | 显示全部楼层
这个可以驱动多少个ws2812呢
wwppd 发表于 2023-2-5 13:13 | 显示全部楼层
用WS2812制作的灯带控制程序非常实用
sheflynn 发表于 2023-2-5 14:11 | 显示全部楼层
通过硬件SPI的可以很巧妙的模拟出WS2812的通信时序,用spi的8位数据模拟ws281x的一位数据。
nomomy 发表于 2023-2-6 12:42 | 显示全部楼层
通过配置SPI的8个时钟周期满足WS2812B所需要的1位所占用的时间
lihuami 发表于 2023-2-7 20:00 | 显示全部楼层
使用的方法是PWM+DMA传输,也有SPI和直接延时等方法
sanfuzi 发表于 2023-2-7 20:12 | 显示全部楼层
怎么操作WS2812B彩灯实现模块的多显示呢?
mickit 发表于 2023-2-7 20:23 | 显示全部楼层
ws2812和ws2812b能混用吗
jackcat 发表于 2023-2-7 20:29 | 显示全部楼层
直接使用IO口进行电平反转要方便  
cashrwood 发表于 2023-2-7 20:40 | 显示全部楼层
驱动ws2812的时候一般采用PWM或者SPI的方式
deliahouse887 发表于 2023-2-7 21:38 | 显示全部楼层
WS2812通信速度为1M比较合适,不会造成乱码,通信很稳定。
sesefadou 发表于 2023-2-7 21:47 | 显示全部楼层
WS2812B是个好东西,在很多场合,都能使用。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

32

主题

163

帖子

2

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

32

主题

163

帖子

2

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