ws2812B+单片机驱动

Posted _WILLPOWER_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ws2812B+单片机驱动相关的知识,希望对你有一定的参考价值。

效果

呼吸

流水

跑马

随机灯带

WS2812B 驱动

数据协议

采用单线归零码,每个像素点(灯),在接受到自己的24bit数据后,将剩下的数据再处理放大后,发出去,也就是每经过一个点,数据少24bit。

RES帧单位,低电平时间330us以上
T0L0码,低电平时间750ns~1.6us
T0H0码,高电平时间220ns~420ns
T1H1码,高电平时间750ns~1.6us
T1L0码,低电平时间220ns~420ns

注意一点就行了:比例3:1,
比如:
T0L 750ns

T0H 250ns

其对时序要求还是很高的,因此一定要满足要求,不要再数据发的过程中做一些耗时的操作

24bit数据结构

|G7|G6|G5|G4|G3|G2|G1|G0|R7|R6|R5|R4|R3|R2|R1|R0|B7|B6|B5|B4|B3|B2|B1|B0|
高位在前,按照GRB顺序

程序

注意stc15的话,该程序的晶振需设置为24M

main.c

#include <stc15f2k60s2.h>
#include <stdio.h>
#include "ws.h"
#include <INTRINS.H>
#define uchar unsigned char
#define uint unsigned int
#define LEDCNT 50 //灯的数目
sbit k1 = P3^0; //按键一 控制模式
sbit k2 = P3^1;	//按键二 关闭灯光
//成员依次为计时最大值,计时数,是否完成计时
typedef struct delay

	uint max;
	uint cnt;
	uchar ok;
 t_delay;
//灯的切换速度(因为定时器是2ms,所以300*2=600ms,以下同理)
t_delay delaytime = 300, 0, 0;
//流水灯的速度(可以设置一个变量然后使用按键控制,都是可以的)
t_delay liushui_time = 30, 0, 0;
//呼吸灯呼吸的速度
t_delay huxi_time = 100, 0, 0;


//GRB
//流水灯流完一次改变颜色
code ws_t wsData[] = 255,0, 0, 0, 255, 0, 0, 0, 250;
//跑马灯的设置
code ws_t PAOMACODE[] = 255, 0,  0, 0, 255, 0, 0, 0, 255;
unsigned int SEED = 0;//随机数种子

//当前按键值,上一次按键值,按键计数
uchar key, tmpKey, keyCnt;
enum

	K_GT,
	K_AS,
	K_WA
 keyState = K_GT;

enum

	HUXI,
	LIUSHUI,
	PAOMA,
	SUIJI,
	XIMIE
gloState = LIUSHUI;

//单次获取按键
uchar GetKey()

	if (k1 == 0)
		return 1;
	else if(k2 == 0)
		return 2;
	return 0;

//自我设定定时器运行
void TimeRun(t_delay *time)

	if (time->cnt++ < time->max)
		;
	else
	
		time->cnt = 0;
		time->ok = 1;
	


void Timer1Init(void) // 2毫秒@12.000MHz

	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x80;		//设置定时初值
	TH1 = 0x44;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	ET1 = 1;

//为了调试用的
void UartInit(void)

	SCON = 0x50;
	AUXR |= 0x01;
	AUXR |= 0x04;
	T2L = 0xE0;
	T2H = 0xFE;
	AUXR |= 0x10;
	ES = 0;
	

void Timer1Handle() interrupt 3

	switch (keyState)
	
	case K_GT:
		tmpKey = GetKey();
		keyState = K_AS;
		keyCnt = 0;
		break;

	case K_AS:
		if (keyCnt++ < 10);
		else if (tmpKey == GetKey())
		
			if (tmpKey != key)
			
				key = tmpKey;
				keyState = K_WA;
			
			else
				keyState = K_GT;
		
		else
			keyState = K_GT;
		break;
	
	//在定时器中计算一个定时
	TimeRun(&delaytime);
	TimeRun(&liushui_time);
	TimeRun(&huxi_time);


void Liushui()

	static uchar i = 0;
	static uchar color = 0;
	if(liushui_time.ok == 1)
	
		liushui_time.ok = 0;
		SendLiushui(LEDCNT, i, wsData[color]);
		i = (i + 1)%LEDCNT;
		if(i == 0)
		
			color = (color + 1)%3;
		
	

void Paoma()

	static uchar i = 0;
	if(delaytime.ok == 1)
	
		delaytime.ok = 0;
		SendPaoma(LEDCNT, PAOMACODE[i]);
		i = (i + 1)%3;
	

void Suiji()

	if(delaytime.ok == 1)
	
		delaytime.ok = 0;
		SendSuiji(LEDCNT);
	

void Huxi()

	static uchar i = 0;
	if(huxi_time.ok == 1)
	
		huxi_time.ok = 0;
		SendHuxi(LEDCNT, i);
		i = (i + 1)%30;
	



void main()

	Timer1Init();
	UartInit();
	EA = 1;
	while (1)
	
		switch(gloState)
		
			case LIUSHUI:
						Liushui();
			break;
			
			case PAOMA:
						Paoma();
			break;
			
			case SUIJI:
						Suiji();
			break;
			
			case HUXI:
						Huxi();
			break;
			
		if(keyState == K_WA)
		
			if(key == 1)
			
				if(gloState == XIMIE)
				
					gloState = HUXI;
				
				else
				
					gloState = (gloState + 1)%4;
				
			
			else if(key == 2)//如果按键二按下,则熄灭全部灯
			
				SendXime(LEDCNT);
				gloState = XIMIE;
			
			keyState = K_GT;
		
	

ws.c

#include <STC15F2K60S2.H>
#include <INTRINS.H>
#include <stdio.h>
#include <stdlib.h>
#include "ws.h"

sbit LED = P2^4; //灯带的数据输入
//呼吸灯的值(这部分可以写一个RGB2HSV转换,这里我直接查找的值)
code ws_t HUXICODE[] = 32,11,227, 29,10,201,23,7,165, 21,7,143, 17,5,122,15,5,101,12,4,81, 6,2,43, 3,1,18, 0,0,0,
												31,219,4, 27,188,3,23,167,3, 21,146,3, 18,125,2,15,104,2,12,84,1, 7,52,1, 5,33,1, 0,0,0,
												218,100,3, 188,86,3,167,77,3, 149,68,2, 125,57,2,104,48,2,84,38,1, 63,29,1, 26,12,0, 0,0,0;

//每一帧至少的间隙
void Delay300us()		//@24.000MHz

	unsigned char i, j;

	i = 1;
	j = 146;
	do
	
		while (--j);
	 while (--i);

//发送24个bit数据
void WS_SendData(ws_t *_data)

    uchar i = 0;
    uchar j = 0;
		uchar *p = (uchar*)_data;
		EA = 0;
    for (i = 0; i < 3; i++)
    
        uchar tmpData;
				tmpData = *(p++);
        for (j = 0; j < 8; j++)
        
            if (((tmpData>>(7-j)) & 0x01) == 0)
            
                LED = 1;
                _nop_();_nop_();_nop_();  	
                LED = 0;
                _nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_();      
            
            else
            
                LED = 1;
                _nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_();		
                LED = 0;
                _nop_();_nop_();_nop_();    
            
        
    
		EA = 1;


//流水灯
//总个数,哪一个灯亮,亮什么值
void SendLiushui(uchar num,uchar whichLight, ws_t _data)

	uint i = 0;
	ws_t ximieValue = 0, 0, 0;
	for(i = 0; i< num+1; i++)
	
        //到该亮的地方才亮
		if((i >= whichLight) && (i <= whichLight + 5))
		
			WS_SendData(&_data);	
		
		else
		
			WS_SendData(&ximieValue);	
		
	
	Delay300us();

//熄灭所有灯
void SendXime(uchar num)

	uint i = 0;
	ws_t ximieValue = 0, 0, 0;
	for(i = 0; i< num+1; i++)
	
		WS_SendData(&ximieValue);	
	
	LED = 0;
	Delay300us();

//跑马灯
void SendPaoma(uchar num, ws_t _data)

	static uchar start = 0;
	uint i = 0;
	ws_t ximieValue = 0, 0, 0;
	for(i = 0; i< num+1; i++)
	
        //一半亮一半不亮
		if((i%2) == start)
		
			WS_SendData(&_data);	
		
		else
		
			WS_SendData(&ximieValue);	
		
	
	start = (start + 1)%2;
	Delay300us();

void SendSuiji(uchar num)

	uint i = 0;
	for(i = 0; i< num+1; i++)
	
        //随机颜色
		ws_t suijiValue = 0,0,0;
		suijiValue.green = SEED>>8;
		suijiValue.red = SEED;
		suijiValue.blue = ~SEED;
		SEED = SEED + 455;
		WS_SendData(&suijiValue);	
	
	Delay300us();

//根据已经设定的值来亮
void SendHuxi(uchar num, uchar lightLevel)

	uint i = 0;
	for(i = 0; i< num+1; i++)
	
		WS_SendData(&HUXICODE[lightLevel]);	
	
	Delay300us();


ws.h

#ifndef _WS_H
#define _WS_H

#define uchar unsigned char
#define uint unsigned int
	
extern unsigned int SEED;//随机种子
typedef struct ws

    uchar green;
    uchar red;
    uchar blue;
ws_t;

void WS_SendData(ws_t* _data);
void SendLiushui以上是关于ws2812B+单片机驱动的主要内容,如果未能解决你的问题,请参考以下文章

ws2812B+单片机驱动

ws2811芯片怎样让他全亮

ws2812 LED灯编程

WS2812原理及实现

Arduino驱动WS2812B呼吸灯效果

ESP 保姆级教程疯狂毕设篇 —— 案例:基于阿里云小程序Arduino的WS2812灯控系统