本帖最后由 阿源玩电子 于 2025-6-22 18:40 编辑
#申请原创#
TIM3+DMA方式驱动WS2812色环
WS2812介绍
WS2812智能LED通过单线NRZ(Non-Return-to-Zero)通信协议传输数据,每个LED需要接收24位(3字节)数据,分别对应G(绿色)、R(红色)、B(蓝色)三种颜色的亮度值(每种颜色8位)。
2.WS2812通信时序详解
典型时序参数: - 逻辑"1": 高电平约800ns,低电平约450ns
- 逻辑"0": 高电平约400ns,低电平约850ns
- 每个bit周期固定为1.25μs (±150n)
3.通信思路
定时器+PWM实现:
- 使用PWM占空比区分逻辑1和逻辑0
- 设置PWM周期为1.25μs
- 逻辑1:占空比64%(800ns高电平)
- 逻辑0:占空比32%(400ns高电平)
4.AT32_Work_Bench工程配置
5.生成工程
定义WS2812.h文件
#ifndef __WS2812_H
#define __WS2812_H
#include "at32m412_416.h" // 使用AT32 MCU的硬件驱动头文件
// ====================
// 硬件相关配置定义
// ====================
/* WS2812数据位时序定义 */
#define RGB_led_bit_1 121 // 逻辑"1"的PWM比较值
#define RGB_led_bit_0 61 // 逻辑"0"的PWM比较值
/* LED灯带配置 */
#define led_data_length 24 // 每个LED需要24位数据(GRB各8位)
#define RGB_PIXEL_NUM 24 // 最大支持LED数量
// ====================
// 数据结构定义
// ====================
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] WS2812数据缓冲区的联合体定义
*
* 使用二维数组存储所有LED的24位数据:
* - 第一维: LED索引(0~RGB_PIXEL_NUM-1)
* - 第二维: 24位数据(8位G + 8位R + 8位B)
*/
typedef union _rgbPixelBuffer {
uint16_t All_Buffer[RGB_PIXEL_NUM][led_data_length];
} RGB_PixelBuffer, *PRGB_PixelBuffer;
// ====================
// 全局变量声明
// ====================
extern RGB_PixelBuffer RGB_Buffer; // 全局数据缓冲区
// ====================
// 函数声明
// ====================
void WS2812_Update(void);
void RGB_Write_Led_Bit(uint32_t RGB, uint16_t Index);
void RGB_Write_Led_Bit_AllLedSame(uint32_t RGB, uint16_t numLeds);
#endif /* __WS2812_H */
定义WS2812.c文件
#include "ws2812.h"
RGB_PixelBuffer RGB_Buffer={0};
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] 设置特定LED的RGB颜色。
* @param RGB: 组合后的RGB颜色值,格式为0x00RRGGBB。
* @param Index: 要写入的LED索引。
* @retval None.
*/
void RGB_Write_Led_Bit(uint32_t RGB, uint16_t Index) {
uint16_t led_index = Index;
uint8_t green= (RGB >> 16);
uint8_t red= (RGB >> 8);
uint8_t blue = RGB;
for (uint8_t n = 0; n < 8; n++) {
RGB_Buffer.All_Buffer[led_index][0 * 8 + n] = (red & (0x80 >> n)) ? RGB_led_bit_1 : RGB_led_bit_0;
RGB_Buffer.All_Buffer[led_index][1 * 8 + n] = (green & (0x80 >> n)) ? RGB_led_bit_1 : RGB_led_bit_0;
RGB_Buffer.All_Buffer[led_index][2 * 8 + n] = (blue & (0x80 >> n)) ? RGB_led_bit_1 : RGB_led_bit_0;
}
}
/**
* @brief 同时点亮所有LED为相同的RGB颜色。
* @param RGB: 组合后的RGB颜色值,格式为0x00RRGGBB。
* @param numLeds: LED的数量。
* @retval None.
*/
void RGB_Write_Led_Bit_AllLedSame(uint32_t RGB, uint16_t numLeds) {
for (uint16_t i = 0; i < numLeds; i++) {
RGB_Write_Led_Bit(RGB, i);
}
}
// 启动DMA传输
void WS2812_Update(void) {
if((dma_data_number_get(DMA1_CHANNEL1) != 0))
{
return;
}else
{
tmr_channel_value_set(TMR3, TMR_SELECT_CHANNEL_1, 0);
tmr_counter_enable(TMR3, FALSE);
dma_channel_enable(DMA1_CHANNEL1, FALSE);
dma_data_number_set(DMA1_CHANNEL1, (RGB_PIXEL_NUM * 24));
dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
tmr_dma_request_enable(TMR3, TMR_C1_DMA_REQUEST, TRUE);
dma_channel_enable(DMA1_CHANNEL1, TRUE);
tmr_counter_enable(TMR3, TRUE);
}
}
DMA中断处理
void DMA1_Channel1_IRQHandler(void)
{
/* add user code begin DMA1_Channel1_IRQ 0 */
if (dma_flag_get(DMA1_FDT1_FLAG) != RESET)
{
tmr_dma_request_enable(TMR3, TMR_C1_DMA_REQUEST, FALSE);
tmr_channel_value_set(TMR3, TMR_SELECT_CHANNEL_1, 0);
dma_channel_enable(DMA1_CHANNEL1, FALSE);
dma_flag_clear(DMA1_FDT1_FLAG);
}
/* add user code end DMA1_Channel1_IRQ 0 */
/* add user code begin DMA1_Channel1_IRQ 1 */
/* add user code end DMA1_Channel1_IRQ 1 */
}
6.波形检查(符合时序要求)
7.点亮效果
|