打印
[MM32生态]

【EV Board (MM32L0136C7P)测评】+SPI轻松驱动WS2812

[复制链接]
1323|35
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 xiaoqi976633690 于 2022-12-4 10:38 编辑

MM32F0136  SPI轻松驱动WS2812
#申请原创#

本例程通过使用SPI2外设,波特率设置为8mhz,驱动WS2812


  • 初始化GPIO_PIN
void BOARD_InitPins(void)
{
    GPIO_Init_Type gpio_init;

    /* PA3 - UART2_RX. */
    gpio_init.Pins  = GPIO_PIN_3;
    gpio_init.PinMode  = GPIO_PinMode_In_Floating;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_init);
    GPIO_PinAFConf(GPIOA, gpio_init.Pins, GPIO_AF_1);

    /* PA2 - UART2_TX. */
    gpio_init.Pins  = GPIO_PIN_2;
    gpio_init.PinMode  = GPIO_PinMode_AF_PushPull;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_init);
    GPIO_PinAFConf(GPIOA, gpio_init.Pins, GPIO_AF_1);

    /* PB14 - SPI2_MISO. */
    gpio_init.Pins  = GPIO_PIN_14;
    gpio_init.PinMode  = GPIO_PinMode_In_Floating;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &gpio_init);
    GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_0);

    /* PB15 - SPI2_MOSI. */
    gpio_init.Pins  = GPIO_PIN_15;
    gpio_init.PinMode  = GPIO_PinMode_AF_PushPull;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &gpio_init);
    GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_0);
}

   2.SPI外设初始化

void SPI_1Lines_HalfDuplex_Init(void)
{

    /* Setup SPI module. */
    SPI_Master_Init_Type spi_init;
    spi_init.ClockFreqHz = BOARD_LOOP_SPI_FREQ;//24MHZ
    spi_init.BaudRate = BOARD_LOOP_SPI_BAUDRATE;//8MHZ
    spi_init.XferMode = SPI_XferMode_TxRx;
    spi_init.PolPha = SPI_PolPha_Alt3;
    spi_init.DataWidth = SPI_DataWidth_8b;
    spi_init.LSB = false;
    spi_init.AutoCS = true;
    SPI_InitMaster(BOARD_LOOP_SPI_PORT, &spi_init);

    /* Enable SPI. */
    SPI_Enable(BOARD_LOOP_SPI_PORT, true);

}


这里我们将SPI 频率设置为8Mhz从下图可以看出每bit占用125ns 一个byte是8x125=1000ns  
根据时序我们将
1110 0000 即0xE0 表示为WS2812的0
1111 1000 即0xF8 表示为WS2812的1
这里5个bit的1 实际是5*125=625 实际是不符合850ns的但是可以用。试过设置SPI频率的6mhz的话也就是每bit 166.666ns 但是所有数据都被识别为1,ws2812全部亮了。


   3.时钟初始化

void BOARD_InitBootClocks(void)
{
    CLOCK_ResetToDefault();
    CLOCK_BootToHSE48MHz();

    /* UART2. */
    RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_UART2, true);
    RCC_ResetAPB1Periphs(RCC_APB1_PERIPH_UART2);

    /* SPI2. */
    RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_SPI2, true);
    RCC_ResetAPB1Periphs(RCC_APB1_PERIPH_SPI2);

    /* GPIOA. */
    RCC_EnableAHBPeriphs(RCC_AHB_PERIPH_GPIOA, true);
    RCC_ResetAPB1Periphs(RCC_AHB_PERIPH_GPIOA);

    /* GPIOB. */
    RCC_EnableAHBPeriphs(RCC_AHB_PERIPH_GPIOB, true);
    RCC_ResetAPB1Periphs(RCC_AHB_PERIPH_GPIOB);
}
  4.WS2812驱动代码WS2812.C
/*
* WS2812.C
*
*  Created on: 2021年10月9日
*      Author: Administrator
*/

#include "board_init.h"
#include "WS2812.H"

/*******************************************************************************
* Function Name  : SPI_1Lines_HalfDuplex_Init
* Description    : Configuring the SPI for half-duplex communication.
* Input          : None
* Return         : None
*******************************************************************************/
u32 ws2812_led[led_cout]; //灯珠数量 一个存储24位rgb颜色
void SPI_1Lines_HalfDuplex_Init(void)
{

    /* Setup SPI module. */
    SPI_Master_Init_Type spi_init;
    spi_init.ClockFreqHz = BOARD_LOOP_SPI_FREQ;//24MHZ
    spi_init.BaudRate = BOARD_LOOP_SPI_BAUDRATE;//8MHZ
    spi_init.XferMode = SPI_XferMode_TxRx;
    spi_init.PolPha = SPI_PolPha_Alt3;
    spi_init.DataWidth = SPI_DataWidth_8b;
    spi_init.LSB = false;
    spi_init.AutoCS = true;
    SPI_InitMaster(BOARD_LOOP_SPI_PORT, &spi_init);

    /* Enable SPI. */
    SPI_Enable(BOARD_LOOP_SPI_PORT, true);

}
void WS2812_SET0(void)
{
    while ( SPI_STATUS_TX_FULL & SPI_GetStatus(BOARD_LOOP_SPI_PORT) )
    {}
    SPI_PutData(BOARD_LOOP_SPI_PORT, 0xE0);//1110 0000
}

void WS2812_SET1(void)
{
    while ( SPI_STATUS_TX_FULL & SPI_GetStatus(BOARD_LOOP_SPI_PORT) )
    {}
    SPI_PutData(BOARD_LOOP_SPI_PORT, 0xF8);//1111 1000
}

void Ws2812_Rest(void)
{
        u8 i = 60;
        while (i) //0.444*200=88.8us
        {
                    while ( SPI_STATUS_TX_FULL & SPI_GetStatus(BOARD_LOOP_SPI_PORT) )
    {}
    SPI_PutData(BOARD_LOOP_SPI_PORT, 0x00);
                i--;
        }
}

void ws2812_rgb(u8 ws_num, u8 r, u8 g, u8 b)
{

        u32 grb = 0;
        grb = g;
        grb <<= 8;
        grb |= r;
        grb <<= 8;
        grb |= b;
        ws2812_led[ws_num] = grb;
        //ws2812_rx(64);
}
//填充LED
void ws2812_rgb_all(u8 ws_count, u8 r, u8 g, u8 b)
{
        u8 i;
        u32 grb = 0;
        grb = g;
        grb <<= 8;
        grb |= r;
        grb <<= 8;
        grb |= b;
        for (i = 0; i < ws_count; i++)
        {
                ws2812_led[i] = grb;
        }
        
}

void ws2812_save(u8 ws_number, u8 r, u8 g, u8 b)
{
        u32 grb = 0;
        grb = g;
        grb <<= 8;
        grb |= r;
        grb <<= 8;
        grb |= b;
        ws2812_led[(ws_number - 1)] = grb;
}

/****************将保存的数组RGB数据发送到所有LED*******/
/******************************************************/
void ws2812_rx(u8 led_count)
{
        u8 a, i;
        for (a = 0; a < led_count; a++)
        {
                for (i = 0; i < 24; i++)
                {
                        if ((ws2812_led[a] & 0x800000) == 0)
                                WS2812_SET0();
                        else
                                WS2812_SET1();
                        ws2812_led[a] <<= 1;
                }
        }
        Ws2812_Rest();
}

void ws2812_clear_all(u8 ws_count)
{
        u8 i;
        u32 grb = 0;
        for (i = 0; i < ws_count; i++)
        {
                ws2812_led[i] = grb;
        }

}


/*
* WS2812.H
*
*  Created on: 2021年10月9日
*      Author: Administrator
*/

#ifndef USER_WS2812_H_
#define USER_WS2812_H_
#include "board_init.h"

#define led_cout 64
#define WS_ARRAY_SIZE (led_cout*3)


typedef  unsigned char u8;
typedef  unsigned int u32;

void SPI_1Lines_HalfDuplex_Init(void);
void WS2812_SET0(void);
void WS2812_SET1(void);
void Ws2812_Rest(void);
//设置第ws_num个灯珠的颜色rgb
void ws2812_rgb(u8 ws_num, u8 ws_r, u8 ws_g, u8 ws_b);

//设置前ws_count个灯珠颜色为rgb
void ws2812_rgb_all(u8 ws_count, u8 ws_r, u8 ws_g, u8 ws_b);

//将最新的ws_data[]数组中的值发送至WS2812B模块
//void ws2812_refresh(u8 ws_count);

//将rgb颜色值保存到第ws_number位数组内
void ws2812_save(u8 ws_number, u8 r, u8 g, u8 b);

//数组中的值发送至WS2812B模块
void ws2812_rx(u8 led_count);
//关闭所有LED
void ws2812_clear_all(u8 ws_count);

#endif /* USER_WS2812_H_ */
   main函数
/*
* Copyright 2021 MindMotion Microelectronics Co., Ltd.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "board_init.h"
#include "WS2812.H"


#define APP_SPI_BUF_LEN 16u /* SPI buffer for SPI tx. */
#define BOARD_DELAY_COUNT     10000u



void app_delay(uint32_t delay)
{
    for (uint32_t i = 0u; i < delay; i++)
    {
        for (uint32_t j = 0u; j < BOARD_DELAY_COUNT; j++)
        {
            __NOP();
        }
    }
}

int main(void)
{
    BOARD_Init();
    printf("spi_master_basic example.\r\n");
    /* Setup spi. */
    SPI_1Lines_HalfDuplex_Init();
                Ws2812_Rest();
                ws2812_rgb_all(8,1,0,0);
                ws2812_rx(8);
    while (1)
    {
                        ws2812_rgb_all(8,3,0,0);//将8颗LED的R,G,B的值写入缓存
                        ws2812_rx(8);//发送LED数据并显示
      app_delay(80);
                        
                  ws2812_rgb_all(8,2,1,0);//橙
                        ws2812_rx(8);
                        app_delay(80);
                        
                        ws2812_rgb_all(8,2,2,0);//黄
                        ws2812_rx(8);
                        app_delay(80);               
                        
                        ws2812_rgb_all(8,0,3,0);//绿
                        ws2812_rx(8);
                        app_delay(80);                                
                        
                        ws2812_rgb_all(8,0,3,3);//青
                        ws2812_rx(8);
                        app_delay(80);                                
                        
                        ws2812_rgb_all(8,0,0,3);//绿
                        ws2812_rx(8);
                        app_delay(80);                        
                        
                        ws2812_rgb_all(8,3,0,3);//绿
                        ws2812_rx(8);
                        app_delay(80);
                        
                        
                        ws2812_rgb(0,3,0,0);
                        ws2812_rgb(1,3,2,0);
                        ws2812_rgb(2,2,3,0);
                        ws2812_rgb(3,0,3,0);
                        ws2812_rgb(4,0,3,2);
                        ws2812_rgb(5,0,0,3);
                        ws2812_rgb(6,3,0,3);
                        ws2812_rgb(7,3,0,0);
                        ws2812_rx(8);
                        app_delay(1000);        
                        
                        //printf("spi_master_basic example.\r\n");

    }
}




显示效果,忽略中间有一个坏掉了

spi_master_basic.zip (305 KB)





使用特权

评论回复
沙发
kkzz| | 2022-12-6 12:48 | 只看该作者
完美的做法,会不会收到中断的干扰呢?

使用特权

评论回复
板凳
febgxu| | 2022-12-6 14:18 | 只看该作者
这个效果好,时间控制的非常精确了。

使用特权

评论回复
地板
iyoum| | 2022-12-6 18:28 | 只看该作者
这个不能使用spi+dma的形式吗?

使用特权

评论回复
5
xiaoqi976633690|  楼主 | 2022-12-6 20:17 | 只看该作者
iyoum 发表于 2022-12-6 18:28
这个不能使用spi+dma的形式吗?

可以用dma的,我这个没有做上来

使用特权

评论回复
6
weifeng90| | 2022-12-8 18:00 | 只看该作者
用PWM驱动比较实用

使用特权

评论回复
7
10299823| | 2022-12-9 22:31 | 只看该作者
延时可以驱动WS2812吗?              

使用特权

评论回复
8
xu@xupt| | 2022-12-10 13:22 | 只看该作者
感谢分享

使用特权

评论回复
9
tpgf| | 2023-1-3 10:36 | 只看该作者
WS2812也是非常经典的spi驱动的灯带芯片了

使用特权

评论回复
10
nawu| | 2023-1-3 11:07 | 只看该作者
如果用延时驱动ws2812的话 就太浪费资源了

使用特权

评论回复
11
aoyi| | 2023-1-3 11:15 | 只看该作者
WS2812RGBWS2812/2811只需一根信号线就能控制灯带上所有led

使用特权

评论回复
12
zljiu| | 2023-1-3 11:24 | 只看该作者
WS2812通过简单的外部接口、特有的级联方案便于利用MCU完成多个LED控制,极大简化了LED控制接口

使用特权

评论回复
13
gwsan| | 2023-1-3 11:55 | 只看该作者
WS2812B-2020是一个集控制电路与发光电路于一体的智能外控LED光源;其外型采用最新的molding封装工艺

使用特权

评论回复
14
tfqi| | 2023-1-3 12:04 | 只看该作者
WS2812芯片是采用单线归零码的通讯方式

使用特权

评论回复
15
Jacquetry| | 2023-1-5 17:14 | 只看该作者
iyoum 发表于 2022-12-6 18:28
这个不能使用spi+dma的形式吗?

可以用dma

使用特权

评论回复
16
timfordlare| | 2023-1-9 17:32 | 只看该作者
dma+spi组合最佳了。              

使用特权

评论回复
17
cemaj| | 2023-1-9 17:40 | 只看该作者
这个spi的速度怎么样              

使用特权

评论回复
18
jonas222| | 2023-1-10 19:49 | 只看该作者
可以使用延时进行判断的。              

使用特权

评论回复
19
i1mcu| | 2023-1-10 20:59 | 只看该作者
这个可以移植arduino的库吗?

使用特权

评论回复
20
kkzz| | 2023-1-10 21:38 | 只看该作者
需要连续使用spi写入数据吗?最大支持多少个led?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

34

主题

187

帖子

2

粉丝