单片机
返回首页

STM32驱动WS2811实现渐变色、跑马灯

2025-11-07 来源:bilibili

一、WS2811简介

  1. 输出端口耐压12V

  2. 芯片内置稳压管,24V以下电源端只需串电阻IC到VDD脚,无需外加稳压管

  3. 灰度调节电路(256级灰度可调)

  4. 内置信号整形电路,任何一个IC收到信号后经过波形整形后在输出,保证线路波形畸变不会累加

  5. 内置上电复位和掉电复位电路

  6. PWM控制端能够实现256级调节,扫描频率不低于400HZ/S

  7. 串行接口级联,一根信号线DI完成数据的接收与解码

  8. 任意两点传输距离不超过2米无需增加任何电路

  9. 当刷新速率30帧/秒时,低速模式级联数不小于512点,高速模式下不小于1024点

  10. 数据发送速度可达与400Kbps与800Kbps两种模式

cut-off

二、通讯协议

数据协议采用单线归零码的通讯方式, 像素点在上电复位以后, DIN端接受从控制器传输过来的数据, 首先送过来的24bit数据被第一个像素点提取后, 送到像素点内部的数据锁存器, 剩余的数据经过内部整形处理电路整形放大后通过DO端口开始转发输出给下一个级联的像素点, 每经过一个像素点的传输, 信号减少24bit。 像素点采用自动整形转发技术, 使得该像素点的级联个数不受信号传送的限制, 仅仅受限信号传输速度要求。

WS2811 0码、1码、reset码时序、串接方法

数据传输

需要精确延时的,使用示波器进行查看

三、电路连接

图出处:天际智联STM32F103开源四轴

四、开源代码

WS2811.h

#ifndef __WS2811_H

#define __WS2811_H

#include <stm32f10x.h>

//#define   Time_D    400          //宏定义

#define nWs 50 // 定义串接级联WS2811个数  50可修改

//B-R-G  定义颜色24bits

#define   White        0xFFFFFF  // 白色

#define   Black        0x000000  // 黑色 (不亮)

#define   Blue         0xFF0000  // 蓝色

#define   Red          0x00FF00  // 红色

#define   Green        0x0000FF  // 绿色

#define   Gray         0x22ee22

extern void WS_GPIO_Init(void);//WS2811端口初始化

extern unsigned long WsDat_RUN[nWs];//流水灯显存

extern unsigned long WsDat[nWs];//流水灯显存

//extern void WS_Reset(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);    //复位

//extern void WS_Set1(GPIO_TypeDef *GPIOx,uint16_t GPIO_PIN,unsigned long dat); 

//发送1个字节

extern void WS_Set_Date(GPIO_TypeDef *GPIOx,uint16_t GPIO_PIN,unsigned char len,unsigned long dat); //发送相同数据

extern void WS_SetAll(GPIO_TypeDef *GPIOx,uint16_t GPIO_PIN); //发送所有字节

//灯带控制方案

extern unsigned long ColorToColor(GPIO_TypeDef *GPIOx,uint16_t GPIO_PIN,unsigned long color0, unsigned long color1,unsigned int speed) ;//颜色渐变   

//初始化显存数组

extern void LED_Init(GPIO_TypeDef *GPIOx,uint16_t GPIO_PIN,unsigned long color);          extern void RUN_LED(GPIO_TypeDef *GPIOx,uint16_t GPIO_PIN,unsigned long color,unsigned int speed,unsigned char temp); //跑马灯

#endif

WS2811.C

#include "WS2811.h"

unsigned long WsDat[nWs];   //显存

unsigned long WsDat_RUN[nWs];   //流水灯显存

/**************************************************

* IO初始化(移植时请修改)

***************************************************/

void WS_GPIO_Init()

{

GPIO_InitTypeDef  GPIO_InitStructure;

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );   //端口时钟,使能

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; // PIN

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz

GPIO_Init(GPIOC, &GPIO_InitStructure); // 端口配置,根据设定参数初始化 

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );   //端口时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_14 | GPIO_Pin_13 | GPIO_Pin_12; // PIN

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz

GPIO_Init(GPIOB, &GPIO_InitStructure); // 端口配置,根据设定参数初始化 

}

/**************************

* 内部延时

***************************/

void WS_delay_us(__IO u32 nCount) //简单的延时函数

{

for(; nCount != 0; nCount--);

void WS_delay2us()

{

unsigned char i;

for(i=0; i<11; i++);

}

void WS_delay05us()

{

// unsigned char i;

// for(i=0; i<1; i++);

}

void WS_delay_ms(uint32_t nms)

{

while(nms--)

{

  WS_delay_us(1670); //普通方式延时

}

}

/***************************

* 发送一比特

****************************/

void TX0(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)    // 发送0

{

GPIO_SetBits(GPIOx, GPIO_Pin); 

    WS_delay05us();

GPIO_ResetBits(GPIOx, GPIO_Pin);

WS_delay2us();

void TX1(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)   // 发送1

{

GPIO_SetBits(GPIOx, GPIO_Pin); 

WS_delay2us();

GPIO_ResetBits(GPIOx, GPIO_Pin);

WS_delay05us();

void WS_Reset(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)   //复位

{

GPIO_ResetBits(GPIOx, GPIO_Pin); 

WS_delay_us(50); 

GPIO_SetBits(GPIOx, GPIO_Pin);

GPIO_ResetBits(GPIOx, GPIO_Pin); 

}

/************************************************

* 发送数据

*************************************************/

void WS_Set1(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin,unsigned long dat)

{

unsigned char i;

for(i=0; i<24; i++)

{

if(0x800000 == (dat & 0x800000) )

TX1(GPIOx,GPIO_Pin);

else

TX0(GPIOx,GPIO_Pin);

dat<<=1;        //左移一位

}

}

void WS_Set_Date(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin,unsigned char len,unsigned long dat) // 全部发送同样的数据

{

   unsigned char i;

   for(i = 0; i <len; i++)

   {

WS_Set1(GPIOx,GPIO_Pin,dat);

   }

WS_Reset(GPIOx,GPIO_Pin);

}

void WS_SetAll(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)   //发送所有字节

{

unsigned char i;

for(i=0;i<nWs;i++)

{

WS_Set1(GPIOx,GPIO_Pin,WsDat_RUN[i]);  

}

WS_Reset(GPIOx,GPIO_Pin);

WS_delay_ms(500);

}

/**************************颜色渐变函数***************************/

/*

从起始颜色---最终颜色

*/

unsigned char abs0(int num)//求绝对值

{

if(num>0) return num;

num = -num;

return (unsigned char) num;

}

unsigned long ColorToColor(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin,unsigned long color0, unsigned long color1,unsigned int speed)  

{

unsigned char Red0, Green0, Blue0;  // 起始三原色

unsigned char Red1, Green1, Blue1;  // 结果三原色

int   RedMinus, GreenMinus, BlueMinus; // 颜色差(color1 - color0)

unsigned char NStep; // 需要几步

float   RedStep, GreenStep, BlueStep; // 各色步进值

unsigned long color; // 结果色

unsigned char i;

// 绿 红 蓝 三原色分解

Red0   = color0>>8;

Green0 = color0>>16;

Blue0  = color0;

Red1   = color1>>8;

Green1 = color1>>16;

Blue1  = color1;

// 绿 红 蓝 三原色分解  若输入的颜色非上述三种

Red0   =( color0&0x00FF00)>>8;

Green0 = (color0&0xFF0000)>>16;

Blue0  = color0;

Red1   = (color1&0x00FF00)>>8;

Green1 = (color1&0xFF0000)>>16;

Blue1  = color1;

// 计算需要多少步(取差值的最大值)

RedMinus   = Red1 - Red0; 

GreenMinus = Green1 - Green0; 

BlueMinus  = Blue1 - Blue0;

//判断两个绝对值大小。。a>b为真,则=a;否则=b

NStep = ( abs0(RedMinus) > abs0(GreenMinus) ) ? abs0(RedMinus):abs0(GreenMinus); 

NStep = ( NStep > abs0(BlueMinus) ) ? NStep:abs0(BlueMinus);

// 计算出各色步进值

RedStep   = (float)RedMinus   / NStep;

GreenStep = (float)GreenMinus / NStep;

BlueStep  = (float)BlueMinus  / NStep;

// 渐变开始

for(i=0; i<NStep; i++)

{

Red1   = Red0   + (int)(RedStep   * i);

Green1 = Green0 + (int)(GreenStep * i);

Blue1  = Blue0  + (int)(BlueStep  * i);

color  = Green1<<16 | Red1<<8 | Blue1; // 合成  绿红蓝

WS_Set_Date(GPIOx,GPIO_Pin,nWs,color); //发送颜色,所有灯带同色

WS_delay_ms(speed);

}

return color;

}

/*************跑马灯****************

000000000000000000000000

111100000000000000000000

000011110000000000000000

000000001111000000000000

111100000000111100000000

000011110000000011110000

***********************************/

void LED_Init(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin,unsigned long color) //初始化显存数组

{

unsigned char i;

for(i=0;i<50;i++)

WsDat_RUN[i]=color;

WS_SetAll(GPIOx,GPIO_Pin);

}

//入口参数     color----speed----temp

//            显示颜色--流水速度--间隔距离

void RUN_LED(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin,unsigned long color,unsigned int speed,unsigned char temp)//跑马灯

{

unsigned char i,j;

for(j=0;j<(nWs-1);j++)

{

for(i=nWs;i>0;i--)

WsDat_RUN[i] = WsDat_RUN[i-1];

if(j%temp == 0)

WsDat_RUN[0] = color;

else

WsDat_RUN[0] = Black;

//WS_Set_Date(GPIO_PIN,nWs,WsDat_RUN[i]); 

WS_SetAll(GPIOx,GPIO_Pin);

WS_delay_ms(speed);

}

}

main.c

#include "stm32f10x.h"

#include "WS2811.h"

int main()

{

WS_GPIO_Init();//GPIOC和GPIOB初始化

ColorToColor(GPIOB,GPIO_Pin_15 | GPIO_Pin_14 | GPIO_Pin_13 | GPIO_Pin_12,Red,Green,10);//颜色渐变端口GPIOB12131415输出

//如果需要其他端口输出先去WS2811.c修改GPIO口初始化函数

}

cut-off

WS2811模块实物图

cut-off

此版本在已在正点原子的战舰版本上运行成功,若使用野火、七星虫等其余主流开发板,请参考商家给的硬件连接图进行修改


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦线性调频增强器

  • 家用电器遥控器

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • DS1669数字电位器

  • HA1377 桥式放大器 BCL 电容 17W(汽车音频)

    相关电子头条文章