本帖最后由 阿源玩电子 于 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.点亮效果
|
打赏榜单
ArteryMCU 打赏了 20.00 元 2025-07-04 理由:[M412开发板评测活动]内容优质
|