基于STM32F103C8T6驱动WS2812彩灯模块点亮RGB灯
文章目录
- 一、WS2812模块简介
- 二、主要特点与LED特性参数
- 三、模块引脚定义
- 四、工作原理与数据协议
- 工作原理
- 数据协议
- 五、STM32F103C8T6驱动示例
- 总结
一、WS2812模块简介
WS2812是一个集控制电路与发光电路于一体的智能外控LED光源。其外型与一个5050LED灯珠相同,每个元件即为一个像素点。像素点内部包含了智能数字接口数据锁存信号整形放大驱动电路,还包含有高精度的内部振荡器和12V高压可编程定电流控制部分,有效保证了像素点光的颜色高度一致。
数据协议采用单线归零码的通讯方式,像素点在上电复位以后,DIN端接受从控制器传输过来的数据,首先送过来的24bit数据被第一个像素点提取后,送到像素点内部的数据锁存器,剩余的数据经过内部整形处理电路整形放大后通过DO端口开始转发输出给下一个级联的像素点,每经过一个像素点的传输,信号减少24bit。像素点采用自动整形转发技术,使得该像素点的级联个数不受信号传送的限制,仅仅受限信号传输速度要求。
LED具有低电压驱动,环保节能,亮度高,散射角度大,一致性好,超低功率,超长寿命等优点。将控制电路集成于LED上面,电路变得更加简单,体积小,安装更加简便。
二、主要特点与LED特性参数
- 特点
● 控制电路与RGB芯片集成在一个5050封装的元器件中,构成一个完整的外控像素点。
● 内置信号整形电路,任何一个像素点收到信号后经过波形整形再输出,保证线路波形畸变不会累加。
● 内置上电复位和掉电复位电路。
● 每个像素点的三基色颜色可实现256级亮度显示,完成16777216种颜色的全真色彩显示,扫描频率不低于400Hz/s。
● 串行级联接口,能通过一根信号线完成数据的接收与解码。
● 任意两点传传输距离在不超过5米时无需增加任何电路。
● 当刷新速率30帧/秒时,低速模式级联数不小于512点,高速模式不小于1024点。
● 数据发送速度可达800Kbps。
● 光的颜色高度一致,性价比高。 - LED参数
三、模块引脚定义
VCC | 输入电压正极 |
---|---|
GND | 输入电压负极 |
DI | 数据输入 |
DO | 数据输出,与下一联级的DI连接 |
四、工作原理与数据协议
工作原理
- 高度集成的像素级控制
WS2812 本质上是将一个小型控制器和 3 颗小功率 LED 集成在一起的智能光源。其封装内包含:
- 精密振荡器:提供约 800 kHz 的时钟参考,确保协议时序稳定;
- 数字移位寄存器:按顺序接收并锁存 24 bit 的颜色数据;
- 信号重塑单元:对接收到的微弱信号进行再生放大,保证后级级联时信号不失真;
- 恒流驱动模块:为 R、G、B 三色 LED 提供精确的驱动电流,保证色彩一致性;
- 信号重塑与级联能力
当第一颗 WS2812 接收到完整的 24 bit 数据并将其锁存后,余下的数据(即除自身所用的 24 bit 外)会被 信号重塑电路 放大并输出到 DOUT,引入下一级的 DIN 端。这一机制使得即使在长链(理论上可达数千点)中,每一级仍能收到清晰、符合时序的波形,无需额外的中继或放大器。
数据协议
- 单线编码
WS2812 只需一根数据线即可传输所有信息,协议利用“高电平时长”区分 0/1:
‘0’ 码:高电平约 0.35 µs(±150 ns),低电平约 0.8 µs,总周期 ≈ 1.25 µs;
‘1’ 码:高电平约 0.7 µs,低电平约 0.6 µs,总周期 ≈ 1.25 µs;
这种编码在高电平和低电平上都不归零于同一电平,不仅简化了硬件设计,还提升了抗抖动能力。
- 24 Bit 数据格式
每个像素点需要 24 bit,按 G7…G0 → R7…R0 → B7…B0 的顺序依次发送。例如,要显示纯绿(255,0,0),主控会发送:11111111 00000000 00000000;其中 11111111 对应十进制 255 的绿色通道,高位先发。
- 复位与数据锁存
在一连串 24 bit 数据发送完毕后,必须将数据线拉低 > 50 µs,WS2812 内部的移位寄存器才会被复位并将新接收的数据输出到 LED 驱动单元,否则会出现刷新失败。 - 总线级联
WS2812 拥有内置信号整形功能,能将余下的数据完整透传至下一级,无需中断或额外控制。这使得在同一根数据线下,可以串联数十、乃至上千颗 WS2812,主控只需一次完整的数据发送即可更新整条链。
通过上述工作原理与协议解读,在有多个led级联的情况下,先发送第一个led的数据,后第二个、第三个、以此类推。
五、STM32F103C8T6驱动示例
1.引脚接线
STM32F103C8T6 | WS2812 |
---|---|
5V | 5V,注意:如果多个级联要外接电源,不要用单片机的5V |
GND | GND |
PA0 | DI |
- 代码示例
WS2812.c
#include "ws2812.h"void WS2812_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_OCInitTypeDef TIM_OCInitStructure;DMA_InitTypeDef DMA_InitStructure;//使能 TIM2、DMA1 和 GPIOA 时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // TIM2 定时器时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // DMA1 总线时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // GPIOA 时钟GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);TIM_InternalClockConfig(TIM2);TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 90 - 1; //ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 0; //CCRTIM_OC1Init(TIM2, &TIM_OCInitStructure);DMA_DeInit(DMA1_Channel2);DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM2->CCR1;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)My_ws_buf;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;DMA_InitStructure.DMA_BufferSize = 0;DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_Init(DMA1_Channel2, &DMA_InitStructure);TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);
}/*** @brief 设置单颗 WS2812B 灯的 RGB 颜色(十进制 0–255)* @param r 红色分量,0 表示关闭,255 表示最大亮度* @param g 绿色分量,0 表示关闭,255 表示最大亮度* @param b 蓝色分量,0 表示关闭,255 表示最大亮度*/
void WS2812B_SetColor(uint32_t r, uint32_t g, uint32_t b)
{uint16_t *p = My_ws_buf; uint32_t mask, rep, bit; uint32_t GRB_Data;GRB_Data = ((g & 0xFFU) << 16)| ((r & 0xFFU) << 8)| (b & 0xFFU); for (rep = 0; rep < LED_REPEAT; rep++) {mask = 1UL << (BITS_PER_LED - 1);for (bit = 0; bit < BITS_PER_LED; bit++, mask >>= 1) {*p++ = (GRB_Data & mask) ? WS2812_HIGH : WS2812_LOW;}}
}//发送信号
void WS2812B_Send(void)
{//清除 DMA 标志、重载传输长度DMA_ClearFlag(DMA1_FLAG_TC2);DMA_SetCurrDataCounter(DMA1_Channel2, LED_REPEAT * BITS_PER_LED);//启动 DMA & 定时器DMA_Cmd(DMA1_Channel2, ENABLE);TIM_Cmd(TIM2, ENABLE);//等待传输完成while (!DMA_GetFlagStatus(DMA1_FLAG_TC2));//关闭 TIM & DMA 并清标志,产生 >50μs 复位低电平TIM_Cmd(TIM2, DISABLE);DMA_Cmd(DMA1_Channel2, DISABLE);DMA_ClearFlag(DMA1_FLAG_TC2);
}void ws2812_OFF(void)
{WS2812B_SetColor(0, 0, 0);WS2812B_Send();
}
main.c
#include "stm32f10x.h" // Device header
#include "ws2812.h"
#include "delay.h"static const uint8_t color_list[][3] = {{255, 0, 0}, // 红{255, 125, 0}, // 橙{255, 255, 0}, // 黄{ 0, 255, 0}, // 绿{ 0, 255, 255}, // 青{ 0, 0, 255}, // 蓝{255, 0, 255}, // 紫{ 0, 0, 0} // 关灯
};uint16_t NUM_COLORS = sizeof(color_list) / sizeof(color_list[0]);
uint32_t idx = 0;int main(void)
{WS2812_Init();
// ws2812_OFF();while(1){uint8_t r = color_list[idx][0];uint8_t g = color_list[idx][1];uint8_t b = color_list[idx][2];WS2812B_SetColor(r, g, b);WS2812B_Send();Delay_ms(1000);idx = (idx + 1) % NUM_COLORS;}
}
- 效果展示
总结
WS2812 是一款将控制电路、信号整形放大和恒流驱动与 RGB 发光单元集成于 5050 封装中的智能化全彩 LED 模块,仅需一根数据线即可以 800 kbps 单线协议传输精确的色彩控制信号,从而实现链式级联上千点的独立寻址与显示。内部集成的数字移位寄存器与精密振荡器可按 GRB 顺序(G7…G0→R7…R0→B7…B0)接收并锁存 24 bit 颜色数据,随后通过恒流驱动电路根据不同位的高低电平宽度产生对应亮度,并将余下数据重塑后输出到下一颗,实现信号级联。可广泛应用于灯带、灯环、可穿戴灯效、舞台装饰等场景。
注意事项:
- 严格时序控制:软件模拟易受中断或系统抖动影响,易导致亮度不稳定或色偏,推荐使用定时器+DMA、SPI 或 RMT(ESP32)等硬件外设生成 PWM 波形,以确保 T0H/T1H 与 T0L/T1L 宽度的高精度。
- 复位低电平:发送完 24 bit 数据后,必须将数据线保持低电平 > 50 µs,WS2812 内部才会将新数据锁存并更新输出;低于此时长可能导致刷新失败或出现残影。
- 链式级联能力:得益于内部信号整形,单线级联可支持 ≥ 1 024 个像素刷新(30 fps 条件下);在更高刷新率或更长链长场景下,建议分段布线并选用多路输出或并行总线以降低时延和信号累积失真。
以上仅为个人观点供参考,如有问题欢迎大家留言讨论,如需源码可点赞收藏加关注,在评论留下邮箱获取!!!