本帖最后由 xiaoqi976633690 于 2022-12-4 10:38 编辑
MM32F0136 SPI轻松驱动WS2812
#申请原创#
本例程通过使用SPI2外设,波特率设置为8mhz,驱动WS2812。
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)
|
此文章已获得独家原创/原创奖标签,著作权归21ic所有,未经允许禁止转载。
|