ws2812B+单片机驱动
文章目录
- 效果
- 呼吸
- 流水
- 跑马
- 随机灯带
- WS2812B 驱动
- 数据协议
- 24bit数据结构
- 程序
- main.c
- ws.c
- ws.h
- 待做
效果
呼吸
流水
跑马
随机灯带
WS2812B 驱动
数据协议
采用单线归零码,每个像素点(灯),在接受到自己的24bit数据后,将剩下的数据再处理放大后,发出去,也就是每经过一个点,数据少24bit。
RES | 帧单位,低电平时间 | 330us以上 |
---|---|---|
T0L | 0码,低电平时间 | 750ns~1.6us |
T0H | 0码,高电平时间 | 220ns~420ns |
T1H | 1码,高电平时间 | 750ns~1.6us |
T1L | 0码,低电平时间 | 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;}elsekeyState = K_GT;}elsekeyState = 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 intextern unsigned int SEED;//随机种子
typedef struct ws
{uchar green;uchar red;uchar blue;
}ws_t;void WS_SendData(ws_t* _data);
void SendLiushui(uchar num,uchar whichLight, ws_t _data);
void SendXime(uchar num);
void SendPaoma(uchar num, ws_t _data);
unsigned int random(unsigned int xxx);
void SendSuiji(uchar num);
void SendHuxi(uchar num, uchar lightLevel);
#endif
待做
RGB2HSV
ws2812B+单片机驱动相关推荐
- 单片机驱动DM9000网卡芯片(详细调试过程)【下】
http://hi.baidu.com/mcu8031/blog/item/c95903138671c625dc540171.html 单片机驱动DM9000网卡芯片(详细调试过程)[下] 4.验证初 ...
- 单片机led闪烁代码_单片机驱动LED发光二极管的电路以及编程
一.单片机驱动单个发光二极管 1.电路 代码: 1.点亮单个LED二极管 #include<reg51.h> sbit LED1=P1^0:void main(void){LED1=1:w ...
- Linux驱动(3)--单片机驱动与Linux驱动的区别
单片机驱动与Linux驱动的区别 1. MCU与MPU的区别 2. 单片机驱动与Linux驱动的区别 1. MCU与MPU的区别 首先我们先聊一下MCU与MPU之间的区别然后在去关心两者的驱动的不同. ...
- 控制led闪烁次数_单片机驱动LED灯的进阶之路
对于大多数单片机的学习者或者是从事单片机行业的工程师来说,单片机驱动LED闪烁起来的时候,基本都是我们入坑的开始,同时当时的那种兴奋与喜悦都是难以忘怀的,从LED灯亮起,到闪烁,再到各种流水灯,能开心 ...
- K_A08_004 基于 STM32等单片机驱动MX1919模块按键控制直流电机正反转加减速启停
目录 一.资源说明 二.基本参数 1.参数 2.引脚说明 三.驱动说明 1.MX1919模块驱动时序 2.对应程序: 3.PWM信号 四.部分代码说明 接线说明 1.STC89C52RC+MX1919 ...
- 【经验分享】调试STM32F107VC单片机驱动DP83848以太网PHY芯片时遇到的问题
调试时使用的程序:https://blog.csdn.net/ZLK1214/article/details/105457370 [杜邦线(或普通电线)影响时钟信号的完整性] 笔者调试STM32F10 ...
- 【解决方案】STM32L152单片机驱动段码LCD屏,执行HAL_LCD_Init函数失败返回HAL_TIMEOUT,长时间卡在LCD_FLAG_RDY的while循环里面的解决办法
STM32L152单片机驱动段码LCD屏,HAL_LCD_Init函数执行失败,卡在LCD_FLAG_RDY里面,函数返回HAL_TIMEOUT /*!< Wait Until the LCD ...
- 按键控制c51单片机驱动unl2003控制步进电机正反转停止及程序调速-萌新入门
** 按键控制c51单片机驱动unl2003控制步进电机正反转停止及程序调速 ** 分享一个萌新入门小工程 一.原件连接: 第一种直接用51开发板 第二种用最小单元加unl2003驱动 二.开发板电路 ...
- 液晶显示屏的C语言编码,AT89C51单片机驱动液晶显示汉字C语言
此程序的完整工程文件下载:http://www.51hei.com/f/8952lkj_c.rar 上图是原理图及其仿真效果. /********************************** ...
- 单片机驱动LM75采集温度
多种型号单片机驱动LM75采集温度 LM75简介 引脚说明 寄存器说明 测试程序 arduino程序 89c51程序 STM32程序 原文链接:https://www.yourcee.com/news ...
最新文章
- 第五个页面:更多电影页面
- 关于Latex一个简单例子
- 研发流程与项目管理之关系
- 真的,太多人辜负了.NET5!
- mysql2008优化_SQL server 2008 数据库优化常用脚本
- bzoj 1488: [HNOI2009]图的同构
- excel VBA编程入门,自定义excel数据库模板生成sql语句
- 安装 LaserJet 1020 时这个设备的驱动程序丢失了一个必需的项,这可能是由于 inf 是为 Windows 95 或更新版本而写的。联系您的硬件供应商。
- 3dmax导出unity3d模型设置
- 使用费马小定理和欧拉定理计算余数
- 万字长文看看.NET的前世今生与将来
- UVALive 7456 Least Crucial Node
- 家里的电脑通过电信宽带设置成外网服务器
- 【网络安全】重放攻击(Replay Attacks)
- 2014Esri中国用户大会亮点系列之——典型案例与应用阐释新一代WebGIS
- PMP续证流程全解析
- 用c语言破解数控机床plc密码,各种机床系统密码大全,赶紧收藏 以备急用
- Sumo 搭建交叉路口交通流仿真平台
- 关于贝加莱Modbus通讯的总结
- ubuntu下使用360wifi2