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)
|