lilijin1995 发表于 2023-2-12 14:12

CH582何以驱动WS2812,TIM之PWM DMA模式实现RainbowCycle效果So easy

本帖最后由 lilijin1995 于 2023-2-14 11:19 编辑

      在我们游乐和电脑、游戏外设行业,WS2812这种类型的灯珠应用还是很广的,有些可以在游乐场的游乐设备上面增加对应的灯板实现绚丽的彩灯效果,有些可以在键盘上,或有些游戏外设上的七彩彩虹灯,七彩呼吸灯等等。有网友评论雷蛇是灯厂,就是因为其键盘鼠标上的炫酷的灯光效果。
      CH582的出现,对于我们搞电脑游戏外设的工程师来说,可以说解决了我们很多选型上面遇到的问题,对于公司生产成本的减低可以说是具有重要意义的,因为其具备了2.4G+蓝牙5.0+USB三种模式。这样极大节约了增加蓝牙模块,2.4G模块带来的成本,而且两个USB外设都支持主从模式!

一、WS2812B的介绍
主要特点
● IC控制电路与LED点光源共用一个电源。
● 控制电路与RGB芯片集成在一个5050封装的元器件中,构成一个完整的外控像素点。
● 内置信号整形电路,任何一个像素点收到信号后经过波形整形再输出,保证线路波形畸变不会累加。
● 内置上电复位和掉电复位电路。
● 每个像素点的三基色颜色可实现256级亮度显示,完成16777216种颜色的全真色彩显示。
● 端口扫描频率2KHz/s。
● 串行级联接口,能通过一根信号线完成数据的接收与解码。
● 当刷新速率30帧/秒时,级联数不小于1024点。
● 数据发送速度可达800Kbps。
● 光的颜色高度一致,性价比高。
● 具有电源反接不会损坏。
● 外围不需要包含电容在内的所有任何电子元器件。
主要应用领域
● 消费性电子产品领域。
● LED灯饰亮化领域。
● 电脑及周边设备\游戏设备\各种电器设备领域。

我们根据特性描述已知:数据发送速度可达800Kbps。 时序图如下:


我们使用CH582M TIM的PWM DMA模式驱动,我们先来看一下官方的TMR例程:
int main()
{
    uint8_t i;

    SetSysClock(CLK_SOURCE_PLL_60MHz);

    /* 配置串口调试 */
    DebugInit();
    PRINT("Start @ChipID=%02X\n", R8_CHIP_ID);

#if 1 /* 定时器2,DMA PWM.*/
    GPIOB_ModeCfg(GPIO_Pin_11, GPIO_ModeOut_PP_5mA);
    GPIOPinRemap(ENABLE, RB_PIN_TMR2);

    PRINT("TMR2 DMA PWM\n");
    TMR2_PWMCycleCfg(120000); // 周期 2000us
    for(i=0; i<50; i++)
    {
      PwmBuf=2400*i;
    }
    for(i=50; i<100; i++)
    {
      PwmBuf=2400*(100-i);
    }
    TMR2_DMACfg(ENABLE, (uint16_t)(uint32_t)&PwmBuf, (uint16_t)(uint32_t)&PwmBuf, Mode_LOOP);
    TMR2_PWMInit(Low_Level, PWM_Times_16);
    /* 开启计数溢出中断,计满1000个周期进入中断 */
    TMR2_ClearITFlag(TMR1_2_IT_DMA_END);
    PFIC_EnableIRQ(TMR2_IRQn);
    TMR2_ITCfg(ENABLE, TMR1_2_IT_DMA_END);

#endif

    while(1);
}
例程中120000配置周期 2000us,是这样算的。T=1/T=1/60(Mhz)*120000=2000us,我们需要配置800Khz也就是1.25us的周期,可以这样子算:T=1/T=1/60(Mhz)*75=1.25us;最终我们可以修改其初始代码如下所示:

void WS2812B_Init(void)
{
    GPIOB_ModeCfg(GPIO_Pin_11, GPIO_ModeOut_PP_5mA);
    GPIOPinRemap(ENABLE, RB_PIN_TMR2);

    PRINT("TMR2 DMA PWM\n");
    TMR2_PWMCycleCfg(75); // 周期 1.25us

    TMR2_DMACfg(ENABLE, (uint16_t)(uint32_t)&PwmBuf, (uint16_t)(uint32_t)&PwmBuf, Mode_LOOP);
    TMR2_PWMInit(High_Level, PWM_Times_1);
    /* 开启计数溢出中断,计满1000个周期进入中断 */
    TMR2_ClearITFlag(TMR1_2_IT_DMA_END);
    PFIC_EnableIRQ(TMR2_IRQn);
    TMR2_ITCfg(ENABLE, TMR1_2_IT_DMA_END);

}因为这里开启了Mode_LOOP,也就是循环模式,那么就不用继续软件启动或开启DMA中断了。只需要刷新一下缓存区即可,这里缓存区使用四字节对齐方式,也是参考官方例程的,代码如下:#define PIXEL_NUM       16
#define NUM             (24*PIXEL_NUM + 300)      // Reset 280us / 1.25us = 224
#define WS1             37
#define WS0             18



__attribute__((aligned(4))) uint32_t PwmBuf;
uint32_t WS281x_Color(uint8_t red, uint8_t green, uint8_t blue) { return red << 16 | green << 8 | blue; }
uint32_t Wheel(uint8_t WheelPos)
{
    WheelPos = 255 - WheelPos;
    if (WheelPos < 85)
    {
      return WS281x_Color(255 - WheelPos * 3, 0, WheelPos * 3);
    }
    if (WheelPos < 170)
    {
      WheelPos -= 85;
      return WS281x_Color(0, WheelPos * 3, 255 - WheelPos * 3);
    }
    WheelPos -= 170;
    return WS281x_Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

void WS281x_SetPixelColor(uint16_t n, uint32_t GRBColor)
{
    uint8_t i;
    if (n < PIXEL_NUM)
    {
      for (i = 0; i < 24; ++i)
            PwmBuf = (((GRBColor << i) & 0X800000) ? WS1 : WS0);
    }
}
void ws281x_rainbowCycle(uint8_t wait) {
uint16_t i, j;

for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< PIXEL_NUM; i++) {
       WS281x_SetPixelColor(i,Wheel(((i * 256 / PIXEL_NUM) + j) & 255));


    }
    DelayMs(10);
}
}其中wheel这是一个RGB颜色渐变算法,大家感兴趣自行学习了解。
最后在main函数中调用实现如下
int main()
{
    uint8_t len;

    SetSysClock(CLK_SOURCE_PLL_60MHz);

    /* 配置串口1:先配置IO口模式,再配置串口 */
    GPIOA_SetBits(GPIO_Pin_9);
    GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);      // RXD-配置上拉输入
    GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出,注意先让IO口输出高电平
    UART1_DefInit();
    WS2812B_Init();


    while(1)
    {
      ws281x_rainbowCycle(10);
    }
}
另外由于开启了DMA传输结束中断,所以需要定义中断回调函数,并清中断。__INTERRUPT
__HIGH_CODE
void TMR2_IRQHandler(void)
{

    if(TMR2_GetITFlag(TMR1_2_IT_DMA_END))
    {
      TMR2_ClearITFlag(TMR1_2_IT_DMA_END);

      /* DMA 结束 */
      /* 用户可自行添加需要的处理 */
    }
}在实现的过程中,我们发现工程编译时候,有些外设库是灰色的如下图

我们可以右键灰色的文件,如下图:

把需要用到的灰色文件参与编译即可。

最后我们一起欣赏一下RainbowCycle彩虹转盘效果:

https://www.bilibili.com/video/BV1P54y1K729/?vd_source=2bbde87de845d5220b1d8ba075c12fb0





alvpeg 发表于 2023-3-2 10:13

这个不如spi的驱动方式简单。            

kmzuaz 发表于 2023-3-2 10:23

这个dma如何快速修改pwm的占空比

chenci2013 发表于 2023-3-2 10:38

直接使用延时函数。            

bestwell 发表于 2023-3-2 10:46

怎么确定亮度怎么样?            

nomomy 发表于 2023-3-2 16:07

可以移植spi+dma的方式。            

houjiakai 发表于 2023-3-2 16:45

PWM DMA模式的效果可以吗?

tpgf 发表于 2023-3-7 16:52

WS2812难道不是通过spi接口实现控制的吗

lilijin1995 发表于 2023-3-7 17:11

tpgf 发表于 2023-3-7 16:52
WS2812难道不是通过spi接口实现控制的吗

我知道的有三种,看你需求

lilijin1995 发表于 2023-3-7 17:12

houjiakai 发表于 2023-3-2 16:45
PWM DMA模式的效果可以吗?

效果看视频

lilijin1995 发表于 2023-3-7 17:12

kmzuaz 发表于 2023-3-2 10:23
这个dma如何快速修改pwm的占空比

修改buffer

晓伍 发表于 2023-3-8 08:10

这个渐变色的效果是不是需要调制一下pwm的各项参数啊

八层楼 发表于 2023-3-8 08:22

alvpeg 发表于 2023-3-2 10:13
这个不如spi的驱动方式简单。

但是感觉控制起来更加的细腻直观

观海 发表于 2023-3-8 09:12

请问渐变色的控制原理是什么 三原色一点一点的加减吗?还是更加复杂的算法

guanjiaer 发表于 2023-3-8 09:31

观海 发表于 2023-3-8 09:12
请问渐变色的控制原理是什么 三原色一点一点的加减吗?还是更加复杂的算法 ...

我觉得 要是不讲究直接控制到什么颜色 这种方式倒是一个简单的办法

keaibukelian 发表于 2023-3-8 09:51

请问为什么有时候有些外设库是灰色的呢?

WoodData 发表于 2023-3-20 08:58

效果不错

Antecer 发表于 2023-7-7 17:34

渐变色有两种方式:
1. 三原色依次加减
2.HSV算法

这个用PWM+DMA驱动ws2812的方式,直接把bit位转换成PWM值的效率其实很低,建议查表,速度能提升6倍(实测过)
页: [1]
查看完整版本: CH582何以驱动WS2812,TIM之PWM DMA模式实现RainbowCycle效果So easy