0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

使用PWM+DMA的方式驱动WS2812B

冬至配饺子 来源:兆易创新GD32 MCU 作者:豪哥 2022-09-22 18:17 次阅读

1.实验简述

使用 PWM+DMA 的方式驱动 WS2812B,并每隔 800ms 随机显示不同颜色。

2.实验硬件

兆易创新GD32F310 MCU开发板套件

16*16 WS2812B

3.开发环境

keil 5.24.1

4.WS2812B讲解

WS2812B 是 WorldSemi 公司推出的外控集成 RGB LED 光源。

WS2812B 则是将控制 IC 和传统 RGB 结合到了一起,我们使用一条数据线即可驱动所有 RGB,另外也使得颜色控制的精度更高,同时也支持 RGB 灯组的单个 RGB 颜色控制,因此WS2812B 除了可以用于照明外,还能应用到办公楼外墙来作为屏幕进行广告宣传,此时每个WS2812B 就对应的是一个像素点。

WS2812B 数据协议采用单线归零码的通讯方式,像素点在上电复位以后,DIN 端接受从控制器传输过来的数据,首先送过来的 24bit 数据(红绿蓝各 8 位)被第一个像素点提取后,送到像素点内部的数据锁存器,剩余的数据经过内部整形处理电路整形放大后通过 DO端口开始转发输出给下一个级联的像素点,每经过一个像素点的传输,信号减少 24bit。

像素点采用自动整形转发技术,使得该像素点的级联个数不受信号传送的限制,仅仅受限信号传输速度要求。WS2812B 传输协议时序图如下:

poYBAGMsNVWAQH7zAADM5joxSaQ966.png

从时序图可以看到,二进制的 0 和 1 用周期相同的不同占空比的方波来表示(1 对应 68%占空比,0 对应 32%占空比),因此我们可以通过改变 PWM 的占空比来模拟出要传输的数据。因为WS2812B 协议对传输速度要求非常高,所以使用了 DMA+PWM 这种方法,在比较事件发生时,DMA 立即响应并将对应数据传输到比较寄存器中。

WS2812 的传输过程如下图:

pYYBAGMsNW-AVtv-AADBaJurDk0079.png

每经过一个 WS2812B,数据就被截走24bit。

WS2812B 的 24 位数据如下:

poYBAGMsNYGAP6aaAAAxzrIMkG8565.png

数据按照高位在前的顺序分别输出绿色,红色和蓝色控制数据。在这里我们顺便说一下RGB 的取色原理。RGB 由三种基本色构成,分别是红,绿,蓝,也叫加法三原色,通过这三种颜色的不同比例可以组合出各种颜色,而不同比例可以通过 PWM 的占空比来实现。如果想要特定颜色,可以使用调色板取色,如下图:

pYYBAGMsNZOAV_rJAADml-OVVdM997.png

5.实验步骤

1、获取demo工程,任意选中一个工程用来修改实现PWM+DMA控制WS2812B 功能

pYYBAGMsNaSADPLCAABevuiTaP8394.png

2、添加需要的头文件和宏定义

poYBAGMsNbuAHSAEAABkINLUKwI266.png

TIMER0_CH0CC为定时器1的CH0通道比较输出的地址。

num为要控制ws2812B的数量,这里我们只控制1个。

3、定义需要的变量和声明需要的初化函数

pYYBAGMsNcyAAkPdAABK6V0HIbk666.png

RGB_buffer数组用来存放占空比数值。

4、配置PWM输出引脚

poYBAGMsNeCAPXqGAACDBOJvEKs372.png

5、配置定时器0通道0输出PWM

`void timer_config(void)
{

timer_oc_parameter_struct timer_ocintpara;
timer_parameter_struct timer_initpara;

rcu_periph_clock_enable(RCU_TIMER0);
timer_deinit(TIMER0);
/* TIMER0 configuration */
timer_initpara.prescaler         = 0;
timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection  = TIMER_COUNTER_UP;
timer_initpara.period            = 89;
timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER0, &timer_initpara);
/* CH0 configuration in PWM0 mode */
timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
timer_ocintpara.outputnstate = TIMER_CCXN_ENABLE;
timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_HIGH;
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocintpara);
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0,0);
timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_ENABLE);
/* TIMER0 primary output enable */
timer_primary_output_config(TIMER0, ENABLE);
/* TIMER0 CH0D DMA request enable */
timer_dma_enable(TIMER0, TIMER_DMA_CH0D);
/* auto-reload preload enable */
//timer_auto_reload_shadow_enable(TIMER0);
    timer_auto_reload_shadow_disable(TIMER0);
/* TIMER0 counter enable */
timer_enable(TIMER0);

}`

6、DMA配置

`void dma_config(void)
{

dma_parameter_struct dma_init_struct;

/* enable DMA clock */
rcu_periph_clock_enable(RCU_DMA);

/* initialize DMA channel1 */
dma_deinit(DMA_CH1);

/* DMA channel1 initialize */
dma_deinit(DMA_CH1);
dma_init_struct.direction    = DMA_MEMORY_TO_PERIPHERAL;
dma_init_struct.memory_addr  = (uint32_t)RGB_buffer;
dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
dma_init_struct.number       =sizeof(RGB_buffer);
dma_init_struct.periph_addr  = (uint32_t)TIMER0_CH0CC;
dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
dma_init_struct.priority     = DMA_PRIORITY_HIGH;
dma_init(DMA_CH1, &dma_init_struct);
/* configure DMA mode */
    dma_circulation_disable(DMA_CH1);
dma_memory_to_memory_disable(DMA_CH1);
/* enable DMA channel1 */
dma_channel_enable(DMA_CH1);

}`

7、通过PWM模拟WS2812B数据协议实现颜色设置

`void setRGB(uint8_t red,uint8_t green,uint8_t blue)
{
uint8_t i = 0,j =0;
uint32_t rgb_value = green<<16 | red<<8 | blue;

while(dma_flag_get(DMA_CH1, DMA_INTF_FTFIF)==RESET);
dma_flag_clear(DMA_CH1,DMA_INTC_FTFIFC);
dma_channel_disable(DMA_CH1);
dma_transfer_number_config(DMA_CH1,sizeof(RGB_buffer));
for(j=1;j<=num;++j)
{
for(i=0;i<24;++i)
{
  if((rgb_value<

}`

8、在主函数实现每隔 800ms 随机显示不同颜色功能。

`int main(void)
{

  systick_config();
gpio_config();
dma_config();
timer_config();
usart0_gpio_config();
usart0_config();
/* print out */
printf("Hello world!\n\r");
while(1)
 {
     setRGB(rand()%256,rand()%256,rand()%256);
     delay_1ms(800);
    };

}`




审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • PWM
    PWM
    +关注

    关注

    114

    文章

    4823

    浏览量

    209564
  • MCU芯片
    +关注

    关注

    3

    文章

    200

    浏览量

    11128
  • WS2812B
    +关注

    关注

    1

    文章

    38

    浏览量

    1870
收藏 人收藏

    评论

    相关推荐

    什么是WS2812BWS2812B灯带是怎么连接的呢?

    WS2812B是一款全彩LED控制IC,单总线控制,何为单总线我的理解就是数据线在一根线上传输的控制方式就是单总线。
    的头像 发表于 07-08 14:53 6226次阅读
    什么是<b class='flag-5'>WS2812B</b>?<b class='flag-5'>WS2812B</b>灯带是怎么连接的呢?

    哪位大神有完整的STM32F205驱动WS2812B灯带的程序

    哪位大神有完整的STM32F205驱动WS2812B灯带的程序
    发表于 09-03 18:08

    使用ESP8266驱动WS2812B型RGB LED智能灯制作分享

    这个智能灯方案很不错,只用了一个无线WIFI esp8266芯片,驱动ws2812b型RGB LED,效果很赞,在群里看到的,特分享下,若是侵犯了版权,联系我删除就行了
    发表于 07-16 04:35

    WS2812B RGB全彩LED灯珠

    WS2812B RGB全彩LED灯珠,只需通过一根信号线控制多个灯显示,本教程使用X-CTR100控制器驱动WS2812灯环。原理WS2812B是一个集控制电路与发光电路于一体的智能外
    发表于 08-06 08:15

    使用DMA+PWM方式驱动ws2812

    :STM32 使用 DMA+PWM 方式驱动 ws2812(x4)附件:MDK5 示例工程一、DMA 的双缓存模式STM32 系列的 MCU
    发表于 12-06 08:24

    怎样使用硬件定时器PWM+DMA方式实现WS2812驱动

    WS2812驱动方式有哪几种?怎样使用硬件定时器PWM+DMA方式实现WS2812
    发表于 01-25 06:56

    怎样给WS2812B发送数据呢

    1. 对于写驱动来说WS2812B芯片手册主要就是看通讯。简单来说就是给WS2812B发送数据,数据就是RGB对应的值,先发高位,按照GRB的顺序发送数据。通常我们用高电平表示数字信号“1”,低电平
    发表于 02-22 06:51

    怎样使用PWM+DMA方式驱动WS2812B

    PWM+DMA 驱动 WS2812一、项目要求(主要目的)使用 PWM+DMA方式驱动
    发表于 02-22 06:42

    可以用SPI DMA驱动WS2812b吗?

    我打算用SPI DMA驱动WS2812b,请问这是可行的吗?还有如果我启动了SPI,可不可以只有MISO引脚有复用,其他引脚继续用作GPIO。
    发表于 08-18 07:42

    CH563驱动ws2812B使用SPI+DMA呢还是用PWM+DMA呢?

    CH563驱动ws2812B使用SPI+DMA呢还是用PWM+DMA呢?有没有大佬有例程的?评估版文件里面的程序(PWM
    发表于 10-17 08:02

    基于GD32F427开发板点亮WS2812B炫彩灯环的设计实现

    1、如何点亮WS2812B炫彩灯环呢  我有一个WS2812B炫彩灯环,搭配精选的背景  在玩过的板子上,我都要把它点亮。  关于WS2812B的介绍资料,网上有很多,这里就不细说了,只说重点:  
    发表于 11-25 15:51

    STM32使用LL库PWMDMA模式驱动ws2812

    STM32使用LL库PWMDMA模式驱动ws2812一、WS2812简介二、CUBEMX初始化代码配置一、
    发表于 11-30 10:21 63次下载
    STM32使用LL库<b class='flag-5'>PWM</b>的<b class='flag-5'>DMA</b>模式<b class='flag-5'>驱动</b><b class='flag-5'>ws2812</b>

    STM32F103C8T6+PWM+DMA驱动 WS2812灯带

    #STM32+PWM+DMA驱动 WS2812灯带#文章目录1.理论:2代码:理论:使用STM32F103C8T6驱动WS2812灯带,每个
    发表于 12-27 19:29 201次下载
    STM32F103C8T6+<b class='flag-5'>PWM+DMA</b><b class='flag-5'>驱动</b> <b class='flag-5'>WS2812</b>灯带

    STM32F1 DMA+PWM 控制WS2812B LED灯

    1. 对于写驱动来说WS2812B芯片手册主要就是看通讯。简单来说就是给WS2812B发送数据,数据就是RGB对应的值,先发高位,按照GRB的顺序发送数据。通常我们用高电平表示数字信号“1”,低电平
    发表于 12-28 19:11 72次下载
    STM32F1 <b class='flag-5'>DMA+PWM</b> 控制<b class='flag-5'>WS2812B</b> LED灯

    PWM+DMA 驱动 WS2812

    PWM+DMA 驱动 WS2812一、项目要求(主要目的)使用 PWM+DMA方式驱动
    发表于 12-28 19:14 107次下载
    <b class='flag-5'>PWM+DMA</b> <b class='flag-5'>驱动</b> <b class='flag-5'>WS2812</b>