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. }

复制代码
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
37条回答
hyz_avr
2020-01-08 13:10
用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. }
复制代码

一周热门 更多>