本帖最后由 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[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 结束 */
/* 用户可自行添加需要的处理 */
}
}
在实现的过程中,我们发现工程编译时候,有些外设库是灰色的如下图
我们可以右键灰色的文件,如下图:
把需要用到的灰色文件参与编译即可。
最后我们一起欣赏一下RainbowCycle彩虹转盘效果:
|