1,实物展示

WS2812是一种可编程的LED灯,具有RGB显示效果,可显示的颜色数量为2^24

1e54e0ee216047a6861c71c07a81c5da.png

8af71af451d04afc9c50a5f295f32a15.jpeg

红色:+5V

白色:GND

绿色:数据输入

2,引脚定义与电气属性

1e27b9cf85b84f38bc199d1d2f50d82b.png

ebb7409945464950a7dcca1f33cfc2c9.png

VDD:电源正,范围+3.5V~+5.3V

VSS :电源地

DIN:输入输入端,电压范围-0.5V  ~  VDD+0.5V

DOUT:数据输出端,电压范围-0.5V ~ VDD+0.5V

单片机数据从DIN进入第一个灯珠时,第一个灯珠会锁存第一个24位数据,然后剩下的数据会从灯珠DOUT引脚输出到下一个灯珠的输入端,依此类推,可达到单总线控制多个灯珠的目的。

值得一提的是,如果使用的是3.3V的单片机,是不能直接驱动WS2812,需要接5V的上拉电阻,然后设置IO口为开漏输出模式,这样才能满足WS2812的电平协议,可能也不用,具体还是自行测试一下。

3,时序分析

该通讯方式为单总线通信,即利用高低电平的持续时间来确定0和1,与我们之前学的DS18B20温度传感器类似。

4e3e39f3a30a4666bb4680e75b71d54b.png

简单说就是,在一个周期内,高电平和低电平的比例,确定了数据帧为0、还是为1

下面的是数据帧的组成部分:

数据帧为1:高电平持续T1H,低电平持续T1L

数据帧为0:高电平持续T0H,低电平持续T0L

复位帧:电平持续时间大于280us

复位帧可以理解为一个结束符号,让灯带知道我们需要操作LED灯的个数,例如我们只需要操作10个灯珠,但是我们有20个灯珠,这时候我们在第十个指令后面加个复位帧,就可以只控制前面10个灯,而不会控制后面的灯,当然前提是灯珠首位相连。

通常情况下,我们设置一个通信周期为800khz,即1250ns

短的持续时间为300ns、长的持续时间为850ns,

这样设置是为了方便STM32单片机使用PWM模式+DMA请求来驱动WS2812灯带。

注意一点就是,如果使用传统的51单片机是不能驱动WS2812,除非使用的是1T的单片机,如果是12T的51单片机,则不能进行控制。

f6aa8433a4ef432d9643e681552d8594.png

一个LED灯需要24位来控制,即三个字节,每个字节代表的是不同的RGB,我们通过输入不同的数值,来控制不同的颜色,其实RGB是我们自然界的三大颜色,其他颜色实际都是这三个原色的组合。

4,  色域表

730797989ca94b2aa9b0a1fbb4b595a9.png

c7dc6bdfa3db49c9ad968132abb556f9.png

a87b53596e3542dfa4f35df6eec45146.png

5,编程实战

①基于STC8H8K64U———24Mhz

使用__nop_()函数作为延时,已知SCT8H单片机作为1T单片机,使用的时钟频率是不需要分频的,此时,机械周期等于时钟振荡周期。

所以单片机的机械周期为𝑇0=1/24𝑀h𝑧≈41𝑛𝑠, 即调用一次nop()的时间为41ns。

由于单片机指令执行需要一定的时间,所以我们的设定值要略小一点。

值得一提的是,该单片机与我们熟知的STC15系列是完全兼容的,所以也可以使用ST15单片机进行开发。

ws2812.c文件

#include "ws2812.h"
#define Led_Pin P14

void WS2812_SendData(unsigned char R,unsigned char G,unsigned char B)
{
  unsigned char i,j,temp[3];
  temp[0]=G;
  temp[1]=R;  
  temp[2]=B; 
  for(j=0;j<3;i++)
  {
    for(i=0;i<8;i++)
    {
      if(temp[j] & (0x80>>i)) //发送1
      {
        Led_Pin=1;
        _nop_();_nop_();_nop_();_nop_();_nop_();//_nop_();    delay 41ns
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();        
        Led_Pin=0;
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();        
      }
      else                //发送0
      {
         Led_Pin=1;
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();       
        Led_Pin=0;
        _nop_();_nop_();_nop_();_nop_();_nop_();     
        _nop_();_nop_();_nop_();_nop_();_nop_();  
        _nop_();_nop_();_nop_();_nop_();_nop_();  
        _nop_();_nop_();_nop_();_nop_();_nop_();          
      }
    }
  }
}
void delay_ms(unsigned int ms)		//@24.000MHz
{
	unsigned char i, j;
  while(ms--)
  {
    i = 24;
    j = 85;
    do
    {
      while (--j);
    } while (--i);   
  }

}

ws2812.h文件

#ifndef __WS2812_H
#define __WS2812_H

#include <STC8H.H>

#include "intrins.h"
void WS2812_SendData(unsigned char R,unsigned char G,unsigned char B);
void delay_ms(unsigned int ms);		//@24.000MHz


#endif

mian.c文件

#include <STC8H.H>
#include "ws2812.h"

void main()
{
  P1M1=0x00;    //准双向IO口模式
  P1M0=0x00;
  
  while(1)
  {
    WS2812_SendData(255,0,0);
    WS2812_SendData(0,255,0);
    WS2812_SendData(0,0,255);
    delay_ms(10);
  }
}

值得一提的是,如果是STC8H系列单片机的话,我们在使用引脚之前,都要进行初始化,因为该系列单片机的默认模式为悬空模式,这点与普通的51单片机有很大区别。

对您有帮助的话,请点个赞吧!!

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐