STM32F 驱动WS2812B (1) IO口

STM32F107通过IO翻转驱动WS2812BLED灯组


基本原理

根据WS2812B的datasheet,这个灯组的控制方式是单IO控制,以高电平的时间不同来判定当前的数据是“1”还是“0”。如下图所示:
在这里插入图片描述
在这里插入图片描述
从图中可以看出0 code对应一个高电平400ns低电平850ns的脉冲,而1 code对应一个高电平800ns,低电平450ns的脉冲,无论0 code还是1 code的脉冲周期都是1250ns。还有一个reset电平是一个大于50us的低电平表示reset。
显示1个LED灯珠的数据需要24位,GRB3种颜色分别占8位,假设现在有3个灯珠,每个灯需要显示红色也就是R=0xFF需要发送如下的数据:
RESET电平 -> LED1(G(00),R(FF),B(00)) -> LED2(G(00),R(FF),B(00)) -> LED3(G(00),R(FF),B(00))

基本思路

第一步是实现1 code跟0 code的脉冲,这里用IO口反转的方式实现,使用nop命令达到ns的延时,通过写BSRR跟BRR来实现输出高低电平,具体实现如下:
1 code:

#define WS_WRITE_ONE 	GPIOB->BSRR = 4;  \
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();\
	GPIOB->BRR  = 4; \
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop()

逻辑分析仪抓波形:
1 code的波形:高电平750ns,低电平417ns,根据数据手册高电平800ns±150ns,低电平450ns±150ns在范围之内
在这里插入图片描述

0 code:

#define WS_WRITE_ZERO 	GPIOB->BSRR = 4; \
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();	\
	GPIOB->BRR  = 4; \
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop()

逻辑分析仪抓波形:
0 code的波形:高电平417ns,低电平792ns,根据数据手册高电平400ns±150ns,低电平850ns±150ns在范围之内
在这里插入图片描述
对于RESET信号,直接通过for循环完成:

void RGB_LED_Reset(void)
{
	GPIOB->BRR  = 4;
	for(int i=0;i<480;i++)
	{
		__nop();__nop();__nop();__nop();
	}
}

代码实现

以一个灯为例,一个灯需要24个0 code或者1 code的脉冲加上reset信号的低电平组成,首先定义一个24*LED_NUM大小的数组用来存放灯的脉冲数据:

#define LED_NUM 1
uint8_t io_data[24*LED_NUM]={0};

其次需要将传入的color值分解以下,传入的color是RGB格式的,由于ws2812b传输格式是GRB所以先处理G数据:

for(i=15;i>=8;i--)//G
{
	(((color>>i)&0x01)==1)?(io_data[index*24+(15-i)]=1):(io_data[index*24+(15-i)]=0);
}

G的数据是从color的第15bit开始到8bit结束,每次获取到bit需要判断是不是1,如果是1就需要在io_data的相应位置填入1,否则填入0.
用相同的方式处理R,B的数据:

for(i=23;i>=16;i--)//R
{
	(((color>>i)&0x01)==1)?(io_data[index*24+(31-i)]=1):(io_data[index*24+(31-i)]=0);
}
for(i=7;i>=0;i--)//B
{
	(((color>>i)&0x01)==1)?(io_data[index*24+(23-i)]=1):(io_data[index*24+(23-i)]=0);
}

使用一个函数循环发送出去:

void led_show(void)
{
	RGB_LED_Reset();
	for(int i=0;i<LED_NUM*24;i++)
	{
		if(io_data[i])
		{
			WS_WRITE_ONE;
		}
		else
		{
			WS_WRITE_ZERO;
		}
	}
}

总结

优点:

  1. 使用单IO口,不用选择外设。
  2. 程序简单,只需要填充所有显示的数据之后发送出去就行
    缺点:
  3. 有一定的硬延时会对系统造成影响。
    针对这个缺点,用逻辑分析仪抓取波形观察:
    在这里插入图片描述

这个抓的波形是显示256个灯的时候,程序中的延时给的是10ms,但实际抓出来的是17.9ms,通过计算256241.25=7680us差不多是,跟抓到的波形符合。所以这种方式不能用在需要时间很准的地方。如果显示的灯数量不多可以忽略这个问题。

关键源码

#define WS_WRITE_ONE 	GPIOB->BSRR = 4;  \
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();\
	GPIOB->BRR  = 4; \
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop()
	
#define WS_WRITE_ZERO 	GPIOB->BSRR = 4; \
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();	\
	GPIOB->BRR  = 4; \
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();\
	__nop();__nop()

#define LED_NUM 1
uint8_t io_data[24*LED_NUM]={0};
void RGB_LED_Reset(void)
{
	GPIOB->BRR  = 4;
	for(int i=0;i<480;i++)
	{
		__nop();__nop();__nop();__nop();
	}
}
void led_show(void)
{
	HAL_SuspendTick();
	RGB_LED_Reset();
	for(int i=0;i<LED_NUM*24;i++)
	{
		if(io_data[i])
		{
			WS_WRITE_ONE;
		}
		else
		{
			WS_WRITE_ZERO;
		}
	}
	HAL_ResumeTick();
}
void show_dot(unsigned int index,unsigned int color)
{
	int i=0;
	for(i=15;i>=8;i--)//G
	{
		(((color>>i)&0x01)==1)?(io_data[index*24+(15-i)]=1):(io_data[index*24+(15-i)]=0);
	}
	for(i=23;i>=16;i--)//R
	{
		(((color>>i)&0x01)==1)?(io_data[index*24+(31-i)]=1):(io_data[index*24+(31-i)]=0);
	}
	for(i=7;i>=0;i--)//B
	{
		(((color>>i)&0x01)==1)?(io_data[index*24+(23-i)]=1):(io_data[index*24+(23-i)]=0);
	}
	led_show();
}
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  while (1)
  {
		show_dot(0,0x00000f);
		HAL_Delay(500);
  }
}
### 回答1: STM32F1系列是一款微控制器,具有强大的控制能力和丰富的外设接,可以用来控制多条WS2812B RGB LED灯带。WS2812B是一种集成了控制电路和LED灯的智能灯珠,它能够通过串行通信协议控制每个像素的颜色,非常适合用于灯光控制应用。 要控制多条WS2812B灯带,首先需要确定灯带的数量和接类型。每个WS2812B灯带都需要一个数据引脚来发送颜色数据。对于STM32F1系列微控制器,可以选择多个GPIO针脚作为数据引脚来控制不同的WS2812B灯带。 接下来,需要编写控制代码来发送颜色数据给WS2812B灯带。首先,需要通过STM32F1的SPI或UART等接配置为串行通信模式。然后,通过相应的GPIO针脚将数据发送给WS2812B灯带。在编写代码时,需要遵循WS2812B的通信协议,即按照一定的时序发送0和1的信号来表示颜色数据。 在代码中,可以定义一个数组或结构体来存储每个灯珠的颜色值。然后,通过逐个灯珠的方式,将颜色数据转换为相应的信号,并通过串行通信接发送到WS2812B灯带。可以使用定时器或延时函数来控制发送信号的时间间隔,以确保数据传输的稳定性。 最后,在主循环中,不断更新灯珠的颜色数据,实现各种灯光效果,如呼吸灯、彩虹灯等。可以通过修改颜色数据数组中的值,然后重新发送数据到灯带,实现不同的灯光效果。 通过以上的步骤和代码编写,就可以实现STM32F1控制多条WS2812B灯带的功能。这样,就可以实现丰富多样的灯光效果,为各种应用场景带来更加出色的视觉效果。 ### 回答2: STMicroelectronics的STM32F1系列是一款强大的微控制器家族,具有良好的性能和灵活性,非常适合用于控制多条WS2812B LED灯条。 为了控制多条WS2812B,首先需要选择合适的引脚来输出控制信号。STM32F1系列拥有丰富的IO引脚资源,可以根据需要选择多个引脚来控制多条LED灯带。 在软件方面,可以利用STM32F1系列微控制器的定时器和GPIO模块来生成适合WS2812B通信的控制信号。首先,需要配置一个定时器来生成适当的PWM信号,通过GPIO输出到WS2812B的DIN引脚。在每个PWM周期内,根据WS2812B的通信协议,需要生成若干个高电平信号和低电平信号,以传输控制数据。可以使用定时器的中断功能,在每个中断中更新GPIO输出的电平。 为了控制多条WS2812B,可以实现一个控制函数,将每个LED灯带的数据转换为适当的控制信号并发送。可以使用存储器数组来存储每个LED灯带的数据,然后在适当的时间间隔内,循环遍历数组,将数据转换为控制信号,并通过GPIO输出到相应的灯带。 需要注意的是,WS2812B的通信速率较高,对于STM32F1系列来说可能会有一定的处理压力。可以通过适当调整定时器的频率和数据处理算法来提高控制的稳定性和效率。 总之,通过合适的硬件选择和软件设计,STM32F1系列微控制器可以很好地实现对多条WS2812B LED灯带的控制,以满足各种应用需求。 ### 回答3: STM32F1是STMicroelectronics(意法半导体)推出的一款32位ARM Cortex-M3内核的微控制器系列。而WS2812B是一款RGB LED驱动芯片。在使用STM32F1来控制多条WS2812B时,需要经过以下步骤: 1. 连接硬件:将每条WS2812B的数据引脚连接到STM32F1的输出引脚。需要确保每个WS2812B的电源和地连接正确,并且数据线连接到正确的STM32F1引脚。 2. 初始化GPIO:在STM32F1上选择一个合适的GPIO引脚来输出WS2812B的数据。初始化GPIO引脚为输出模式,并设置为低电平。 3. 编写控制代码:使用STM32F1的编程工具,例如Keil或STM32CubeIDE,在C语言中编写控制WS2812B的代码。可以使用STM32F1的定时器或延时函数来生成WS2812B所需的时序信号。 4. 发送数据信号:通过控制GPIO引脚的电平变化,以满足WS2812B数据传输的需求。根据WS2812B的通信协议,每个RGB LED都需要24位(8位红色,8位绿色,8位蓝色)的数据。可以通过逐位操作或使用STM32F1的外设来发送数据。 5. 重复步骤4:根据所需的WS2812B数量,重复步骤4来控制所有的WS2812B。确保数据传输的正确性和完整性。 6. 代码优化:使用延时函数和定时器等优化控制代码,以提高性能和稳定性。提高控制程序的效率可以使WS2812B的变化更加平滑和流畅。 总结,使用STM32F1来控制多条WS2812B需要连接正确的硬件,初始化GPIO引脚,编写控制代码,发送数据信号,并进行代码优化。通过这些步骤,可以实现对多条WS2812B的精确控制。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

网布

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

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

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

打赏作者

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

抵扣说明:

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

余额充值