OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 1884|回复: 10

求助,用STM32控制多个串联的WS2812B的RGB灯

[复制链接]

6

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2019-6-13
在线时间
26 小时
发表于 2019-7-31 15:26:44 | 显示全部楼层 |阅读模式
1金钱
求用STM32控制多个串联的WS2812B的RGB灯的思路或者代码

最佳答案

查看完整内容[请看2#楼]

上面测试过。。。灯亮没问题。。stm32F405
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

4

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2019-6-10
在线时间
2 小时
发表于 2019-7-31 15:26:45 | 显示全部楼层
上面测试过。。。灯亮没问题。。stm32F405
回复

使用道具 举报

109

主题

5564

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
10570
金钱
10570
注册时间
2017-2-18
在线时间
1913 小时
发表于 2019-7-31 17:27:28 | 显示全部楼层
帮顶~~
回复

使用道具 举报

6

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2019-6-13
在线时间
26 小时
 楼主| 发表于 2019-8-1 08:59:24 | 显示全部楼层
自己顶·······
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手入门

积分
16
金钱
16
注册时间
2019-8-6
在线时间
3 小时
发表于 2019-8-6 14:16:31 | 显示全部楼层
我也遇到了同样的问题,有没有高手帮忙解答,重谢!
回复

使用道具 举报

0

主题

7

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-5-21
在线时间
10 小时
发表于 2019-8-6 14:28:41 | 显示全部楼层
使用  CD4051  CD4052  等模拟开关芯片   可以实现开关部分      精确到单个的话   可以使用io口拓展芯片    在led两端  一个拉高一个拉低  (芯片有595.或者选择 138编码器   等等)
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手入门

积分
16
金钱
16
注册时间
2019-8-6
在线时间
3 小时
发表于 2019-8-6 15:04:11 | 显示全部楼层
不知道楼主搞定了没?
回复

使用道具 举报

6

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2019-6-13
在线时间
26 小时
 楼主| 发表于 2019-8-6 15:29:43 | 显示全部楼层
daidai0626 发表于 2019-8-6 15:04
不知道楼主搞定了没?

还没有的
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手入门

积分
16
金钱
16
注册时间
2019-8-6
在线时间
3 小时
发表于 2019-8-7 09:11:24 | 显示全部楼层

搞定了,请告知下,必有重谢
回复

使用道具 举报

0

主题

4

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2019-6-10
在线时间
2 小时
发表于 2019-10-21 10:18:48 | 显示全部楼层
#ifndef __WS2812B_H__
#define __WS2812B_H__

#include <stdbool.h>
#include "stm32f4xx.h"



#define WS2812B_TEST                     1
#define WS2812B_GPIO_PERIF               RCC_AHB1Periph_GPIOA
#define WS2812B_TIM_PERIF                RCC_APB1Periph_TIM3
#define WS2812B_TIM                      TIM3
#define WS2812B_DMA                      RCC_AHB1Periph_DMA1
#define WS2812B_DMA_CHANNEL              DMA1_Stream4
#define WS2812B_DMA_NVIC_IRQChannel      DMA1_Stream4_IRQn
#define WS2812B_GPIO_PORT                GPIOA
#define WS2812B_GPIO_PIN                 GPIO_Pin_6

#define WS2812B_PIN_SOURCE                                                         GPIO_PinSource6
#define        WS2812B_GPIO_AF_TIMER                                     GPIO_AF_TIM3

#define WS2812B_TMI_CLOCK                56000000
#define WS2812B_TIM_PERIOD               29

#define WS2812B_NUM                      40
#define WS2812B_PULSE_BIT_SIZE           24
#define WS2812B_BUFF_SIZE                (24 * (WS2812B_NUM) + 50)   // Buffer size needs to be the number of LEDs times 24 bits plus 43 trailing bit
#define WS2812B_NVIC_PRI                 1
#define WS2812B_DMA_PeripheralBaseAddr   (uint32_t)&TIM3->CCR1;

#define WS2812B_PWM_HIGH_PULSE_WIDTH           19                    // Duty cycle of pwm signal for a logical 1 to be read by the ws2812 chip
#define WS2812B_PWM_LOW_PULSE_WIDTH            9                     // Duty cycle of pwm signal for a logical 0 to be read by the ws2812 chip
#define WS2812B_ALL_INDEX                      -1

#define WS2812B_CREATE_PULSE_BUFF() do { \
        clr = color; \
        for (j = 0; j < WS2812B_PULSE_BIT_SIZE; j++) { \
            ws2812bBuff[k++] = (clr & 0x800000 ) ? WS2812B_PWM_HIGH_PULSE_WIDTH : WS2812B_PWM_LOW_PULSE_WIDTH; \
            clr <<= 1; \
        } \
    } while(0)

void ws2812bInit(void);
bool ws2812bTest(void);
void ws2812bClear(const int index);
void ws2812bClearAll(void);
void ws2812bSet(const int index, const int color);
void ws2812bSetAll(const int32_t color);
void DMA1_Stream5_IRQHandler(void);

#endif

#include "ws2812b.h"
#include <rtthread.h>
#include <string.h>


static bool isInited = false;


static uint16_t ws2812bBuff[WS2812B_BUFF_SIZE];   // Array of data to be sent to leds.
static void ws2812bSend(void);



void ws2812bInit(void)
{
                GPIO_InitTypeDef GPIO_InitStruct;
                TIM_TimeBaseInitTypeDef  TIM_TimeBaseStruct;
                TIM_OCInitTypeDef  TIM_OCInitStruct;
                DMA_InitTypeDef DMA_InitStruct;
                NVIC_InitTypeDef NVIC_InitStructure;  
       
                RCC_AHB1PeriphClockCmd(WS2812B_GPIO_PERIF, ENABLE);
                RCC_APB1PeriphClockCmd(WS2812B_TIM_PERIF, ENABLE);
                RCC_AHB1PeriphClockCmd(WS2812B_DMA, ENABLE);
               
                GPIO_InitStruct.GPIO_Pin = WS2812B_GPIO_PIN;
                GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
                GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
                GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
                GPIO_InitStruct.GPIO_Speed = GPIO_Speed_25MHz;
                GPIO_Init(WS2812B_GPIO_PORT, &GPIO_InitStruct);
               
                GPIO_PinAFConfig(WS2812B_GPIO_PORT, WS2812B_PIN_SOURCE, WS2812B_GPIO_AF_TIMER);
   
    TIM_DeInit(WS2812B_TIM);
    TIM_TimeBaseStruct.TIM_Period = WS2812B_TIM_PERIOD;
    TIM_TimeBaseStruct.TIM_Prescaler = (uint16_t)(SystemCoreClock / WS2812B_TMI_CLOCK) - 1;
    TIM_TimeBaseStruct.TIM_ClockDivision = 0;
    TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
                TIM_TimeBaseStruct.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(WS2812B_TIM, &TIM_TimeBaseStruct);
   
    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStruct.TIM_Pulse = 0;
    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;   
                TIM_OC1Init(WS2812B_TIM, &TIM_OCInitStruct);               
                TIM_OC1PreloadConfig(WS2812B_TIM,TIM_OCPreload_Enable);
                TIM_ARRPreloadConfig(WS2812B_TIM, ENABLE);
               
                DMA_DeInit(WS2812B_DMA_CHANNEL);
                while (DMA_GetCmdStatus(WS2812B_DMA_CHANNEL) != DISABLE){}
                       
                DMA_InitStruct.DMA_BufferSize = WS2812B_BUFF_SIZE; // Specifies the buffer size
    DMA_InitStruct.DMA_Channel = DMA_Channel_5; // Deinitialize DAM1 Channel 7 to their default reset values.
                DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;                            // Data transfered from memory to peripheral
                DMA_InitStruct.DMA_FIFOMode= DMA_FIFOMode_Disable;                                                                                        //DMAμ&#196;FIFO&#196;£ê&#189;
                DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
                DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&ws2812bBuff;                // Specifies the buffer memory address
                DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
                DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;           // Specifies the memory data width
                DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;                       // Incrament the buffer index
                DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;                                 // Specifies the operation mode. Normal or Circular
                DMA_InitStruct.DMA_PeripheralBaseAddr = WS2812B_DMA_PeripheralBaseAddr;     // Specifies Physical address of the peripheral in this case Timer
                DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
                DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;   // Specifies the peripheral data width 16bit               
                DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;              // Do not incrament the peripheral address               
                DMA_InitStruct.DMA_Priority = DMA_Priority_High;                           // Specifies the software priority
                DMA_Init(WS2812B_DMA_CHANNEL, &DMA_InitStruct);                            // Initialize DAM1 Channel 2 to values specified in the DMA_InitStruct structure.               

                TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE);

                ws2812bClearAll();
   
    isInited = true;
}

bool ws2812bTest(void)
{
    #if(WS2812B_TEST == 1)
    ws2812bSet(0, 0xff0000);
    for(int i = 1000000; i > 0; i--);
    ws2812bClear(0);
    #endif
    return isInited;
}

void ws2812bClear(const int index)
{
    ws2812bSet(index, 0);
}

void ws2812bClearAll()
{
    int32_t i, j, k = 0;
   
    for (i = 0; i < WS2812B_NUM; i++)
    {
        for (j = 0; j < WS2812B_PULSE_BIT_SIZE; j++)
        {
            ws2812bBuff[k++] = WS2812B_PWM_LOW_PULSE_WIDTH;
        }
    }

    memset(&ws2812bBuff[k], 0, WS2812B_BUFF_SIZE - k);
    ws2812bSend();
}

void ws2812bSet(const int index, const int32_t color)
{
    int32_t i, j;
    int32_t k = 0;
    int32_t clr = color;
   
    if(index >= WS2812B_NUM || (index < 0 && index != WS2812B_ALL_INDEX))
    {
        return;
    }
   
    k = index * WS2812B_PULSE_BIT_SIZE;
   
    if(index != WS2812B_ALL_INDEX)
    {
        WS2812B_CREATE_PULSE_BUFF();
    }
    else
    {
        for(i = 0; i < WS2812B_NUM; i++)
            WS2812B_CREATE_PULSE_BUFF();
    }

    ws2812bSend();
}

void ws2812bSetAll(const int32_t color)
{
    ws2812bSet(WS2812B_ALL_INDEX, color);
}
static void ws2812bSend(void)
{
                DMA_SetCurrDataCounter(WS2812B_DMA_CHANNEL, WS2812B_BUFF_SIZE);                
                DMA_Cmd(WS2812B_DMA_CHANNEL, ENABLE);        //ê1&#196;üDMA
                TIM_SetCounter(TIM3,0x0000);
                TIM_Cmd(TIM3, ENABLE);                        //ê1&#196;ü&#182;¨ê±&#198;÷
               
                while(!DMA_GetFlagStatus(WS2812B_DMA_CHANNEL,DMA_FLAG_TCIF4));        // wait until transfer complete
                DMA_Cmd(WS2812B_DMA_CHANNEL, DISABLE);        //ê1&#196;üDMA
               
       
                DMA_ClearFlag(WS2812B_DMA_CHANNEL,DMA_FLAG_TCIF4);
                TIM_Cmd(TIM3, DISABLE);                        //ê1&#196;ü&#182;¨ê±&#198;÷
}


/*2aê&#212;3ìDò2019.10.18&#198;á±&#206;*/
//uint8_t rgb0[1][3] = {0,0,0};
//uint8_t rgb1[1][3] = {0xAA, 0xAA, 0xAA};
//uint8_t r[1][3] = {255,0,0};
//uint8_t g[1][3] = {0,255,0};
//uint8_t b[1][3] = {0,0,255};
//uint8_t y[1][3] = {255,0,255};
//uint8_t cg[1][3] = {153,51,250};

//#define TIMING_ONE  68        // 0.8usμ&#231;&#198;&#189;ê±&#188;&#228;
//#define TIMING_ZERO 37        // 0.3usμ&#231;&#198;&#189;ê±&#188;&#228;

//void WS2812_send(uint8_t (*color)[3], uint16_t len)
//{
//        uint8_t i;
//        uint16_t memaddr;
//        uint16_t buffersize;
//        buffersize = (len*24)+ 50;        // number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes
//        memaddr = 0;                                // reset buffer memory index

//        while (len)
//        {       
//                for(i=0; i<8; i++) // GREEN data
//                {
//                        ws2812bBuff[memaddr] = ((color[0][1]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
//                        memaddr++;
//                }
//                for(i=0; i<8; i++) // RED
//                {
//                                ws2812bBuff[memaddr] = ((color[0][0]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
//                                memaddr++;
//                }
//                for(i=0; i<8; i++) // BLUE
//                {
//                                ws2812bBuff[memaddr] = ((color[0][2]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
//                                memaddr++;
//                }
//                len--;
//        }
////===================================================================//       
////bug£o×&#238;oóò&#187;&#184;&#246;&#214;ü&#198;ú2¨D&#206;2&#187;&#214;aμà&#206;aê2&#195;′è&#171;ê&#199;&#184;&#223;μ&#231;&#198;&#189;£&#172;1ê&#212;&#246;&#188;óò&#187;&#184;&#246;2¨D&#206;
//          ws2812bBuff[memaddr] = ((color[0][2]<<8) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
////===================================================================//       
//          memaddr++;       
//                while(memaddr < buffersize)
//                {
//                        ws2812bBuff[memaddr] = 0;
//                        memaddr++;
//                }

//                DMA_SetCurrDataCounter(WS2812B_DMA_CHANNEL, buffersize);                
//                DMA_Cmd(WS2812B_DMA_CHANNEL, ENABLE);        //ê1&#196;üDMA
//                TIM_SetCounter(TIM3,0x0000);
//                TIM_Cmd(TIM3, ENABLE);                        //ê1&#196;ü&#182;¨ê±&#198;÷
//               
//                while(!DMA_GetFlagStatus(WS2812B_DMA_CHANNEL,DMA_FLAG_TCIF4));        // wait until transfer complete
//                DMA_Cmd(WS2812B_DMA_CHANNEL, DISABLE);        //ê1&#196;üDMA
//               
//       
//                DMA_ClearFlag(WS2812B_DMA_CHANNEL,DMA_FLAG_TCIF4);
//                TIM_Cmd(TIM3, DISABLE);                        //ê1&#196;ü&#182;¨ê±&#198;÷
//}
/*2aê&#212;3ìDò2019.10.18&#198;á±&#206;*/


ALIGN(RT_ALIGN_SIZE)
static char ws2812b_thread_stack[1024];
struct rt_thread ws2812b_thread;
static void ws2812b_thread_entry(void *param)
{
    rt_time_t        next_delay;
    ws2812bInit();
                if(!ws2812bTest()) while(1);
    next_delay = 50; //100ms
    rt_thread_delay(next_delay);

    while(1)
    {
//                        for(int i = 0;i < 31;i++)
//                        {
//                                ws2812bSet(i, 0xff0000);
//                                rt_thread_delay(next_delay);
//                        }
//                        rt_thread_delay(next_delay);
//                        ws2812bClearAll();
//                        for(int i = 0;i < 31;i++)
//                        {
//                                ws2812bSet(i, 0x00ff00);
//                                rt_thread_delay(next_delay);
//                        }
//                        rt_thread_delay(next_delay);
//                        ws2812bClearAll();
//                        for(int i = 0;i < 31;i++)
//                        {
//                                ws2812bSet(i, 0x0000ff);
//                                rt_thread_delay(next_delay);
//                        }
                       
                        ws2812bSet(5, 0xff0000);
                        rt_thread_delay(next_delay);
                        ws2812bClearAll();
                        rt_thread_delay(next_delay);
                }
}

void ws2812b_thread_init(uint8_t prio)
{
    //pulse pump thread init
    rt_thread_init(&ws2812b_thread, "ws2812b",
                   ws2812b_thread_entry, RT_NULL,
                   &ws2812b_thread_stack[0],
                   sizeof(ws2812b_thread_stack), prio, 5);
    rt_thread_startup(&ws2812b_thread);
}

回复

使用道具 举报

0

主题

4

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2019-6-10
在线时间
2 小时
发表于 2019-10-21 10:26:31 | 显示全部楼层
如果需要stm32f1系列代码,网址没有权限粘贴,大家百度一下:WS2812灯珠的STM32驱动方式(二)——DMA+PWM ,这个解释真不错
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-5 12:27

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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