CH32幻彩灯控 - WS2812及同等类型灯珠的四种驱动方式
创作时间:
作者:
@小白创作中心
CH32幻彩灯控 - WS2812及同等类型灯珠的四种驱动方式
引用
1
来源
1.
https://www.cnblogs.com/wchmcu/p/18260676
当下ARGB(Addressable RGB)盛行,用CH32也可轻松施展灯光魔法;以CH32X035为例分析驱动WS2812幻彩LED灯珠的四种方式。
WS2812时序
WS2812是集控制电路与发光电路于一体的LED,采用单线数据协议,每24bit数据控制总线上的一颗LED。但此处的bit不等同于二进制中的位,它由自己的一段时序代表最小的信息量单位,分别为0码和1码,还有Reset码,典型时序如下图:
24bit 的数据结构为每 8bit 控制一种颜色, bit[23:16] 代表 Green 绿色,灰度为0255, bit[15:8] 代表 Red 红色, bit[7:0] 代表 Blue 蓝色,同理灰度都为0255;在发送数据时按照GRB的顺序高位先发。
方式一,IO翻转驱动
- IO初始化,配置GPIO为推挽输出,初始化为低电平;
- IO翻转的时间,通过写寄存器的方式来翻转IO电平,逻辑分析仪测量CH32X035在48M主频下的IO翻转的时间如下,高电平执行时间45ns,低电平执行时间40ns;
- 控制输出时序;
void WS2812_0(void) // 输出0码
{
/* T0H - 300ns , T0L - 600ns */
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF); // 高电平时间 45ns
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BCR = GPIO_Pin_0; // 低电平时间 40ns
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
}
void WS2812_1(void) // 输出1码
{
/* T1H - 600ns , T1L - 600ns */
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF); // 高电平时间 45ns
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BSHR = (GPIO_Pin_0 & (uint32_t)0x0000FFFF);
GPIOA->BCR = GPIO_Pin_0; // 低电平时间 40ns
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
GPIOA->BCR = GPIO_Pin_0;
}
void WS2812_Reset(void) // 输出Reset码
{
/* RES 低电平280us以上 */
GPIOA->BCR = GPIO_Pin_0;
Delay_Us(300);
}
- 调用以上函数组成IO输出的时序,控制RGB色彩;
方式二,定时器PWM+DMA驱动
- 定时器初始化,重装载值(10-1);预分频值(6-1);可得PWM频率 800K Hz,PWM选择模式1,输出极性配置为高,即低于比较值时输出有效电平,且有效电平为高;
void TIM1_PWMOut_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure={0};
TIM_OCInitTypeDef TIM_OCInitStructure={0};
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure={0};
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure );
TIM_TimeBaseInitStructure.TIM_Period = 10-1;
TIM_TimeBaseInitStructure.TIM_Prescaler = (SystemCoreClock/8000000)-1; // 800K Hz
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性高
TIM_OC1Init( TIM1, &TIM_OCInitStructure );
TIM_OC1PreloadConfig( TIM1, TIM_OCPreload_Enable ); ///通道1
TIM_ARRPreloadConfig( TIM1, ENABLE );
TIM_Cmd( TIM1, ENABLE );
}
- DMA初始化,DMA方向为内存到外设,即将比较值从内存搬运至定时器的比较寄存器;DMA传输数据宽度为半字,且不开启循环模式,
- 使能PWM输出;
- 使能DMA传输修改定时器比较值来控制PWM占空比,PWM周期为1250ns,根据每bit数据决定PWM输出的占空比,来控制输出0码(高电平30%,低电平70%)或1码(高电平50%,低电平50%);
方式三,SPI驱动
- SPI初始化,主机模式,数据宽度8位,每字节控制WS2812的一个bit(最小时序码),即24字节控制一颗LED;
- 设置RGB的缓存,每24字节控制一颗灯珠,以输出三颗灯珠依此为为绿红蓝为例:
uint8_t SPI_Tx_Buffer[] = {
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x0F, // G - 0x01
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // R - 0x00
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // B - 0x00
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // G - 0x00
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x0F, // R - 0x01
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // B - 0x00
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // G - 0x00
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // R - 0x00
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x0F, // B - 0x01
};
- SPI发送,输出RGB
for(uint8_t i=0;i<(24*3);i++) // 每24字节控制一颗灯珠,共3颗
{
SPI_I2S_SendData(SPI1, SPI_Tx_Buffer[i]);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);
}
Delay_Us(300); // Reset
方式四,PIOC驱动
CH32X035内嵌了一个可编程协议IO微控制器,可实现单线输出;
- 设置RGB缓存,以三颗灯珠为例;
u8 RGBpbuf[] = {
0x01, 0x00, 0x00, // G-R-B
0x00, 0x01, 0x00,
0x00, 0x00, 0x01,
};
- 输出通道初始化,若选择PC18或PC19为输出通道,则须先关闭PC18和PC19默认的 SWD 功能;
- 根据缓存输出RGB
uint16_t total_bytes;
u8* RGB_RAM;
RGB1W_Init( );
stat = 0x80;
while(1)
{
total_bytes = rgb_data_bytes;
Delay_Ms(200);
stat = 0x80;
if ( stat != 0xFF )
{
if ( stat < 0x80 )
{
if ( stat == RGB1W_ERR_OK ) printf("1-wire finished\r\n");
else printf("1-wire error %02x\r\n", stat);
stat = 0x80; // free
}
if ( stat == 0x80 && total_bytes )
{ //RAM mode for 1~3072 bytes data
stat = 0xFF; // wait
RGB_RAM = RGBpbuf;
RGB1W_SendRAM( total_bytes, RGB_RAM ,0);
total_bytes = 0;
}
}
if ( PIOC->D8_SYS_CFG & RB_INT_REQ ) { // query if disable interrupt
stat = PIOC->D8_CTRL_RD; // auto remove interrupt request after reading
}
}
总结
四种方式均可驱动WS2812及其同等类型的LED灯珠,可根据引脚资源和具体应用环境自由选择,以CH32X035为例参考程序如下:
热门推荐
质量成本管理怎么实施?
赴美留学限制专业?哪些专业受影响?如何应对?
作为中国最古老的集体运动,蹴鞠有着什么样的发展?
4种药吃久了,可能导致记忆力减退或痴呆,要谨慎服用
甘草在中药方里面起什么作用
互联网医院创新康复咨询模式 助力患者重返健康生活
对人体健康至关重要——铜的趣话
一起认识|潮州工夫茶的四位非遗传人
为什么我做了 PET/CT 后还需做 CT 增强检查?
北证50指数三连涨 北交所整体换手率已呈现新变化
注释方式如何提高代码可读性
2025年一建《机电工程管理与实务》重点考点清单
SQL中INSTR函数的使用方法详解
大肠癌前兆有哪些?从早期到晚期,专业医师带你全面认识大肠癌
甜蜜的陷阱:果糖如何成为癌症的帮凶
水卡过户流程是怎样的?操作步骤有哪些?
食品厂“全透明”生产!数字孪生+PLC,卫生抽查一次过关!
不用手机接收验证码的五种方法
到底谁还再给浴室装百叶帘?看看人家的做法,又省钱又实用
诸葛亮的八阵图:传奇阵法的历史之谜
金粉世家:看冷清秋被迁怒才明白,金家除了她,其他人都是伪君子
人工智能对生活的影响:重塑日常、提升效率与创造新机遇
法院诉前调解化纠纷:安装摄像头引发的邻里矛盾如何化解?
工业化对世界人民福祉的重要意义
减肥期间每日适合摄入多少卡路里
个人申请工伤赔偿流程及时间规定是什么
十几秒拍摄可收获一个3D真人手办
家庭急救割伤的处理方法是什么
从中轴线到古建筑,一览中华文明之美 | 云品好书
如何写重点项目标题:15个关键步骤