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

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

3天内不再提示

瑞萨e2studio(28)----SPI 驱动WS2812灯珠

嵌入式单片机MCU开发 来源:嵌入式单片机MCU开发 作者:嵌入式单片机MCU开 2023-12-01 16:48 次阅读

概述

本文介绍了如何使用瑞萨RA微控制器,结合E2STUDIO配置工具和SPI通讯接口,来驱动和控制WS2812 LED灯带。这是一个集硬件连接、软件配置和编程开发于一体的综合性项目,目标是实现对LED灯带颜色和亮度的精确控制。

视频教学

[https://www.bilibili.com/video/BV14u4y1h7u6/]

样品申请

[https://www.wjx.top/vm/wBbmSFp.aspx#]

源码下载

[https://download.csdn.net/download/qq_24312945/88489756]

芯片级联方法

在这里插入图片描述
芯片在上电复位以后,接收DIN端打来的数据,接收够24bit后,DO端口开始转发数据,供下一个芯片提供输入数据。在转发之前,DO口一直拉低。此时灯珠将不接收新的数据,内置RGB芯片根据接收到的24bit数据后产生的不同占空比信号,展现不同亮度。如果DIN端输入信号为RESET信号,芯片将接收到的数据送显示,芯片将在该信号结束后重新接收新的数据,在接收完开始的24bit数据后,通过DO口转发数据,灯珠在没有接收到RESET码前,RGB亮度保持不变,当接收到80us以上低电平RESET码后,灯珠内部RGB芯片将根据刚才接收到的24bit数据后产生的不同占空比信号,展现不同亮度。
在这里插入图片描述

数据传输

在这里插入图片描述

24bit数据结构:
在这里插入图片描述

时序

时序波形图如下所示。
在这里插入图片描述

在这里插入图片描述

新建工程

在这里插入图片描述

软件准备

在这里插入图片描述

保存工程路径

在这里插入图片描述

芯片配置

本文中使用R7FA4M2AD3CFP来进行演示。

在这里插入图片描述

开始SPI配置

点击Stacks->New Stack->Connectivity->SPI (r_sci_spi)。

在这里插入图片描述

SPI属性配置

将SPI的配置速度设为7.5M,数据宽度设为8位。
CPHA配置为第二边沿采样;在第一个跳变沿时,MOSI在空闲状态保持高电平,而在第二个跳变沿,它会保持上一次传输的最终电平。由于发送数据的最后一位总是低电平,这样配置可以避免WS2812误判。CPOL设置为高,确保SCK在空闲时保持高电平状态。

在这里插入图片描述

时钟配置

SPI (r_sci_spi)的时钟来自PLCKA。
在这里插入图片描述

查询用户手册,配置7.5M频率需要PLCK主频为60M。

在这里插入图片描述

开发板上的外部高速晶振为12M,需要修改XTAL为12M,配置PCLKA为60MHz。

在这里插入图片描述
在这里插入图片描述

SPI配置

系统采用单总线协议,通过总线上高低电平的时长来区分逻辑0和1。WS2811工作在800kHz频率下,将SPI设置为6.4MHz—即其工作频率的8倍—可以确保每个字节(8位)正好对应一个逻辑位。在这种设置下,‘11111000’(0xF8)代表逻辑1,‘11000000’(0xC0)代表逻辑0。

在这里插入图片描述

由于瑞萨RA在SPI发送时候会拉高电平。

在这里插入图片描述

所以在发送的时候需要先发送8位低电平进行复位,复位时间最短位80us。
7.5MHz频率换算位时间位133.3ns,80us/133.3ns≈600位,为了确保复位成功,需发送700位的低电平数据,即发送700/8≈88字节数据。
所以定义显存数组为88+实际灯珠数量。

//灯条显存SPI数据缓存
uint8_t gWs2812bDat_SPI[WS2812B_AMOUNT * 24+88] = {0};

逻辑分析仪显示如下所示。
在这里插入图片描述

逻辑0下发送的数据为11000000’(0xC0)。
逻辑0下高电平位264ns。

在这里插入图片描述

逻辑0下低电平位800ns。

在这里插入图片描述

逻辑1下发送的数据为‘11111000’(0xF8)。
逻辑1下高电平位666ns。

在这里插入图片描述

逻辑1下低电平位400ns。

在这里插入图片描述

这种精确的时序配置和电平控制对于确保WS2812灯带的正确驱动至关重要,可以通过上述配置来优化SPI接口的性能,确保与WS2812的高效通信

CPHA配置

CPHA配置为第二边沿采样下数据传输结束如下所示。
在这里插入图片描述

CPHA配置为第二边沿采样下数据传输结束如下所示。
在这里插入图片描述

由于RESET Code为低电平,且要大于80us,所以数据传输完毕必须为低电平。

在这里插入图片描述

代码

在main.c中添加头文件。

#include "ws2812.h"

在main.c中添加函数申明和移位操作以及回调函数处理。

fsp_err_t err = FSP_SUCCESS;
volatile bool g_transfer_complete = false;
void sci_spi_callback (spi_callback_args_t * p_args)
{
    if (SPI_EVENT_TRANSFER_COMPLETE == p_args- >event)
    {
        g_transfer_complete = true;
    }
}

extern tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT];

void move_Front()
{
    uint8_t i;
    uint8_t temp[3];
    temp[0] = gWs2812bDat[0].R;
    temp[1] = gWs2812bDat[0].G;
    temp[2] = gWs2812bDat[0].B; 
    for (i = 0; i < WS2812B_AMOUNT-1; i++)
    {
        gWs2812bDat[i].R = gWs2812bDat[i+1].R;
        gWs2812bDat[i].G = gWs2812bDat[i+1].G;
        gWs2812bDat[i].B = gWs2812bDat[i+1].B;
    }
        gWs2812bDat[7].R = temp[0];
        gWs2812bDat[7].G = temp[1];
        gWs2812bDat[7].B = temp[2];
}

添加初始化显示。

err = R_SCI_SPI_Open(&g_spi0_ctrl, &g_spi0_cfg);
    assert(FSP_SUCCESS == err);

    sci_spi_extended_cfg_t sci_spi_extended_cfg_t1;
    WS2812B_Task();
    R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);

添加流水灯。

while (1)
    {
      WS2812B_Task();
      move_Front();
      R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MILLISECONDS);
    }

hal_entry.c

#include "hal_data.h"
#include "ws2812.h"
FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER

fsp_err_t err = FSP_SUCCESS;
volatile bool g_transfer_complete = false;
void sci_spi_callback (spi_callback_args_t * p_args)
{
    if (SPI_EVENT_TRANSFER_COMPLETE == p_args- >event)
    {
        g_transfer_complete = true;
    }
}

extern tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT];

void move_Front()
{
    uint8_t i;
    uint8_t temp[3];
    temp[0] = gWs2812bDat[0].R;
    temp[1] = gWs2812bDat[0].G;
    temp[2] = gWs2812bDat[0].B;
    for (i = 0; i < WS2812B_AMOUNT-1; i++)
    {
        gWs2812bDat[i].R = gWs2812bDat[i+1].R;
        gWs2812bDat[i].G = gWs2812bDat[i+1].G;
        gWs2812bDat[i].B = gWs2812bDat[i+1].B;
    }
        gWs2812bDat[7].R = temp[0];
        gWs2812bDat[7].G = temp[1];
        gWs2812bDat[7].B = temp[2];
}



/*******************************************************************************************************************//**
 * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function
 * is called by main() when no RTOS is used.
 **********************************************************************************************************************/
void hal_entry(void)
{
    /* TODO: add your own code here */
    err = R_SCI_SPI_Open(&g_spi0_ctrl, &g_spi0_cfg);
    assert(FSP_SUCCESS == err);

    sci_spi_extended_cfg_t sci_spi_extended_cfg_t1;
    WS2812B_Task();
    R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);

    while (1)
    {
      WS2812B_Task();
      move_Front();
      R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MILLISECONDS);
    }

#if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
#endif
}

/*******************************************************************************************************************//**
 * This function is called at various points during the startup process.  This implementation uses the event that is
 * called right before main() to set up the pins.
 *
 * @param[in]  event    Where at in the start up process the code is currently at
 **********************************************************************************************************************/
void R_BSP_WarmStart(bsp_warm_start_event_t event)
{
    if (BSP_WARM_START_RESET == event)
    {
#if BSP_FEATURE_FLASH_LP_VERSION != 0

        /* Enable reading from data flash. */
        R_FACI_LP- >DFLCTL = 1U;

        /* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
         * C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
#endif
    }

    if (BSP_WARM_START_POST_C == event)
    {
        /* C runtime environment and system clocks are setup. */

        /* Configure pins. */
        R_IOPORT_Open (&g_ioport_ctrl, g_ioport.p_cfg);
    }
}

#if BSP_TZ_SECURE_BUILD

FSP_CPP_HEADER
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();

/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
{

}
FSP_CPP_FOOTER

#endif

ws2812.c

/*
 * ws2812.c
 *
 *  Created on: 2023年10月31日
 *      Author: Administrator
 */

#include "ws2812.h"
#include "hal_data.h"
extern fsp_err_t err ;
extern volatile bool g_transfer_complete ;

//灯条显存SPI数据缓存
uint8_t gWs2812bDat_SPI[WS2812B_AMOUNT * 24+88] = {0};
//灯条显存
tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT] = {

//R    G      B
0XFF, 0X00, 0X00,   //0
0X00, 0XFF, 0X00,   //1
0X00, 0X00, 0XFF,   //2
0X00, 0XFF, 0XFF,   //3
0XFF, 0X00, 0XFF,   //4
0XFF, 0XFF, 0X00,   //5
0XFF, 0XFF, 0XFF,   //6
0X00, 0X00, 0X00,   //7
};

void WS2812b_Set(uint16_t Ws2b812b_NUM, uint8_t r,uint8_t g,uint8_t b)
{
    uint8_t *pR = &gWs2812bDat_SPI[88+(Ws2b812b_NUM) * 24 + 8];
    uint8_t *pG = &gWs2812bDat_SPI[88+(Ws2b812b_NUM) * 24];
    uint8_t *pB = &gWs2812bDat_SPI[88+(Ws2b812b_NUM) * 24 + 16];

    for(uint8_t i = 0; i <  8; i++) {
        if(g & 0x80) {
            *pG = CODE_1;
        }
        else {
            *pG = CODE_0;
        }
        if(r & 0x80) {
            *pR = CODE_1;
        }
        else {
            *pR = CODE_0;
        }
        if(b & 0x80) {
            *pB = CODE_1;
        }
        else {
            *pB = CODE_0;
        }
        r < <= 1;
        g < <= 1;
        b < <= 1;
        pR++;
        pG++;
        pB++;
    }
}
void WS2812B_Task(void)
{
    uint8_t dat = 0;
    for(int i=0;i< 88;i++)
    {
        gWs2812bDat_SPI[i]=0;

    }
    //将gWs2812bDat数据解析成SPI数据
    for(uint8_t iLED = 0; iLED < WS2812B_AMOUNT; iLED++)
    {
        WS2812b_Set(iLED, gWs2812bDat[iLED].R, gWs2812bDat[iLED].G, gWs2812bDat[iLED].B);
    }
    //总线输出数据

    /* Send the reset command */
    g_transfer_complete = false;
    err = R_SCI_SPI_Write(&g_spi0_ctrl, gWs2812bDat_SPI, sizeof(gWs2812bDat_SPI), SPI_BIT_WIDTH_8_BITS);
    assert(FSP_SUCCESS == err);
    /* Wait for SPI_EVENT_TRANSFER_COMPLETE callback event. */
    while (  g_transfer_complete==false)
    {
        ;
    }
//    //使总线输出低电平
//    g_transfer_complete = false;
//     err = R_SCI_SPI_Write(&g_spi0_ctrl, dat, 1, SPI_BIT_WIDTH_8_BITS);
//     assert(FSP_SUCCESS == err);
//     /* Wait for SPI_EVENT_TRANSFER_COMPLETE callback event. */
//     while (  g_transfer_complete==false)
//     {
//         ;
//     }

    //帧信号:一个大于50us的低电平
     R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
}

ws2812.h

/*
 * ws2812.h
 *
 *  Created on: 2023年10月31日
 *      Author: Administrator
 */

#ifndef WS2812_H_
#define WS2812_H_

#include < stdint.h >

//            编码 0 : 11000000
#define CODE_0      0xc0
//            编码 1 : 11111000
#define CODE_1      0xF8
/*ws2812b灯珠数量*/
#define WS2812B_AMOUNT      8

typedef struct
{
    uint8_t R;
    uint8_t G;
    uint8_t B;
} tWs2812bCache_TypeDef;

extern tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT];

void WS2812b_Set(uint16_t Ws2b812b_NUM, uint8_t r,uint8_t g,uint8_t b);
void WS2812B_Task(void);


#endif /* WS2812_H_ */

审核编辑 黄宇

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

    关注

    35

    文章

    22309

    浏览量

    86305
  • SPI
    SPI
    +关注

    关注

    17

    文章

    1706

    浏览量

    91578
  • 灯珠
    +关注

    关注

    0

    文章

    80

    浏览量

    18459
  • WS2812
    +关注

    关注

    0

    文章

    32

    浏览量

    6179
收藏 人收藏

    评论

    相关推荐

    e2studio(25)----电容触摸配置(2)

    e2studio(25)----电容触摸配置(2)
    的头像 发表于 08-21 15:50 926次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>e2studio</b>(25)----电容触摸配置(<b class='flag-5'>2</b>)

    STM32C0开发(1)----SPI 驱动WS2812

    本文介绍了如何使用STM32微控制器,结合STM32CubeMX配置工具和SPI通讯接口,来驱动和控制WS2812 LED带。这是一个集硬件连接、软件配置和编程开发于一体的综合性项目
    的头像 发表于 12-01 16:47 2567次阅读
    STM32C0开发(1)----<b class='flag-5'>SPI</b> <b class='flag-5'>驱动</b><b class='flag-5'>WS2812</b><b class='flag-5'>灯</b><b class='flag-5'>珠</b>

    e2studio(1)----芯片之搭建FSP环境

    视频教学 样品申请 请勿添加外链 e2studio软件 e2studio的集成开发环境,FSP 提供了众多可提高效率的工具,用于开发针对
    发表于 09-30 15:28

    stm32F767 控制WS2812的问题

    使用stm32F767 PWM+DMA控制108个WS2812, 第一个颜色有时不正常,其它
    发表于 08-19 17:43

    WS2812B RGB全彩LED

    WS2812B RGB全彩LED,只需通过一根信号线控制多个显示,本教程使用X-CTR100控制器驱动
    发表于 08-06 08:15

    为什么用树莓派驱动WS2812会不亮呢

    为什么用树莓派驱动WS2812会不亮呢?是什么原因?如何解决?
    发表于 01-18 06:11

    STM32F103C8T6+PWM+DMA驱动 WS2812

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

    e2studio(2)----GPIO输出

    本篇文章主要介绍如何使用e2studio单片机进行GPIO输出,并以LED显示。
    的头像 发表于 11-14 17:11 1294次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>e2studio</b>(<b class='flag-5'>2</b>)----GPIO输出

    e2studio(3)----GPIO输入检测

    本篇文章主要介绍如何使用e2studio单片机进行GPIO输出,并以LED显示。
    的头像 发表于 11-14 20:15 2794次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>e2studio</b>(3)----GPIO输入检测

    e2studio(8)----PWM

    本篇文章主要介绍如何使用e2studio单片机进行PWM输出。
    的头像 发表于 11-15 10:43 1184次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>e2studio</b>(8)----PWM

    e2studio(9)----EXIT

    本篇文章主要介绍如何使用e2studio单片机进行EXIT检测,之后通过按键形式以及的亮灭形式进行演示。
    的头像 发表于 11-15 10:53 1081次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>e2studio</b>(9)----EXIT

    e2studio(10)----DAC

    本篇文章主要介绍如何使用e2studio单片机进行DAC输出。
    的头像 发表于 11-15 10:59 1005次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>e2studio</b>(10)----DAC

    e2studio----DAC

    本篇文章主要介绍如何使用e2studio单片机进行DAC输出。
    的头像 发表于 11-02 16:13 1155次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>e2studio</b>----DAC

    e2studio----PWM

    本篇文章主要介绍如何使用e2studioRA MCU进行PWM输出。
    的头像 发表于 11-02 15:59 1291次阅读
    <b class='flag-5'>瑞</b><b class='flag-5'>萨</b><b class='flag-5'>e2studio</b>----PWM

    论如何使用WS2812以及类似

    ​  WS2812 LED,这是一种非常流行的可寻址RGB LED。每个WS2812 LED内部集成了控制电路,因此可以通过一个数据输入线来单独控制每一个LED的颜色和亮度。这种特
    的头像 发表于 09-30 15:11 450次阅读
    论如何使用<b class='flag-5'>WS2812</b>以及类似<b class='flag-5'>灯</b><b class='flag-5'>珠</b>