基于STM32的HAL库的WS2812幻彩灯带控制

1、使用STM32F103RCT6正点原子的mini开发板控制不同颜色的幻彩灯亮,实现的效果如下:

2、幻彩灯带介绍

WS2812幻彩灯带有三条接线,5V、GND和控制信号线,利用单片机的SPI引脚可以发出不同频率协议的脉冲即可实现对幻彩灯带的各个灯珠的颜色和亮灭的控制。

本实验幻彩灯购买链接:(1米长度)

https://item.taobao.com/item.htm?_u=o8bd2jve615&id=654130322772&pisk=gW731UgmZM-QKLw9XNTQmt9kvbqtReT5zT3JeUpzbdJ_NDnLO3RPZTbRv_JJrTXlEpKzdeQlIs18OaFB8zAPHOYR9ppRI7XdN4eQVe3rE914d6p8OavyI9WkVW9JULXRaMFTkrCCOUTPr-UYkl2rkiBnYL-zahRpt5dU1MzP0UTzH8mtzHaDP95uHuuEbCJ6ZQREYTJwbBpwaBuFUd-wgIHezTWy7FRpwYorz4PibId2T28yLh-wgIOyzUWP_5AWQB8yzbErTptvbNy16I-DNGM15BxH36JF9s_a2HoCOdVQtNjMvKzvI4uPSBf6GuIjoupVcpKvFOzt-UfwZOxAx-0hE_5f4hboLWBVZGXWJNPrYKSdp3bpjvoeievH0w-Zt25B4GbMJwySc1CMLnYOXlwp2eXhcKtUfR6lspBP-hk3BLIA6w-G3R3GF3jPJF7UQrjr-coq5su5mjYIV0te1CvAIeyqL5lERdFgsmoWYCOFa5ViV0te1CvYs5mDOHR6T_5..&skuId=4831138941464&spm=a1z09.2.0.0.7a5f2e8du891QX

3、幻彩灯带使用STM32单片机的硬件SPI+DMA实现驱动,具体cubeMX配置见文章:

基于cubeMX的STM32开启SPI及DMA_stm32cubemx spi dma-CSDN博客

具体电路连接为:幻彩灯带线有白色的接5V,中间信号线接SPI通信线的MOSI即PB5引脚,最后一条线接GND。

WS2812幻彩灯带驱动代码如下:

(1)ws2812.c

#include "ws2812.h"
#include "spi.h"
#include "dma.h"

// 常用的颜色
const RGBColor_TypeDef RED      = {30 ,0  ,  0};
const RGBColor_TypeDef GREEN    = {0  , 30,  0};
const RGBColor_TypeDef BLUE     = {0  ,  0, 30};
const RGBColor_TypeDef YELLOW   = { 30, 30,  0};
const RGBColor_TypeDef MAGENTA  = { 30,  0, 30};
const RGBColor_TypeDef BLACK    = {  0,  0,  0};
const RGBColor_TypeDef WHITE    = { 30, 30, 30};

//模拟bit码:0xC0 为 0,0xF8 为 1
const uint8_t code[]={0xC0,0xF8};
//灯颜色缓存区
RGBColor_TypeDef RGB_DAT[RGB_NUM];

//SPI底层发送接口,一次发24个字节,相当于1个灯
extern DMA_HandleTypeDef hdma_spi3_tx;
static void SPI_Send(uint8_t *SPI_RGB_BUFFER)
{
  /* 判断上次DMA有没有传输完成 */
	while(HAL_DMA_GetState(&hdma_spi3_tx) != HAL_DMA_STATE_READY);
  /* 发送一个(24bit)的 RGB 数据到 2812 */
	HAL_SPI_Transmit_DMA(&hspi3,SPI_RGB_BUFFER,24);  
}
//颜色设置函数,传入 ID 和 颜色,进而设置缓存区
void RGB_Set_Color(uint8_t LedId, RGBColor_TypeDef Color)  
{
  if(LedId < RGB_NUM)
	{
		RGB_DAT[LedId].G = Color.G;
		RGB_DAT[LedId].R = Color.R;
		RGB_DAT[LedId].B = Color.B;
	}
}
//刷新函数,将颜色缓存区刷新到WS2812,输入参数是指定的刷新长度
void RGB_Reflash(uint8_t reflash_num)
{
	static uint8_t RGB_BUFFER[24]={0};
	uint8_t dat_b,dat_r,dat_g;
	//将数组颜色转化为 24 个要发送的字节数据
	if(reflash_num>0 && reflash_num<=RGB_NUM)
	{
		for(int i=0;i<reflash_num;i++)
		{
			dat_g = RGB_DAT[i].G;
			dat_r = RGB_DAT[i].R;
			dat_b = RGB_DAT[i].B;
			for(int j=0;j<8;j++)
			{
				RGB_BUFFER[7-j] =code[dat_g & 0x01];
				RGB_BUFFER[15-j]=code[dat_r & 0x01];
				RGB_BUFFER[23-j]=code[dat_b & 0x01];
				dat_g >>=1;
				dat_r >>=1;
				dat_b >>=1;
			}
			SPI_Send(RGB_BUFFER);
		}
	}
}
//复位函数
void RGB_RST(void)
{
	uint8_t dat[100] = {0};
  /* 判断上次DMA有没有传输完成 */
	while(HAL_DMA_GetState(&hdma_spi3_tx) != HAL_DMA_STATE_READY);
  /* RGB RESET */
	HAL_SPI_Transmit_DMA(&hspi3,dat,100); 
	HAL_Delay(10);
}

//常用颜色的点亮测试函数
void RGB_RED(uint16_t RGB_LEN)
{
  uint8_t i;
  for(i=0;i<RGB_LEN;i++)  
    RGB_Set_Color(i,RED);
	RGB_Reflash(RGB_LEN);
}
void RGB_GREEN(uint16_t RGB_LEN)
{
  uint8_t i;
  for(i=0;i<RGB_LEN;i++)  
    RGB_Set_Color(i,GREEN);
	RGB_Reflash(RGB_LEN);
}
void RGB_BLUE(uint16_t RGB_LEN)
{
  uint8_t i;
  for(i=0;i<RGB_LEN;i++)  
    RGB_Set_Color(i,BLUE);
	RGB_Reflash(RGB_LEN);
}
void RGB_YELLOW(uint16_t RGB_LEN)
{
  uint8_t i;
  for(i=0;i<RGB_LEN;i++)  
    RGB_Set_Color(i,YELLOW);
	RGB_Reflash(RGB_LEN);
}
void RGB_MAGENTA(uint16_t RGB_LEN)
{
  uint8_t i;
  for(i=0;i<RGB_LEN;i++)  
    RGB_Set_Color(i,MAGENTA);
	RGB_Reflash(RGB_LEN);
}
void RGB_BLACK(uint16_t RGB_LEN)
{
  uint8_t i;
  for(i=0;i<RGB_LEN;i++)  
    RGB_Set_Color(i,BLACK);
	RGB_Reflash(RGB_LEN);
}
void RGB_WHITE(uint16_t RGB_LEN)
{
  uint8_t i;
  for(i=0;i<RGB_LEN;i++)  
    RGB_Set_Color(i,WHITE);
	RGB_Reflash(RGB_LEN);
}

 (2)main函数中的调用

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */


  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */
//	RGB_BLACK(24);
//	HAL_Delay(100);
//	RGB_WHITE(20);
//	HAL_Delay(100);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
			

    /* USER CODE BEGIN 3 */
   // RGB_BLACK(60);
	//HAL_Delay(500);
	RGB_WHITE(60); //控制第1-60个灯珠全白
	HAL_Delay(500);
	RGB_YELLOW(59);//控制第1-59个灯珠全黄
	HAL_Delay(500);
	RGB_BLUE(58);//控制第1-58个灯珠全蓝
	HAL_Delay(500);	
	RGB_GREEN(57);//控制第1-57个灯珠全绿
	HAL_Delay(500);
  RGB_RED(56);//控制第1-56个灯珠全红
	HAL_Delay(500);		
		
		
	}
  /* USER CODE END 3 */
}

3、程序源码工程下载

https://download.csdn.net/download/jacklood/90684404

### 使用 HAL STM32 上驱动 WS2812 的方法 #### 初始化配置 为了使能 PWM 输出并控制 WS2812 彩灯,需通过 STM32CubeMX 配置定时器 TIMx 用于生成精确的 PWM 波形。设置 GPIO 引脚作为定时器通道输出,并启用 DMA 功能来传输数据流[^1]。 ```c // 定义 LED 数量以及缓冲区大小 #define NUM_LEDS (30U) #define BUFFER_SIZE (NUM_LEDS * 3) uint8_t ledBuffer[BUFFER_SIZE]; ``` #### 编写驱动程序 编写 `ws2812.c` 和对应的头文件 `ws2812.h` 来封装具体的操作逻辑。这些源码实现了向 WS2812 发送颜色信息的功能,其中包含了重要的时序处理部分以匹配 WS2812 所需的数据协议[^2]。 ```c void WS2812_SendData(uint8_t* pData, uint16_t Size){ /* 启动DMA发送 */ HAL_TIM_PWM_Start_DMA(&htim1,TIM_CHANNEL_1,(uint32_t*)pData,Size); } ``` #### 设置时序参数 由于不同型号单片机执行效率有所区别,因此需要微调定时器预分频系数及时基周期等参数,确保产生的脉冲宽度满足 WS2812 要求。对于 STM32F103C8T6 平台来说,通常采用如下设定: - 自动重装载寄存器 ARR=799; - 计数频率 PSC=83;这样可以得到大约 400kHz 的载波频率[^4]。 #### 主函数实现 最后,在主循环里更新 LED 数据即可完成整个流程的设计。这里展示了一个简单的例子,它会依次点亮每一颗 RGB 灯珠形成流动效果[^3]。 ```c int main(void){ // ...省略初始化代码... while(1){ for(int i = 0; i < NUM_LEDS; ++i){ memset(ledBuffer, 0, sizeof(ledBuffer)); SetPixelColor(i, RED); // 用户自定义的颜色设置函数 WS2812_SendData((uint8_t *)ledBuffer,BUFFER_SIZE); HAL_Delay(50); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jacklood

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值