搜索
bottom↓
回复: 40

stm32 驱动ws2812

  [复制链接]

出0入0汤圆

发表于 2017-3-12 15:44:06 | 显示全部楼层 |阅读模式
最近正在用stm32做一个台灯,使用到了ws2812 LED,到网上找ws2812的stm32驱动,找半天找到一个,结果还是用不了。所以决定还是自己动手来吧。
下面的驱动代码贴出来,时候大家要使用也不错的
ws2812.h

  1. #ifndef __WS2812_H
  2. #define __WS2812_H

  3. #ifdef __cplusplus
  4. extern "C"
  5. {
  6. #endif

  7. #include "stm32f10x_conf.h"

  8. // The following macro must be ported to  your platform
  9. // 以下的宏定义请移植到你的IO Pin
  10. #define   ws2812DIN_HIGH()     (GPIOA->BSRR = 0x00001000)
  11. #define   ws2812DIN_LOW()      (GPIOA->BSRR = 0x10000000)
  12. #define   ws2812DIN_INIT()     { \
  13.                                                                 RCC->APB2ENR |= 0x01<<2; \
  14.                                                                 GPIOA->CRH &= ~(0x000f0000); \
  15.                                                                 GPIOA->CRH |= (0x00030000); \
  16.                                                                 GPIOA->BSRR |= (0x10000000); \
  17.                                                                 }

  18. // RGB structure
  19. typedef struct
  20. {
  21.         // R,G,B color value
  22.     uint8_t ucRedVal;
  23.     uint8_t ucGreenVal;
  24.     uint8_t ucBlueVal;
  25. }RGB_t;
  26. // when you want to use ws2812 , you must call this function
  27. void ws2812_Init(void);
  28. void ws2812_SendRes(void);
  29. void ws2812_SendRGBData(RGB_t xRGB);


  30. /*** typical usage for above API, 典型的使用方法
  31.  ws2812_Init();
  32.     GRB_t xRGB;
  33.     xRGB.ucRedVal = 0xff;
  34.     xRGB.ucGreenVal = 0x00;
  35.     xRGB.ucBlueVal = 0x00;
  36.     while(1)
  37.     {
  38.             // The first ws2812
  39.             ws2812_SendRGBData(xRGB);
  40.             // The second ws2812
  41.             ws2812_SendRGBData(xRGB);
  42.             // The third ws2812
  43.             ws2812_SendRGBData(xRGB);
  44.             //  The fourth ws2812
  45.             ws2812_SendRGBData(xRGB);
  46.             // send frame seperator
  47.             ws2812_SendRes();


  48.     }

  49. */

  50. #ifdef __cplusplus
  51. }
  52. #endif
  53. #endif
复制代码


ws2812.c 文件


  1. #include "ws2812.h"

  2. /*
  3. * @Desc: delay a approximate us
  4. * @Args: ulUs, us about to delay
  5. * @Returns: None
  6. */
  7. static void
  8. DelayUs(uint32_t ulUs)
  9. {
  10.         uint32_t j;
  11.         while(ulUs--)
  12.         {
  13.                 j = 12;
  14.                 while(j)
  15.                 {
  16.                         j--;
  17.                 }
  18.         }
  19. }


  20. /*
  21. * @Desc: delay a number of nop for your platform(one nop equal to 13.9 ns)
  22. * @Args: ulNopNum, nop number
  23. * @Returns: None
  24. *
  25. */
  26. static void
  27. DelayNop(uint32_t ulNopNum)
  28. {
  29.         while(ulNopNum)
  30.         {
  31.                 __NOP();
  32.                 ulNopNum--;
  33.         }
  34. }


  35. /*
  36. * @Desc: init ws2812, just init io Pin, \
  37. *   you must call this function firstly whenever \
  38. *   you want to use ws28128
  39. * @Args: None
  40. * @Returns: None
  41. *
  42. */
  43. void
  44. ws2812_Init(void)
  45. {
  46.         ws2812DIN_INIT();
  47. }


  48. /*
  49. * @Desc: send rgb value to a ws2812,
  50. * @Args: xRGB, rgb value container variable
  51. * @Returns: NOne
  52. *
  53. */
  54. void
  55. ws2812_SendRGBData(RGB_t xRGB)
  56. {
  57.         uint32_t i = 0;
  58.         uint32_t ulColor = 0;
  59.         // put blue color  bit to ulColor
  60.         for(i = 0; i < 8; i++)
  61.         {
  62.                 ulColor = ((xRGB.ucBlueVal & 0x01) | (ulColor << 1));
  63.                 xRGB.ucBlueVal >>= 1;
  64.         }
  65.         // put red color  bit to ulColor
  66.         for(i = 8; i < 16; i++)
  67.         {
  68.                 ulColor = ((xRGB.ucRedVal & 0x01) | (ulColor << 1));
  69.                 xRGB.ucRedVal >>= 1;
  70.         }
  71.         // put green color bit to ulColor
  72.         for(i = 16; i < 24; i++)
  73.         {
  74.                 ulColor = ((xRGB.ucGreenVal & 0x01) | (ulColor << 1));
  75.                 xRGB.ucGreenVal >>= 1;
  76.         }
  77.         // send 24 bits color data
  78.         for(i = 0; i < 24; i++)
  79.         {
  80.                 if((ulColor & (uint32_t)0x01))
  81.                 {
  82.                         ws2812DIN_HIGH();
  83.                         DelayNop(20);
  84.                         ws2812DIN_LOW();
  85.                 }
  86.                 else
  87.                 {
  88.                         ws2812DIN_HIGH();
  89.                         ws2812DIN_LOW();
  90.                         DelayNop(20);
  91.                 }
  92.                 ulColor >>= 1;
  93.         }
  94. }

  95. /*
  96. * @Desc: send a frame seperator
  97. * @Args: None
  98. * @Returns: None
  99. */
  100. void
  101. ws2812_SendRes(void)
  102. {
  103.     ws2812DIN_LOW();
  104.     DelayUs(100);
  105. }

复制代码

阿莫论坛20周年了!感谢大家的支持与爱护!!

如果想吃一顿饺子,就得从冰箱里取出肉,剁馅儿,倒面粉、揉面、醒面,擀成皮儿,下锅……
一整个繁琐流程,就是为了出锅时那一嘴滚烫流油的热饺子。

如果这个过程,禁不住饿,零食下肚了,饺子出锅时也就不香了……《非诚勿扰3》

出0入0汤圆

 楼主| 发表于 2017-3-12 15:52:05 | 显示全部楼层
仔细想了一下把,又把驱动重新的写了一下,(主要把数据结构改了,把ws812_SendRGBData() 换成了ws2812_SendColorData() ),具体地如下:
ws2812.h文件

  1. /**
  2. * Copyright ©2017 Thogo Tech. All Rights Reserved.
  3. *
  4. *@description: This file contains data structure and API
  5.      definition for RGB LED ws2812.it's sensible for time
  6. *@author: infinite.ft
  7. *@create_at: 2017/03/09
  8. *@update_at: 2017/03/12
  9. *@version: 0.0.1
  10. *
  11. */
  12. #ifndef __WS2812_H
  13. #define __WS2812_H

  14. #ifdef __cplusplus
  15. extern "C"
  16. {
  17. #endif

  18. #include "stm32f10x_conf.h"

  19. // The following macro must be ported to  your platform
  20. #define   ws2812DIN_HIGH()     (GPIOA->BSRR = 0x00001000)
  21. #define   ws2812DIN_LOW()      (GPIOA->BSRR = 0x10000000)
  22. #define   ws2812DIN_INIT()     { \
  23.                                                                 RCC->APB2ENR |= 0x01<<2; \
  24.                                                                 GPIOA->CRH &= ~(0x000f0000); \
  25.                                                                 GPIOA->CRH |= (0x00030000); \
  26.                                                                 GPIOA->BSRR |= (0x10000000); \
  27.                                                                 }
  28. // RGB color type structure
  29. typedef union
  30. {
  31.         struct {
  32.                 uint8_t ucPadding;
  33.                 uint8_t ucBlue;
  34.                 uint8_t ucRed;
  35.                 uint8_t ucGreen;
  36.         }xRGB;
  37.         uint32_t ulBits;
  38. }Color_t;

  39. // when you want to use ws2812 , you must call this function
  40. void ws2812_Init(void);
  41. void ws2812_SendRes(void);
  42. void ws2812_SendColorData(Color_t xColor);

  43. /*** typical usage for above API
  44.     Color_t xColor;
  45.     xColor.xRGB.ucRed = 0xff;
  46.     xColor.xRGB.ucGreen = 0x00;
  47.     xColor.xRGB.ucBlue = 0x00;
  48.     while(1)
  49.     {
  50.             // first ws2812
  51.             ws2812_SendColorData(xColor);
  52.             // second ws2812
  53.             ws2812_SendColorData(xColor);
  54.             // third ws2812
  55.             ws2812_SendColorData(xColor);
  56.             // fourth ws2812
  57.             ws2812_SendColorData(xColor);
  58.             // send frame seperator
  59.             ws2812_SendRes();


  60.     }

  61. */

  62. #ifdef __cplusplus
  63. }
  64. #endif
  65. #endif

复制代码


ws2812.c 文件

  1. /**
  2. *
  3. * Copyright ©2017 Thogo Tech. All Rights Reserved.
  4. *
  5. * @description: this file contains functions that responsible
  6.      for performing operation for RGB LED ws2812
  7. * @author: infinite.ft
  8. * @create_at: 2017/03/09
  9. * @update_at: 2017/03/12
  10. * @version: 0.0.1
  11. *
  12. */

  13. #include "ws2812.h"

  14. /*
  15. * @Desc: delay a approximate us
  16. * @Args: ulUs, us about to delay
  17. * @Returns: None
  18. */
  19. static void
  20. DelayUs(uint32_t ulUs)
  21. {
  22.         uint32_t j;
  23.         while(ulUs--)
  24.         {
  25.                 j = 12;
  26.                 while(j)
  27.                 {
  28.                         j--;
  29.                 }
  30.         }
  31. }


  32. /*
  33. * @Desc: delay a number of nop for your platform(one nop equal to 13.9 ns)
  34. * @Args: ulNopNum, nop number
  35. * @Returns: None
  36. *
  37. */
  38. static void
  39. DelayNop(uint32_t ulNopNum)
  40. {
  41.         while(ulNopNum)
  42.         {
  43.                 __NOP();
  44.                 ulNopNum--;
  45.         }
  46. }


  47. /*
  48. * @Desc: init ws2812, just init io Pin, \
  49. *   you must call this function firstly whenever \
  50. *   you want to use ws28128
  51. * @Args: None
  52. * @Returns: None
  53. *
  54. */
  55. void
  56. ws2812_Init(void)
  57. {
  58.         ws2812DIN_INIT();
  59. }


  60. /*
  61. * @Desc: send RGB color value to a ws2812,
  62. * @Args: xColor, rgb color value  variable
  63. * @Returns: NOne
  64. *
  65. */
  66. void ws2812_SendColorData(Color_t xColor)
  67. {
  68.         uint32_t i = 0;
  69.         // send 24 bits color data
  70.         for(i = 0; i < 24; i++)
  71.         {
  72.                 if((xColor.ulBits & (uint32_t)(0x01 << (31-i))))
  73.                 {
  74.                         ws2812DIN_HIGH();
  75.                         DelayNop(20);
  76.                         ws2812DIN_LOW();
  77.                 }
  78.                 else
  79.                 {
  80.                         ws2812DIN_HIGH();
  81.                         ws2812DIN_LOW();
  82.                         DelayNop(20);
  83.                 }
  84.         }
  85. }
  86. /*
  87. * @Desc: send a frame seperator
  88. * @Args: None
  89. * @Returns: None
  90. */
  91. void
  92. ws2812_SendRes(void)
  93. {
  94.     ws2812DIN_LOW();
  95.     DelayUs(100);
  96. }


复制代码

出0入0汤圆

发表于 2017-3-12 16:31:30 | 显示全部楼层
谢谢楼主分享,正准备玩2812呢,还没来及买,先收藏一下,以后再试

出0入0汤圆

发表于 2017-3-12 18:42:09 | 显示全部楼层
github上有不少。楼主的代码那个硬件delay真的不太好,哈哈

出0入0汤圆

发表于 2017-3-12 20:29:25 | 显示全部楼层
我想问问,LED灯带业内一般是用什么软件来编辑动画效果,MCU那一边有现成的驱动吗?查了淘宝,发现好像每一个厂商都是自己定义的一个格式,自己的一个编辑软件

出200入2554汤圆

发表于 2017-3-12 20:34:19 | 显示全部楼层
jlhgold 发表于 2017-3-12 18:42
github上有不少。楼主的代码那个硬件delay真的不太好,哈哈

金老板啊幸会幸会

出0入0汤圆

发表于 2017-3-12 20:38:27 | 显示全部楼层
用delay软件延时的吗,还是用dma+pwm驱动的好点.

http://www.cnblogs.com/shangdawei/p/4762102.html

  1. #include "ws2812.h"
  2. #include <stm32f4xx.h>
  3. #include <stm32f4xx_rcc.h>
  4. #include <stm32f4xx_gpio.h>
  5. #include <stm32f4xx_tim.h>
  6. #include <stm32f4xx_dma.h>

  7. static uint16_t PWM_Buffer[ PWM_BUFFER_SIZE ];
  8. uint32_t frame_pos = 0;
  9. int incomplete_return = 0;

  10. void Update_Buffer( uint16_t* buffer );

  11. static void start_dma( void )
  12. {
  13.   static DMA_InitTypeDef dma_init =
  14.   { .DMA_BufferSize = PWM_BUFFER_SIZE, .DMA_Channel = DMA_Channel_5, .DMA_DIR =
  15.     DMA_DIR_MemoryToPeripheral, .DMA_FIFOMode = DMA_FIFOMode_Disable,
  16.     .DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull, .DMA_Memory0BaseAddr =
  17.       (uint32_t) PWM_Buffer, .DMA_MemoryBurst = DMA_MemoryBurst_Single,
  18.     .DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord, .DMA_MemoryInc =
  19.       DMA_MemoryInc_Enable, .DMA_Mode = DMA_Mode_Circular,
  20.     .DMA_PeripheralBaseAddr = (uint32_t) &TIM3->CCR4, .DMA_PeripheralBurst =
  21.       DMA_PeripheralBurst_Single, .DMA_PeripheralDataSize =
  22.       DMA_PeripheralDataSize_HalfWord, .DMA_PeripheralInc =
  23.       DMA_PeripheralInc_Disable, .DMA_Priority = DMA_Priority_Medium };
  24.   
  25.   DMA_Init( DMA1_Stream2, &dma_init );
  26.   DMA_Cmd( DMA1_Stream2, ENABLE );
  27.   TIM_DMACmd( TIM3, TIM_DMA_CC4, ENABLE );
  28. }

  29. static void init_buffers( void )
  30. {
  31.   for ( int i = 0; i < PWM_BUFFER_SIZE; i++ )
  32.   {
  33.     PWM_Buffer[ i ] = 0;
  34.   }
  35.   for ( int i = 0; i < FRAMEBUFFER_SIZE; i++ )
  36.   {
  37.     ws2812_framebuffer[ i ].red = 0;
  38.     ws2812_framebuffer[ i ].green = 0;
  39.     ws2812_framebuffer[ i ].blue = 0;
  40.   }
  41. }

  42. void ws2812_init( )
  43. {
  44.   init_buffers( );
  45.   
  46.   //InitStructures...
  47.   GPIO_InitTypeDef GPIO_InitStructure;
  48.   TIM_TimeBaseInitTypeDef TIM_TimeBase_InitStructure;
  49.   TIM_OCInitTypeDef TIM_OC_InitStructure;
  50.   NVIC_InitTypeDef nvic_init;
  51.   
  52.   //Clock für GPIO setzen
  53.   RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOC, ENABLE );
  54.   
  55.   //Clock für TIM4 setzen
  56.   RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE );
  57.   
  58.   //GPIO_PIN konfigurieren
  59.   
  60.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  61.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  62.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  63.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  64.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  65.   GPIO_Init( GPIOC, &GPIO_InitStructure );
  66.   
  67.   //GPIO Alternate function verbinden
  68.   GPIO_PinAFConfig( GPIOC, GPIO_PinSource9, GPIO_AF_TIM3 );
  69.   
  70.   TIM_TimeBase_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  71.   TIM_TimeBase_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  72.   TIM_TimeBase_InitStructure.TIM_Period = 104;
  73.   TIM_TimeBase_InitStructure.TIM_Prescaler = 0;
  74.   TIM_TimeBaseInit( TIM3, &TIM_TimeBase_InitStructure );
  75.   
  76.   TIM_OC_InitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  77.   TIM_OC_InitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
  78.   TIM_OC_InitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
  79.   TIM_OC_InitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  80.   TIM_OC_InitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
  81.   TIM_OC_InitStructure.TIM_OutputState = TIM_OutputState_Enable;
  82.   TIM_OC_InitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
  83.   TIM_OC_InitStructure.TIM_Pulse = 0;
  84.   TIM_OC4Init( TIM3, &TIM_OC_InitStructure );
  85.   
  86.   TIM_CtrlPWMOutputs( TIM3, ENABLE );
  87.   
  88.   TIM_OC4PreloadConfig( TIM3, TIM_OCPreload_Enable );
  89.   TIM_ARRPreloadConfig( TIM3, ENABLE );
  90.   
  91.   TIM_CCxCmd( TIM3, TIM_Channel_4, TIM_CCx_Enable );
  92.   TIM_Cmd( TIM3, ENABLE );
  93.   
  94.   // DMA
  95.   RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_DMA1, ENABLE );
  96.   TIM_DMACmd( TIM3, TIM_DMA_CC4, ENABLE );
  97.   DMA_ITConfig( DMA1_Stream2, DMA_IT_HT, ENABLE );
  98.   DMA_ITConfig( DMA1_Stream2, DMA_IT_TC, ENABLE );
  99.   
  100.   start_dma( );
  101.   
  102.   // NVIC for DMA
  103.   nvic_init.NVIC_IRQChannel = DMA1_Stream2_IRQn;
  104.   nvic_init.NVIC_IRQChannelPreemptionPriority = 4;
  105.   nvic_init.NVIC_IRQChannelSubPriority = 0;
  106.   nvic_init.NVIC_IRQChannelCmd = ENABLE;
  107.   NVIC_Init( &nvic_init );
  108. }

  109. // writes the pwm values of one byte into the array which will be used by the dma
  110. static inline void color2pwm( uint16_t ** const dest, const uint8_t color )
  111. {
  112.   uint8_t mask = 0x80;
  113.   
  114.   do
  115.   {
  116.     if ( color & mask )
  117.     {
  118.       * *dest = 49;
  119.     }
  120.     else
  121.     {
  122.       * *dest = 20;
  123.     }
  124.     *dest += 1;
  125.     mask >>= 1;
  126.   }while ( mask != 0 );
  127. }

  128. void Update_Buffer( uint16_t* buffer )
  129. {
  130.   struct led *framebufferp;
  131.   uint32_t i, j;
  132.   uint16_t * bufp;
  133.   
  134.   for ( i = 0; i < ( PWM_BUFFER_SIZE / 2 ) / 24; i++ )
  135.   {
  136.     if ( incomplete_return )
  137.     {
  138.       incomplete_return = 0;
  139.       for ( j = 0; j < 24; j++ )
  140.       {
  141.         buffer[ i * 24 + j ] = 0;
  142.       }
  143.       
  144.     }
  145.     else
  146.     {
  147.       if ( frame_pos == FRAMEBUFFER_SIZE )
  148.       {
  149.         incomplete_return = 1;
  150.         frame_pos = 0;
  151.         
  152.         for ( j = 0; j < 24; j++ )
  153.         {
  154.           buffer[ i * 24 + j ] = 0;
  155.         }
  156.       }
  157.       else
  158.       {
  159.         framebufferp = &ws2812_framebuffer[ frame_pos++ ];
  160.         bufp = buffer + ( i * 24 );
  161.         
  162.         // edit here to change order of colors in "ws2812_framebuffer" (0x00RRGGBB, 0x00GGBBRR, etc)
  163.         // the chip needs G R B
  164.         color2pwm( &bufp, framebufferp->green ); // green
  165.         color2pwm( &bufp, framebufferp->red ); // red
  166.         color2pwm( &bufp, framebufferp->blue ); // blue
  167.       }
  168.     }
  169.   }
  170. }

  171. void DMA1_Stream2_IRQHandler( void )
  172. {
  173.   // Half-Transfer completed
  174.   if ( DMA_GetITStatus( DMA1_Stream2, DMA_IT_HTIF2 ) )
  175.   {
  176.     DMA_ClearITPendingBit( DMA1_Stream2, DMA_IT_HTIF2 );
  177.     Update_Buffer( PWM_Buffer );
  178.   }
  179.   
  180.   // Transfer completed
  181.   if ( DMA_GetITStatus( DMA1_Stream2, DMA_IT_TCIF2 ) )
  182.   {
  183.     DMA_ClearITPendingBit( DMA1_Stream2, DMA_IT_TCIF2 );
  184.     Update_Buffer( PWM_Buffer + ( PWM_BUFFER_SIZE / 2 ) );
  185.   }
  186.   
  187. }
复制代码

出0入22汤圆

发表于 2017-3-12 21:10:46 来自手机 | 显示全部楼层
这是不是单线驱动那个led?

出0入0汤圆

发表于 2017-3-12 23:14:42 | 显示全部楼层
t3486784401 发表于 2017-3-12 20:34
金老板啊幸会幸会

杨博士好,哈哈

出0入0汤圆

 楼主| 发表于 2017-3-13 09:06:48 | 显示全部楼层
本帖最后由 helloforworld 于 2017-3-13 09:08 编辑

大神写终于出来指导了,

出0入0汤圆

 楼主| 发表于 2017-3-13 09:09:45 | 显示全部楼层
hyz_avr 发表于 2017-3-12 20:38
用delay软件延时的吗,还是用dma+pwm驱动的好点.

http://www.cnblogs.com/shangdawei/p/4762102.html

楼主能说一下 通过DMA+PWM驱动ws2812有什么好处吗

出0入0汤圆

发表于 2017-3-13 09:10:21 | 显示全部楼层
spi+dma啊,so easy

出0入0汤圆

 楼主| 发表于 2017-3-13 09:31:33 | 显示全部楼层

楼主,SPI+DMA 的优点?

出200入2554汤圆

发表于 2017-3-13 20:30:08 | 显示全部楼层
helloforworld 发表于 2017-3-13 09:31
楼主,SPI+DMA 的优点?

单线的WS2812对时序实时性要求比较严(800kbps,不允许间断),用软件模拟的话,对CPU的占用太大;
对应到C程序里,就是有这么一段很耗时还不能打断(进去前需要关中断)。

SPI+DMA都是硬件的结构,设置好寄存器后,底层硬件负责产生800kbps发送时序,此时CPU已经解放;
对应到C程序里,就是这么一段已经调用完成,可以随便搞其他什么事情了。

我用 AVR (7.3M)写过这个的驱动,直接汇编排指令来节省时间的,中断什么的都不用想,完全来不及。

出10入0汤圆

发表于 2017-3-13 20:52:23 来自手机 | 显示全部楼层
first_blood 发表于 2017-3-13 09:10
spi+dma啊,so easy

顶,最优方案     

出0入0汤圆

发表于 2017-3-14 21:21:39 | 显示全部楼层
spi+dma,不占用CPU,就是用ram虚拟出一段显存出来,更新RGB灯,只需要更新一下ram就行。用spi的位模拟ws2812的时序,spi时钟2.25M,一个bit0.44us,用3个bit表示ws2812b的一个bit,100为0,110为1,一个灯24bit需要spi发送9个字节,需要做一个转码程序。做小型彩色点阵屏都带的动

出0入0汤圆

发表于 2017-3-15 09:15:04 来自手机 | 显示全部楼层
彩色的台灯?

出0入0汤圆

 楼主| 发表于 2017-3-18 09:24:36 | 显示全部楼层
first_blood 发表于 2017-3-14 21:21
spi+dma,不占用CPU,就是用ram虚拟出一段显存出来,更新RGB灯,只需要更新一下ram就行。用spi的位模拟ws28 ...

谢谢楼主,

出0入0汤圆

 楼主| 发表于 2017-3-18 09:25:06 | 显示全部楼层

对,做一个可变颜色的台灯

出0入0汤圆

发表于 2017-3-18 10:12:51 | 显示全部楼层
SPI+DMA驱动方式:
MCU: STM32F103C8T6
IO配置:PB15(SPI2.MOSI) , 5V上拉电阻(1K)+ 开漏输出
SPI时钟:9M,每bit0.11us, 用12bit拼接成一个WS2812的数据位

  1. unsigned char ws2812b_PixBuf[48] = {0};//像素缓存区 16个灯*3
  2. unsigned char spi_SendBuf[576] = {0,0,0};//SPI的发送缓存区

  3. #define SENDLENGTH 576


  4. /*
  5. *****************************************************
  6. *        功能说明: WS2812b初始化
  7. *        形    参:
  8. *        返 回 值:
  9. *        备    注:
  10. *****************************************************
  11. */
  12. void WS2812b_Init(void)
  13. {
  14.         GPIO_InitTypeDef GPIO_InitStructure;
  15.         SPI_InitTypeDef SPI_InitStructure;
  16.         DMA_InitTypeDef DMA_InitStructure;
  17.        
  18.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  19.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,  ENABLE);
  20.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  21.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
  22.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;  
  23.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  24.         GPIO_Init(GPIOB, &GPIO_InitStructure);
  25.        
  26.         GPIO_ResetBits(GPIOB,GPIO_Pin_15);//拉低数据线,复位WS2812b

  27.         SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;//一线发送
  28.         SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主模式
  29.         SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8位
  30.         SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//时钟空闲时为高
  31.         SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//时钟的第二个跳变沿采样数据
  32.         SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//软件控制片选信号
  33.         SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;//波特率4分频  36M/4 = 9M =0.11us
  34.         SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//高位在前
  35.         SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC校验多项式 大于1即可
  36.         SPI_Init(SPI2, &SPI_InitStructure);  
  37.        
  38.         DMA_DeInit(DMA1_Channel5);
  39.         DMA_InitStructure.DMA_BufferSize = SENDLENGTH;
  40.         DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & (SPI2->DR);
  41.         DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)spi_SendBuf;
  42.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  43.         DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
  44.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  45.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  46.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  47.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  48.         DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  49.         DMA_Init(DMA1_Channel5, &DMA_InitStructure); /* DMA1 CH5 = MEM -> DR */
  50.        
  51.         SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
  52.         SPI_Cmd(SPI2, ENABLE);
  53.         DMA_Cmd(DMA1_Channel5, DISABLE);
  54. }

  55. /*
  56. *****************************************************
  57. *        功能说明: WS2812b显示
  58. *        形    参:
  59. *        返 回 值:
  60. *        备    注:
  61. *                        放在主循环里面定时刷新,
  62. *           刷新像素缓存区数据即可改变显示
  63. *****************************************************
  64. */
  65. void WS2812b_Display(void)
  66. {
  67.         unsigned short i,j;
  68.         unsigned short index;
  69.         unsigned short tmp;
  70.        
  71.         for(i = 0;i < 48;i++)//轮询像素缓存区
  72.         {
  73.                 for(j = 0;j < 8;j++)//轮询每个像素字节的每个位,转换成SPI的12bit数据
  74.                 {
  75.                         index = 8 * i + j;
  76.                         tmp = ws2812b_PixBuf[i] & (1 << (7 - j));
  77.                        
  78.                         if(index & 1)
  79.                         {
  80.                                 spi_SendBuf[3 * ((index - 1) / 2) + 1] |= 0x0f;
  81.                                
  82.                                 if(tmp)
  83.                                         spi_SendBuf[3 * ((index - 1) / 2) + 2] = 0xf0;
  84.                                 else               
  85.                                         spi_SendBuf[3 * ((index - 1) / 2) + 2] = 0x00;
  86.                         }
  87.                         else
  88.                         {
  89.                                 spi_SendBuf[3 * (index / 2) + 1] = 0x00;
  90.                                
  91.                                 if(tmp)
  92.                                         spi_SendBuf[3 * (index / 2)] = 0xff;               
  93.                                 else
  94.                                         spi_SendBuf[3 * (index / 2)] = 0xf0;
  95.                         }
  96.                 }
  97.         }
  98.        
  99.         DMA_Cmd(DMA1_Channel5, DISABLE);
  100.         DMA_ClearFlag(DMA1_FLAG_TC5);
  101.         DMA1_Channel5->CNDTR = SENDLENGTH;
  102.         DMA_Cmd(DMA1_Channel5, ENABLE);
  103. }
复制代码

出0入0汤圆

发表于 2017-3-18 12:35:51 | 显示全部楼层
helloforworld 发表于 2017-3-18 09:25
对,做一个可变颜色的台灯

这还是台灯么。。。装饰灯吧。

出0入0汤圆

 楼主| 发表于 2017-3-18 15:54:45 | 显示全部楼层
huangqi412 发表于 2017-3-18 12:35
这还是台灯么。。。装饰灯吧。

不一定就非得装饰灯才能是五颜六色.在不同的环境下,比如看书,看电影,听音乐,办公,也可以使用不同颜色灯光

出0入0汤圆

 楼主| 发表于 2017-3-18 15:56:45 | 显示全部楼层
浮生莫若闲 发表于 2017-3-18 10:12
SPI+DMA驱动方式:
MCU: STM32F103C8T6
IO配置:PB15(SPI2.MOSI) , 5V上拉电阻(1K)+ 开漏输出

我就喜欢楼主这么实在的人,一言不合就show your code

出0入0汤圆

发表于 2017-3-18 16:49:23 | 显示全部楼层
可以,不过我在想有没有更好的延时产生脉冲的方式

出0入0汤圆

发表于 2017-3-18 19:28:33 | 显示全部楼层
helloforworld 发表于 2017-3-18 15:56
我就喜欢楼主这么实在的人,一言不合就show your code

刚好前几天从淘宝上买了块16灯的板子玩了下,不过我上面的代码没有检测每次的刷新是否完成。所以,在定时刷新显示的时候,为了确保上一次SPI的传输已经完成,间隔时间可以稍微长点

出0入14汤圆

发表于 2017-3-18 21:19:18 | 显示全部楼层
first_blood 发表于 2017-3-14 21:21
spi+dma,不占用CPU,就是用ram虚拟出一段显存出来,更新RGB灯,只需要更新一下ram就行。用spi的位模拟ws28 ...

看了下WS2812的驱动。。。0和1是占空比不一样,

        高      低
0 是  0.35  0.8  us
1 是  0.7    0.6  us

这种用SPI怎么实现?SPI的波特率是一定的啊,除非  SPI 设定的波特率位时间可以到0.1us才有可能实现

出0入0汤圆

发表于 2017-3-19 21:35:53 | 显示全部楼层
9M 不就是0.11us,ws2812b的时序跟ws2812不一样

出0入0汤圆

发表于 2017-3-19 22:01:39 | 显示全部楼层
mark下,以后肯定有的用,谢谢!

出0入0汤圆

发表于 2017-3-29 20:03:26 | 显示全部楼层
您好,看到您发帖驱动WS2812,现在我遇到点问题,您方便指点我一下嘛?非常感谢。。。

出0入0汤圆

发表于 2017-3-30 08:46:43 | 显示全部楼层
浮生莫若闲 发表于 2017-3-18 10:12
SPI+DMA驱动方式:
MCU: STM32F103C8T6
IO配置:PB15(SPI2.MOSI) , 5V上拉电阻(1K)+ 开漏输出

您好,看到您发帖驱动WS2812,现在我遇到点问题,您方便指点我一下嘛?非常感谢。。。

出0入0汤圆

发表于 2017-3-30 09:01:03 | 显示全部楼层
zhujie123 发表于 2017-3-30 08:46
您好,看到您发帖驱动WS2812,现在我遇到点问题,您方便指点我一下嘛?非常感谢。。。 ...

什么问题

出0入4汤圆

发表于 2017-3-30 10:52:38 | 显示全部楼层
isakura 发表于 2017-3-18 21:19
看了下WS2812的驱动。。。0和1是占空比不一样,

        高      低

时间不用这么精确的,楼上不是说了12 spi的bit 组成1 ws的bit

出0入0汤圆

发表于 2019-5-5 18:23:27 | 显示全部楼层
浮生莫若闲 发表于 2017-3-18 10:12
SPI+DMA驱动方式:
MCU: STM32F103C8T6
IO配置:PB15(SPI2.MOSI) , 5V上拉电阻(1K)+ 开漏输出

        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 试了试这个代码 加这句DMA才正常

出0入0汤圆

发表于 2019-5-6 17:46:57 | 显示全部楼层
一般般吧

出0入0汤圆

发表于 2019-6-13 14:22:50 | 显示全部楼层
Halley 发表于 2019-5-5 18:23
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 试了试这个代码 加这句DMA才正常

试了下,确实要加上这句才正常。 谢谢分享。  

出0入0汤圆

发表于 2019-6-13 17:29:51 | 显示全部楼层
这个要io快,慢的需要pwm了

出0入0汤圆

发表于 2020-6-10 08:22:52 来自手机 | 显示全部楼层
最近要用到一ws2812,标记一下

出0入0汤圆

发表于 2020-11-2 07:01:41 来自手机 | 显示全部楼层
请教下楼主,你这个io直接接在ws2812的din脚的吗,需要做电平转换吗?

出0入0汤圆

发表于 2020-11-12 23:21:56 | 显示全部楼层
直接用SPI输出,几句话的事 .

出0入0汤圆

发表于 2020-11-13 08:40:01 | 显示全部楼层
我们用这个统一标准ISELED,一路类似iic协议的可以控制4096颗灯珠的RGB啊
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-28 20:24

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表