1705|2

151

帖子

0

资源

一粒金砂(高级)

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

/*******************************************************************************
 * @brief * @param       
 * @retval      
 * @attention *******************************************************************************/
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;
    }

    __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、时序控制截图:完美的波形

1.png 2.png

 

5、工程源码

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

个人签名We are a team and we work as a team !

回复

5255

帖子

18

资源

五彩晶圆(中级)

很详细,谢谢分享

个人签名

默认摸鱼


回复

1058

帖子

0

资源

版主

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


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

查找数据手册?

EEWorld Datasheet 技术支持

最新文章 更多>>
    推荐帖子
    如何学习嵌入式系统(基于ARM平台)

    如何学习嵌入式系统(基于ARM平台)一、嵌入式系统的概念主要从三个方面上来理解。1、从硬件上,将基于CPU的处围器件,整合到CPU ...

    邀请小伙伴一起看直播,可随机获赠精美礼品!

    >>活动详情:有奖直播,煮酒数创客,看好创意如何发生! 【邀请有好礼】   即日起——11月12日,每邀请 5 名好友新关注 ...

    对于linux下system()函数的深度理解

    这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system() ...

    【GD32F350 都市青年家庭安防卫士 】第七贴 I2C驱动OV5640

    本帖最后由 传媒学子 于 2018-10-8 22:29 编辑 【GD32F350 都市青年家庭安防卫士 】第七贴 I2C驱动OV5640 很多朋友认为I2C ...

    MSP430单片机的8大输出方式

    1 输出模式0 输出模式:输出信号OUTx由每个捕获/比较模块的控制寄存器CCTLx中的OUTx位定义,并在写入该寄存器后立即更新。最终位 ...

    Qorvo IDP 新任总裁讨论射频、MEMS 和电源技术的未来

    在过去的两年里,Qorvo 取得了令人兴奋的进步,这些进步直接影响了您的设计。通过内部开发和收购,我们为智能家居、物联网、UWB ...

    关闭
    站长推荐上一条 1/9 下一条

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

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

    北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

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