stm32 驱动ws2812

2020-01-07 19:22发布

最近正在用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. }

复制代码
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
36条回答
t3486784401
1楼-- · 2020-01-09 08:36
helloforworld 发表于 2017-3-13 09:31
楼主,SPI+DMA 的优点?

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

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

我用 AVR (7.3M)写过这个的驱动,直接汇编排指令来节省时间的,中断什么的都不用想,完全来不及。
chenhaimeng123
2楼-- · 2020-01-09 12:59
 精彩回答 2  元偷偷看……
first_blood
3楼-- · 2020-01-09 13:59
spi+dma,不占用CPU,就是用ram虚拟出一段显存出来,更新RGB灯,只需要更新一下ram就行。用spi的位模拟ws2812的时序,spi时钟2.25M,一个bit0.44us,用3个bit表示ws2812b的一个bit,100为0,110为1,一个灯24bit需要spi发送9个字节,需要做一个转码程序。做小型彩 {MOD}点阵屏都带的动
huangqi412
4楼-- · 2020-01-09 16:29
彩 {MOD}的台灯?
helloforworld
5楼-- · 2020-01-09 19:57
first_blood 发表于 2017-3-14 21:21
spi+dma,不占用CPU,就是用ram虚拟出一段显存出来,更新RGB灯,只需要更新一下ram就行。用spi的位模拟ws28 ...

谢谢楼主,
helloforworld
6楼-- · 2020-01-09 23:19
huangqi412 发表于 2017-3-15 09:15
彩 {MOD}的台灯?

对,做一个可变颜 {MOD}的台灯

一周热门 更多>