7935|5

208

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

04.WS2812B驱动实现之SPI [复制链接]

1、简介

前面我们介绍了通过GPIO引脚和PWM结合DMA这两种方式来实现对WS2812B的驱动,本篇帖子我们就来介绍另外一种方式:通过MCU的SPI接口来驱动WS2812B,我们通过配置SPI的8个时钟周期满足WS2812B所需要的1位所占用的时间,通过发送的数据来控制WS2812B一位当中的高低电平占比来实现;通过SPI接口,我们仅需使用到MOSI一个引脚即可,下面我们来看看程序是如何配置和实现的。

 

2、主要程序代码

#define WS2812B_SPI_BIT_H   0xF8
#define WS2812B_SPI_BIT_L   0xC0

/*******************************************************************************
 * [url=home.php?mod=space&uid=159083]@brief[/url] * @param       
 * @retval      
 * [url=home.php?mod=space&uid=1020061]@attention[/url] *******************************************************************************/
static void WS2812B_Write24Bits(uint8_t R, uint8_t G, uint8_t B)
{
    for(uint8_t i = 0; i < 8; i++)
    {
        if((G << i) & 0x80)
        {
            RGB_BitBuffer[i + 0x00] = WS2812B_SPI_BIT_H;
        }
        else
        {
            RGB_BitBuffer[i + 0x00] = WS2812B_SPI_BIT_L;
        }
    }

    for(uint8_t i = 0; i < 8; i++)
    {
        if((R << i) & 0x80)
        {
            RGB_BitBuffer[i + 0x08] = WS2812B_SPI_BIT_H;
        }
        else
        {
            RGB_BitBuffer[i + 0x08] = WS2812B_SPI_BIT_L;
        }
    }

    for(uint8_t i = 0; i < 8; i++)
    {
        if((B << i) & 0x80)
        {
            RGB_BitBuffer[i + 0x10] = WS2812B_SPI_BIT_H;
        }
        else
        {
            RGB_BitBuffer[i + 0x10] = WS2812B_SPI_BIT_L;
        }
    }

    __disable_irq();

    for(uint8_t i = 0; i < 24; i++)
    {
        while(!(SPI_STAT(SPI1) & SPI_FLAG_TBE));
        SPI_DATA(SPI1)    =    RGB_BitBuffer[i];
    }

    __enable_irq();
}

……

/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
static void WS2812B_DisplayFullColor(void)
{
    static uint8_t Index = 0;
    static uint8_t Count = 0, Mode = 0;

    uint8_t R_TAB[65] =
    {
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 240, 220, 
        200, 180, 160, 140, 120, 100,  80,  60,  40,  20,   0,   0,   0,   0,   0,
          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0,   0,   0,   0,   0,   0,   0,  20,  40,  60,  80, 100, 120, 140,
        160, 180, 200, 220, 240
    };

    uint8_t G_TAB[65] =
    {
          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  20,  40,  60,
         80, 100, 120, 140, 160, 180, 200, 220, 240, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255
    };

    uint8_t B_TAB[65] =
    {
          0,  20,  40,  60,  80, 100, 120, 140, 160, 180, 200, 220, 240, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
        255, 255, 255, 255, 255, 255, 255, 255, 255, 240, 220, 200, 180, 160, 140,
        120, 100,  80,  60,  40,  20,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0,   0,   0,   0
    };

    uint8_t Step = 31, CountCOMP = 30;

    switch(Mode)
    {
        case 0: RGB_Gradient(0x00,0x00,0x00, 0x00,0x00,0xFF, Step); break;
        case 1: RGB_Gradient(0x00,0x00,0x00, 0x00,0xFF,0x00, Step); break;
        case 2: RGB_Gradient(0x00,0x00,0x00, 0xFF,0x00,0x00, Step); break;
        default: break;
    }

    for(uint8_t i = 0; i < 60; i++)
    {
        if(Mode != 3)
        {
            WS2812B_Write24Bits(RGB_TAB[Index][0], RGB_TAB[Index][1], RGB_TAB[Index][2]);

            Index = (Index + 1) % Step;     CountCOMP = 30;
        }
        else
        {
            WS2812B_Write24Bits(R_TAB[Index], G_TAB[Index], B_TAB[Index]);

            Index = (Index + 1) % 65;       CountCOMP = 60;
        }
    }

    if(Count++ == CountCOMP)
    {
        Count = 0;
        Index = 0;

        Mode = (Mode + 1) % 4;
    }
}

……

/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void WS2812B_Init(void)
{
    spi_parameter_struct spi_init_struct;

    rcu_periph_clock_enable(RCU_GPIOB);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
    gpio_af_set(GPIOB, GPIO_AF_6, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);

    rcu_periph_clock_enable(RCU_SPI1);

    spi_i2s_deinit(SPI1);
    spi_struct_para_init(&spi_init_struct);

    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_4;
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI1, &spi_init_struct);

    spi_fifo_access_size_config(SPI1, SPI_BYTE_ACCESS);

    spi_enable(SPI1);

    WS2812B_DisplayAllRed();    SysTick_DelayMS(500);
    WS2812B_DisplayAllGreen();  SysTick_DelayMS(500);
    WS2812B_DisplayAllBlue();   SysTick_DelayMS(500);

    TASK_Append(TASK_ID_WS2812B, WS2812B_DisplayFullColor, 50);
}

……

 

3、运行视频效果


 

 

4、时序控制截图:完美的波形

 

5、工程源码

Template_SPI.zip (391.89 KB, 下载次数: 149)

此帖出自GD32 MCU论坛

最新回复

good  详情 回复 发表于 2023-4-28 16:40
点赞(4) 关注(2)
个人签名We are a team and we work as a team !
 

回复
举报

7628

帖子

2

TA的资源

五彩晶圆(高级)

沙发
 

很详细,谢谢分享

此帖出自GD32 MCU论坛
 
个人签名

默认摸鱼,再摸鱼。2022、9、28

 
 

回复

7196

帖子

2

TA的资源

版主

板凳
 

这个效果好啊,估计幕布后面用的应该就是这种灯带!

此帖出自GD32 MCU论坛
 
 
 

回复

7

帖子

1

TA的资源

一粒金砂(中级)

4
 

这个效果很不错,代码很详细,学习了,谢谢分享!

此帖出自GD32 MCU论坛
 
 
 

回复

2

帖子

0

TA的资源

一粒金砂(初级)

5
 

sdafegg fea

此帖出自GD32 MCU论坛
 
 
 

回复

3

帖子

0

TA的资源

一粒金砂(初级)

6
 
good
此帖出自GD32 MCU论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表