WS2812B灯带驱动实验

实验环境:

KEIL5、正点原子阿波罗STM32F767开发板

一、灯带介绍

过多介绍我这里不赘述了,想了解详情的可以看看手册,直接开干。

1.1、灯带连接方式

我们只要控制DIN端就好了。
请添加图片描述

1.2、传输数据方式

简单理解就是单总线发了一串数据,第一个灯拿了第一个字节的数据,第二个灯拿个第二个字节的数据,以此类推。
请添加图片描述

1.3、控制时序

代码就照这个时序写,因为例程中没有没有纳秒级别的延迟函数,所以我们要根据自己芯片去写。
请添加图片描述
我用的晶振是216M,一个 __nop() 计算方式为:1 / 216MHz ≈ 0.0046us = 4.6ns 。
根据这个就可以写纳秒(ns)级别的函数了。

二、程序介绍

2.1、WC2812B.c

/************************************************************
@Description: WS2812B全彩LED灯驱动
***********************************************************/
#include "WS2812B.h"
#include "delay.h"

Color_TypeDef PixelBuf[PIXEL_NUM]; //像数数据
uint8_t flag;
Color_TypeDef	Color_Prar;	
//晶振216M,1/216≈0.004629us=4.6ns
#define delay_4_6ns		__nop()							//1个nop是4.6ns
#define	delay_23ns		delay_4_6ns;delay_4_6ns;delay_4_6ns;delay_4_6ns;delay_4_6ns
#define delay_115ns		delay_23ns;delay_23ns;delay_23ns;delay_23ns;delay_23ns
//T0H
#define delay_391ns		delay_115ns;delay_115ns;delay_115ns;delay_23ns;delay_23ns
//T0L
#define delay_851ns		delay_805ns;delay_23ns;delay_23ns
//T1L
#define delay_460ns		delay_115ns;delay_115ns;delay_115ns;delay_115ns
//T1H
#define delay_805ns		delay_460ns;delay_115ns;delay_115ns;delay_115ns

/*---------------------------------------------------------------------------
@Function   :WS2812B_Init
@Description:初始化
----------------------------------------------------------------------------*/
void WS2812B_Init(void)
{
	GPIO_InitTypeDef GPIO_Initure;
	__HAL_RCC_GPIOB_CLK_ENABLE();           //开启GPIOA时钟
	GPIO_Initure.Pin=WS2812B_PIN;           //PB1
	GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输入
	GPIO_Initure.Pull=GPIO_PULLUP;        	//上拉
	GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速

	HAL_GPIO_Init(WS2812B_PORT,&GPIO_Initure);
	HAL_GPIO_WritePin(WS2812B_PORT,WS2812B_PIN,GPIO_PIN_SET);	//PB1置1 
}
/*---------------------------------------------------------------------------
@Function   :WS2812B_Reset
@Description:复位
----------------------------------------------------------------------------*/
void WS2812B_Reset(void)          //复位函数
{
	WS2812B_Low();
	delay_us(300);
}

/*---------------------------------------------------------------------------
@Function   :WS2812B_WriteByte
@Description:写一个字节
----------------------------------------------------------------------------*/
void WS2812B_WriteByte(uint8_t dat)
{
	u8 i;
	for (i=0;i<8;i++)
	{
		//先发送高位
		if (dat & 0x80) //1
		{
			WS2812B_Hi();
			delay_805ns; 	//T1H
			WS2812B_Low();	
			delay_460ns; //T1L
		}
		else	//0
		{
			WS2812B_Hi();
			delay_391ns; //T0H
			WS2812B_Low();	
			delay_851ns; //T0L
		}
		dat<<=1;
	}
}

/*---------------------------------------------------------------------------
@Function   :RGB_LED_Write_24Bits
@Description:写入1个24bit颜色数据
----------------------------------------------------------------------------*/
void RGB_LED_Write_24Bits(uint8_t green, uint8_t red, uint8_t blue)
{
    WS2812B_WriteByte(green);
    WS2812B_WriteByte(red);
    WS2812B_WriteByte(blue);
    WS2812B_Reset();
}

/*---------------------------------------------------------------------------
@Function   :RGB_LED_Red
@Description:写入1红色数据
@Input      :无
@Retrun     :无
@Others     :
----------------------------------------------------------------------------*/
void RGB_LED_Red(void)
{
    uint8_t i;
    for (i = 0; i < 1; i++)
    {
        RGB_LED_Write_24Bits(0, 0xff, 0);
    }
}


/*---------------------------------------------------------------------------
@Function   :RGB_LED_Green
@Description:写入1绿色数据
----------------------------------------------------------------------------*/
void RGB_LED_Green(void)
{
    uint8_t i;
    for (i = 0; i < 1; i++)
    {
        RGB_LED_Write_24Bits(0xff, 0, 0);
    }
}

/*---------------------------------------------------------------------------
@Function   :RGB_LED_Blue
@Description:写入1蓝色数据
----------------------------------------------------------------------------*/
void RGB_LED_Blue(void)
{
    uint8_t i;
    for (i = 0; i < 1; i++)
    {
        RGB_LED_Write_24Bits(0, 0, 0xff);
    }
}

/*---------------------------------------------------------------------------
@Function   :WS2812B_WriteColor
@Description:写入1个24bit颜色数据
----------------------------------------------------------------------------*/
void WS2812B_WriteColor(Color_TypeDef *pColor)
{
	WS2812B_WriteByte(pColor->G);
	WS2812B_WriteByte(pColor->R);
	WS2812B_WriteByte(pColor->B);
}

/*---------------------------------------------------------------------------
@Function   :WS2812B_RefreshPixel
@Description:更新显示
@Input      :无
@Retrun     :无
@Others     :
----------------------------------------------------------------------------*/
void WS2812B_RefreshPixel(void)
{
	u8 i;

	for(i=0;i<PIXEL_NUM;i++)
	{
		WS2812B_WriteColor(&PixelBuf[i]);
	}
}
//============================================================================
void Copy_Color(Color_TypeDef *pDst,Color_TypeDef *pScr)
{
	pDst->R = pScr->R;
	pDst->G = pScr->G;
	pDst->B = pScr->B;
}

/*---------------------------------------------------------------------------
@Function   :WS2812B_FillColor
@Description:填充颜色
@Input      :start:开始位置;end:结束信置;pColor:颜色值
@Retrun     :无
@Others     :
----------------------------------------------------------------------------*/
void WS2812B_FillColor(u16 start,u16 end,Color_TypeDef *pColor)
{
	if (start > end) //交换位置
	{
		u16 temp;
		temp = start;
		start = end;
		end = temp;
	}

	if (start >= PIXEL_NUM)return; //超出范围
	if (end >= PIXEL_NUM)end = PIXEL_NUM-1;

	//填充颜色值
	while(start <= end)
	{
		Copy_Color(&PixelBuf[start],pColor);
		start++;
	}
}

/*---------------------------------------------------------------------------
@Function   :WS2812B_All_Blue
@Description:点亮全部灯带显示为蓝色
----------------------------------------------------------------------------*/
void WS2812B_All_Blue(u8 num)
{
	Color_Prar.G = 0x00;
	Color_Prar.R = 0x00;
	Color_Prar.B = 0xff;
	WS2812B_FillColor(0,num,&Color_Prar);	
}
void WS2812B_All_Red(u8 num)	//全红
{
	Color_Prar.G = 0x00;
	Color_Prar.R = 0xff;
	Color_Prar.B = 0x00;
	WS2812B_FillColor(0,num,&Color_Prar);	
}
void WS2812B_All_Green(u8 num)	//全绿
{
	Color_Prar.G = 0xff;
	Color_Prar.R = 0x00;
	Color_Prar.B = 0x00;
	WS2812B_FillColor(0,num,&Color_Prar);	
}

void WS2812B_All_Yellow(u8 num)	//全黄
{
	Color_Prar.G = 0xff;
	Color_Prar.R = 0xff;
	Color_Prar.B = 0x00;
	WS2812B_FillColor(0,num,&Color_Prar);	
}

2.2、WS2812.h

/************************************************************
@Description: WS2812B全彩LED灯驱动
***********************************************************/
#ifndef __WS2812B_H
#define	__WS2812B_H
#include "sys.h"

//WS2812B IO 定义  注意初始化APB时钟也要修改
#define WS2812B_PORT		GPIOB
#define WS2812B_PIN			GPIO_PIN_1
#define WS2812B_RCC_AHB		__HAL_RCC_GPIOB_CLK_ENABLE()           //开启GPIOB时钟

#define WS2812B_Hi()	HAL_GPIO_WritePin(WS2812B_PORT,WS2812B_PIN,GPIO_PIN_SET)	
#define WS2812B_Low()	HAL_GPIO_WritePin(WS2812B_PORT,WS2812B_PIN,GPIO_PIN_RESET)	
//颜色
typedef struct color{
	u8 G;
	u8 R;
	u8 B;
}Color_TypeDef;

//------------------------
#define PIXEL_NUM	60	//LED灯的个数

void WS2812B_Init(void);
void WS2812B_Reset(void);
void WS2812B_WriteColor(Color_TypeDef *pColor);

void RGB_LED_Write_24Bits(uint8_t green, uint8_t red, uint8_t blue);
void RGB_LED_Red(void);
void RGB_LED_Green(void);
void RGB_LED_Blue(void);

void WS2812B_RefreshPixel(void);
void WS2812B_FillColor(u16 start,u16 end,Color_TypeDef *pColor);

void WS2812B_All_Blue(u8 num);
void WS2812B_All_Red(u8 num);
void WS2812B_All_Green(u8 num);
void WS2812B_All_Yellow(u8 num);
#endif 

2.3、KEY.c

#include "key.h"
#include "delay.h"
#include "WS2812B.h"

//按键初始化函数
void KEY_Init(void)
{
    GPIO_InitTypeDef GPIO_Initure;
    
    __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟
    __HAL_RCC_GPIOC_CLK_ENABLE();           //开启GPIOC时钟
    __HAL_RCC_GPIOH_CLK_ENABLE();           //开启GPIOH时钟
    
    GPIO_Initure.Pin=GPIO_PIN_0;            //PA0
    GPIO_Initure.Mode=GPIO_MODE_INPUT;      //输入
    GPIO_Initure.Pull=GPIO_PULLDOWN;        //下拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    HAL_GPIO_Init(GPIOA,&GPIO_Initure);
    
    GPIO_Initure.Pin=GPIO_PIN_13;           //PC13
    GPIO_Initure.Mode=GPIO_MODE_INPUT;      //输入
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    HAL_GPIO_Init(GPIOC,&GPIO_Initure);
    
    GPIO_Initure.Pin=GPIO_PIN_2|GPIO_PIN_3; //PH2,3
    HAL_GPIO_Init(GPIOH,&GPIO_Initure);
}

//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//0,没有任何按键按下
//1,WKUP按下 WK_UP
//注意此函数有响应优先级,KEY0>KEY1>KEY2>WK_UP!!
u8 KEY_Scan(u8 mode)
{
    static u8 key_up=1;     //按键松开标志
    if(mode==1)key_up=1;    //支持连按
    if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
    {
        delay_ms(10);
        key_up=0;
        if(KEY0==0)       return KEY0_PRES;
        else if(KEY1==0)  return KEY1_PRES;
        else if(KEY2==0)  return KEY2_PRES;
        else if(WK_UP==1) return WKUP_PRES;          
    }else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1;
    return 0;   //无按键按下
}


void KEY_LED_Control(void)
{
	switch(KEY_Scan(0))
	{
		case KEY0_PRES:
		{
			WS2812B_All_Blue(30);
			delay_ms(100);
			WS2812B_RefreshPixel();		//更新显示
		}break;
		case KEY1_PRES:
		{
			WS2812B_All_Red(30);
			delay_ms(100);	
			WS2812B_RefreshPixel();		//更新显示
		}break;
		case KEY2_PRES:
		{
			WS2812B_All_Green(30);
			delay_ms(100);
			WS2812B_RefreshPixel();		//更新显示
		}break;
		case WKUP_PRES:
		{
			WS2812B_All_Yellow(30);
			delay_ms(100);
			WS2812B_RefreshPixel();		//更新显示
		}break;
	}
}

2.4、KEY.h

#ifndef _KEY_H
#define _KEY_H
#include "sys.h"

#define KEY0        HAL_GPIO_ReadPin(GPIOH,GPIO_PIN_3)  //KEY0按键PH3
#define KEY1        HAL_GPIO_ReadPin(GPIOH,GPIO_PIN_2)  //KEY1按键PH2
#define KEY2        HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13) //KEY2按键PC13
#define WK_UP       HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)  //WKUP按键PA0

#define KEY0_PRES 	1
#define KEY1_PRES	2
#define KEY2_PRES	3
#define WKUP_PRES   4

void KEY_Init(void);
u8 KEY_Scan(u8 mode);
void KEY_LED_Control(void);

#endif

2.5、main.c

#include "sys.h"
#include "delay.h"
#include "key.h"
#include "WS2812B.h"

int main(void)
{
    Cache_Enable();                 //打开L1-Cache
    HAL_Init();				        //初始化HAL库
    Stm32_Clock_Init(432,25,2,9);   //设置时钟,216Mhz 
    delay_init(216);                //延时初始化
	KEY_Init();						//按键初始化
	WS2812B_Init();					//灯带控制IO口初始化

    while(1)
    {		
		KEY_LED_Control();	//由此按钮函数控制切换红、绿、蓝、黄四种颜色
	}
}

遇到的问题

灯带是点亮了,也能控制切换,但是,灯带受外部干扰也很强,不控制的情况下,也可能会不受控制的点亮。

文章参考:

闲来无事,搞了条WS2812B全彩灯带玩一下,驱动程序借助以下两篇文章的大佬的程序修改。
https://blog.csdn.net/Lennon8_8/article/details/108980808
https://blog.csdn.net/weixin_53411486/article/details/127246513
做实验前结合这两位仁兄的贴子,感谢两位大佬。

附带代码连接

有遇到相同实验环境的情况的伙伴,也可以直接使用这份代码实验一下。
https://download.csdn.net/download/weixin_41569625/87452923

  • 4
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值