[蓝牙芯片]CH582何以驱动WS2812,TIM之PWM DMA模式实现RainbowCycle效果So easy

      在我们游乐和电脑、游戏外设行业,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[i]=2400*i;

    }

    for(i=50; i<100; i++)

    {

      PwmBuf[i]=2400*(100-i);

    }

    TMR2_DMACfg(ENABLE, (uint16_t)(uint32_t)&PwmBuf[0], (uint16_t)(uint32_t)&PwmBuf[100], 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[0], (uint16_t)(uint32_t)&PwmBuf[NUM], 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[NUM];

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[24 * n + i] = (((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 结束 */

        /* 用户可自行添加需要的处理 */

    }

}

在实现的过程中,我们发现工程编译时候,有些外设库是灰色的如下图


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

把需要用到的灰色文件参与编译即可。
---------------------
作者:lilijin1995
链接:https://bbs.21ic.com/icview-3283418-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个示例代码,用于通过 CH582M 控制 WS2812C 灯带: ```C #include <ch582m.h> // 定义灯带的像素数量 #define NUM_LEDS 10 // 定义引脚 #define DATA_PIN 2 // 定义颜色结构体 typedef struct { uint8_t r; uint8_t g; uint8_t b; } RGBColor; // 定义灯带颜色数组 RGBColor leds[NUM_LEDS]; // 初始化 CH582M void ch582m_init() { CH582M_Init(); } // 发送颜色数据到灯带 void ch582m_sendData() { uint8_t i; for (i = 0; i < NUM_LEDS; i++) { CH582M_WriteByte(leds[i].g); CH582M_WriteByte(leds[i].r); CH582M_WriteByte(leds[i].b); } } // 设置指定像素的颜色 void setPixelColor(uint8_t index, uint8_t r, uint8_t g, uint8_t b) { leds[index].r = r; leds[index].g = g; leds[index].b = b; } // 清除所有像素的颜色 void clearPixels() { uint8_t i; for (i = 0; i < NUM_LEDS; i++) { setPixelColor(i, 0, 0, 0); } } int main() { // 初始化 CH582M ch582m_init(); // 清除所有像素的颜色 clearPixels(); // 设置指定像素的颜色 setPixelColor(0, 255, 0, 0); // 设置第一个像素为红色 setPixelColor(1, 0, 255, 0); // 设置第二个像素为绿色 setPixelColor(2, 0, 0, 255); // 设置第三个像素为蓝色 // 发送颜色数据到灯带 ch582m_sendData(); return 0; } ``` 这是一个简单的示例代码,用于控制 CH582M 控制器通过单总线协议发送颜色数据到 WS2812C 灯带。您可以根据需要修改像素数量、引脚定义以及设置每个像素的颜色。请确保您已正确安装 CH582M 的驱动和相关库,并将代码适配到您的开发环境中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值