STM407IGT6+WS2818灯带
WS2818驱动的时序要求如下:
STM32F407IGT6 是一款基于 ARM Cortex-M4 内核的高性能微控制器,具备丰富的外设接口。
以下是使用 STM32F407IGT6 控制 WS2812B 灯带的一些基本步骤:
硬件连接:
数据线:将 WS2812B 灯带的数据线连接到 STM32F407IGT6 的某个SPI TX引脚上,这个引脚需要配置为 SPI 输出模式。
电源:确保 WS2812B 灯带接收到合适的 5V(或其它规格要求的电压)电源供应,并注意共地连接。
限流电阻:可能需要在数据线上串联一个限流电阻,以防止过高的电流损坏 LED 或微控制器。
软件配置:
初始化 SPI:配置一个 GPIO 引脚作为 SPI 的 MOSI(主输出从输入)引脚,设置正确的 SPI 通讯参数(如时钟频率、CPOL、CPHA)以匹配 WS2812B 的要求。
定时器配置:WS2812B 对时序要求非常严格,因此需要配置一个定时器来生成精确的时间延迟。
编程控制:
数据缓冲区:创建一个数据缓冲区来存储每个 LED 的颜色值。
发送函数:编写一个函数来填充数据缓冲区,并将其发送到 WS2812B 灯带上。这个函数需要处理 WS2812B 的特定编码方式(通常是 GRB 格式)。
刷新函数:编写一个函数来触发 SPI 传输,将缓冲区中的数据发送到灯带上。
调试和测试:
初步测试:先尝试点亮一个或几个 LED,确保通信正常。
性能优化:根据需要优化 SPI 传输速率,以实现最佳性能。
功耗优化:如果功耗是一个考虑因素,可以调整时钟设置和电源管理策略。
以下是一个简化的代码示例,展示了如何初始化 SPI 和发送数据到 WS2812B 灯带:
WS2812.c
#include "WS2812.h"
//#include "tim.h" // 引入定时器头文件用于延时
SPI_HandleTypeDef hspi2;
uint8_t ws2812_data_buffer[WS2812_LED_NUM][24];
/**
* @Description 初始化SPI2用于WS2812
* @Param void
* @Return void
*/
void ws2812_SPI_Init(void) {
__HAL_RCC_SPI2_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 初始化 PB13 (SCK), PB15 (MOSI)
GPIO_InitStruct.Pin = GPIO_PIN_13 | GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// SPI2 初始化
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_1LINE;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; // 根据实际需求设置
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 7;
HAL_SPI_Init(&hspi2);
}
/**
* @Description 延时函数(基于HAL库的定时器)
* @Param {uint32_t ms} 延时毫秒数
* @Return void
*/
void delay_ms(uint32_t ms) {
HAL_Delay(ms);
}
/**
* @Description WS2812初始化
* @Param void
* @Return void
*/
void ws2812_Init(void) {
ws2812_SPI_Init();
delay_ms(WS2812_LED_NUM * 10);
}
/**
* @Description 通过SPI2发送数据
* @Param {uint8_t *data} 数据缓冲区指针
* {uint16_t length} 数据长度
* @Return void
*/
void ws2812_Send_Data(uint8_t *data, uint16_t length) {
HAL_SPI_Transmit(&hspi2, data, length, HAL_MAX_DELAY);
}
/**
* @Description 关闭所有灯光
* @Param void
* @Return void
*/
void ws2812_AllShutOff(void) {
uint16_t i;
uint8_t j;
for (i = 0; i < WS2812_LED_NUM; i++) {
for (j = 0; j < 24; j++) {
ws2812_data_buffer[i][j] = SIG_0;
}
}
ws2812_Send_Data((uint8_t *)ws2812_data_buffer, WS2812_LED_NUM * 24);
delay_ms(10 * WS2812_LED_NUM);
}
/**
* @Description 合并RGB值为24位
* @Param {uint8_t red, green, blue} RGB颜色值
* @Return {uint32_t} 24位RGB值
*/
uint32_t ws281x_color(uint8_t red, uint8_t green, uint8_t blue) {
return green << 16 | red << 8 | blue;
}
/**
* @Description 点亮所有灯
* @Param {uint8_t red, green, blue} RGB颜色值
* @Return void
*/
void ws2812_AllOpen(uint8_t red, uint8_t green, uint8_t blue) {
uint16_t i, j;
for (j = 0; j < WS2812_LED_NUM; j++) {
for (i = 0; i < 24; ++i) {
ws2812_data_buffer[j][i] =
(((ws281x_color(red, green, blue) << i) & 0X800000) ? SIG_1 : SIG_0);
}
}
ws2812_Send_Data((uint8_t *)ws2812_data_buffer, WS2812_LED_NUM * 24);
delay_ms(10);
}
ws2818.h
#ifndef __WS2812_H
#define __WS2812_H
#include "stm32f4xx_hal.h"
#define WS2812_LED_NUM 14
// 11111000 SIG_1 5/8 = 62.5%
// 11100000 SIG_0 3/8 = 37.5%
#define SIG_1 0XF8
#define SIG_0 0XC0
void ws2812_Init(void);
void ws2812_Send_Data(uint8_t *data, uint16_t length);
void ws2812_AllShutOff(void);
void ws2812_AllOpen(uint8_t red, uint8_t green, uint8_t blue);
#endif
测试代码
main.c
```c
#include "main.h"
#include "ws2812.h"
#include "./usart/bsp_debug_usart.h"
static void SystemClock_Config(void);
int main(void) {
HAL_Init();
SystemClock_Config(); // 配置时钟168MHz
DEBUG_USART_Config();
printf("start\r\n");
ws2812_Init();
ws2812_AllOpen(255,0,0);
printf("end\r\n");
while (1) {
// 点亮第一个LED为红色
ws2812_AllOpen(255,0,0);
HAL_Delay(1000);
// 点亮第二个LED为绿色
ws2812_AllOpen(0,255,0);
HAL_Delay(1000);
// 点亮第二个LED为蓝色
ws2812_AllOpen(0,0,255);
HAL_Delay(1000);
// 关闭所有LED
ws2812_AllShutOff();
HAL_Delay(1000);
}
}
/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 168000000
* HCLK(Hz) = 168000000
* AHB Prescaler = 1
* APB1 Prescaler = 4
* APB2 Prescaler = 2
* HSE Frequency(Hz) = 8000000
* PLL_M = 25
* PLL_N = 336
* PLL_P = 2
* PLL_Q = 7
* VDD(V) = 3.3
* Main regulator output voltage = Scale1 mode
* Flash Latency(WS) = 5
* @param None
* @retval None
*/
static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
while(1) {};
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
while(1) {};
}
/* STM32F405x/407x/415x/417x Revision Z devices: prefetch is supported */
if (HAL_GetREVID() == 0x1001)
{
/* Enable the Flash prefetch */
__HAL_FLASH_PREFETCH_BUFFER_ENABLE();
}
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/