单片机教程网

电脑版
提示:原网页已由神马搜索转码, 内容由www.51hei.com提供.
查看:4909|回复:19

用ws2812b灯珠制作32位摇摇棒

 [复制链接]
ID:885138发表于 2021-2-28 18:50来自手机|显示全部楼层
用了一片hc89s003,32个ws2812b灯珠(5050),8只104电容一个滚珠开关,一个带保护板的锂电池(160mAh),一个电源开关,一个USB口,简易充电电路,导线及0欧贴片电阻若干,还有30cm长的pvc线槽。
制作小技巧:
一、ws2812灯珠旋转个小角度,直接手拉手串接,电路简洁(图三,灯串两侧+-电源,第一灯外接输入);
二、滚珠开关斜向上45度左右安装;
三、usb口可用于充电,同时借用usb的D+/D-改为串口txd/rxd,接自制一条假usb真串口线时又可下载固件,很方便。下方串口下载四针仍保留;
四、电路除单片机(ssop20封装,图中转接板背面)和usb接口用了pcb板,其余均用导线加热熔胶方式,适合单件DIY;
五、软件参照论坛搜到的普通led灯摇摇棒程序,最低层改用了ws2812b驱动,延时参数边试边调整。
上加工后的实物图(摇时的闪烁图肉眼可见连续效果,手机拍不了)
IMG_20210228_180827.jpg
IMG_20210228_181042.jpg
IMG_20210228_181129.jpg

评分

黑币 +50
收起理由
+ 50
共享资料的黑币奖励!

查看全部评分

ID:1112801发表于 2024-3-12 18:51|显示全部楼层
npn 发表于 2021-3-1 11:38
ws2812b 并不适合制作摇摇棒(最多只能显示出几种颜色),因为内部RGB芯片是通过PWM驱动的LED,只有线性驱动 ...

线性驱动用什么LED
ID:698161发表于 2023-3-27 14:31|显示全部楼层
沙发备用
ID:69115发表于 2021-3-10 01:41|显示全部楼层
楼主说的很好 PWM 亮度,在运动中显示,就变成光点的运动长度了.
ID:885138发表于 2021-3-3 14:16来自手机|显示全部楼层
yanhengbo 发表于 2021-3-3 14:04
那是否可以理解为:低于400HZ可以显示真彩,高于400HZ,就是8位色?

应该是指2.5mS周期内灯珠基本不动时可显真彩,与运动速度有关
ID:63570发表于 2021-3-3 14:04|显示全部楼层
xxd0708 发表于 2021-3-3 13:19
ws2812b有三路独立的8位pwm,如果灯珠静止,占空比就表现为该静止点的三路灯的亮度,理论可显24位真彩。
...

那是否可以理解为:低于400HZ可以显示真彩,高于400HZ,就是8位色?
ID:885138发表于 2021-3-3 13:19来自手机|显示全部楼层
yanhengbo 发表于 2021-3-3 09:52
这么说,WS2812灯里面的驱动是三颗R,G,B灯共用的一个PWM?分不同时段驱动3颗灯吗?我理解是3个PWM同时驱 ...

ws2812b有三路独立的8位pwm,如果灯珠静止,占空比就表现为该静止点的三路灯的亮度,理论可显24位真彩。
但ws2812b的pwm周期为2.5mS(400Hz),未考虑到快速运动场景。故灯珠快速运动时(平移与旋转),占空比就表现为一个周期内运动幅度中亮灯状态运动长度的大小,而不能表现为某个单点的亮度,即在某个具体点三路灯各有亮或暗两种状态,共2的3次幂=8种组合,也就是只有8色之一。
所以我前文所指出的,静可显真彩但做不了摇摇棒或旋转屏,动可做摇摇棒或旋转屏但只有8色。
ID:63570发表于 2021-3-3 09:52|显示全部楼层
xxd0708 发表于 2021-3-1 20:42
pwm是脉宽调制,即调节亮与灭的时间,亮时100%亮度,灭时0%亮度,理论上需要25%亮度时就让亮的时长占一个 ...

这么说,WS2812灯里面的驱动是三颗R,G,B灯共用的一个PWM?分不同时段驱动3颗灯吗?我理解是3个PWM同时驱动的R,G,B,如果是3个PWM同时驱动,应该就是真彩了吧?
ID:390416发表于 2021-3-2 22:11|显示全部楼层
npn 发表于 2021-3-1 11:38
ws2812b 并不适合制作摇摇棒(最多只能显示出几种颜色),因为内部RGB芯片是通过PWM驱动的LED,只有线性驱动 ...

关键是 PWM合成的颜色 也足够了,真要搞出1600万色,你眼睛能分辨出来?
ID:390416发表于 2021-3-2 22:07|显示全部楼层
xxd0708 发表于 2021-3-1 13:41
一手拿手机另一只手摇,视频有点晃眼哈

你需要DIY一个手机支架,推荐使用80mm的PVC排水管,荣耀10手机 插进去刚刚好
ID:390416发表于 2021-3-2 22:05|显示全部楼层
dj3365191 发表于 2021-3-2 11:32
WS2812比较适合Arduino驱动,WS2812要求的频率要高一点

89单片机也可以驱动的,89C52驱动WS2812 http://www.51hei.com/bbs/dpj-170855-1.html
ID:58937发表于 2021-3-2 17:07|显示全部楼层
好作品 謝謝分享
ID:143767发表于 2021-3-2 11:32|显示全部楼层
WS2812比较适合Arduino驱动,WS2812要求的频率要高一点
ID:885138发表于 2021-3-1 20:42来自手机|显示全部楼层
yanhengbo 发表于 2021-3-1 16:08
请教,为什么PWM的只能显示几种颜色,而线性的可以真彩,是什么原理呢?谢谢。

pwm是脉宽调制,即调节亮与灭的时间,亮时100%亮度,灭时0%亮度,理论上需要25%亮度时就让亮的时长占一个周期的25%,当时周期不能太大否则会感觉到闪烁。
现在看三色灯,如需RGB分量大小之比为3:2:1,pwm模式下其实是三色的时长为3:2:1,在灯珠静止时,那看起来是亮度之比(混色成某种橙黄色);而摇摇棒是动态的,所以看起来是摆动宽度之比,即此比例下实际一个周期有三段颜色,第一段RGB都亮(白色),第二段为R+G(黄色),第三段为R(红色),而不是合成色。
所以ws2812之类的彩灯如用于摇摇棒,实际只能显示8种颜色的点阵(R,G,B,R+G,R+B,G+B,R+G+B和0,即红绿蓝黄橙青白黑),数值的大小可改变8色之1的点阵扫过的宽度,但不能产生新的颜色。
综上,用ws2812灯时,静的时候可以混色,但不能产生平面效果;摇的时候可以产生平面效果,但只有8色。8色显字或简单图案,玩玩是够了,但真彩还是别想了。
一不小心在手机上输了这么多字 :-P

评分

黑币 +40
收起理由
+ 40
回帖助人的奖励!

查看全部评分

ID:63570发表于 2021-3-1 16:08|显示全部楼层
npn 发表于 2021-3-1 11:38
ws2812b 并不适合制作摇摇棒(最多只能显示出几种颜色),因为内部RGB芯片是通过PWM驱动的LED,只有线性驱动 ...

请教,为什么PWM的只能显示几种颜色,而线性的可以真彩,是什么原理呢?谢谢。
ID:885138发表于 2021-3-1 13:41|显示全部楼层
一手拿手机另一只手摇,视频有点晃眼哈

VID_20210301_132547.zip

18.04 MB, 下载次数: 29, 下载积分: 黑币 -5

ID:885138发表于 2021-3-1 12:33来自手机|显示全部楼层
npn 发表于 2021-3-1 11:38
ws2812b 并不适合制作摇摇棒(最多只能显示出几种颜色),因为内部RGB芯片是通过PWM驱动的LED,只有线性驱动 ...

是的,所以只能玩玩。程序里仅设了6种颜色,比单色或双色稍强一点。不过线路的确比没芯片的LED简单些

评分

黑币 +20
收起理由
+ 20
回帖助人的奖励!

查看全部评分

ID:57657发表于 2021-3-1 11:38|显示全部楼层
ws2812b 并不适合制作摇摇棒(最多只能显示出几种颜色),因为内部RGB芯片是通过PWM驱动的LED,只有线性驱动才可以摇出1600万种颜色。
ID:885138发表于 2021-3-1 07:31来自手机|显示全部楼层
51hei团团 发表于 2021-2-28 23:44
干的漂亮,能分享下程序吗?


/*
*32只WS2812+滚珠开关制作的摇摇棒*
*演示在上方16个LED上显示“你真棒”三个汉字
*CPU:HC89S003F4 16K bytes flash ROM, 256+256 bytes data RAM
*WS2812 接P22(推挽驱动) ,滚珠开关接P00(下降沿中断方式)
*晶振频率:32MHz,Fosc 16MHz
*程序版本:V1.00
*硬件平台:003F4 V1.00

*编写软件:Keil uVision4
*编写:xxd0708

*声明:本程序只供学习使用,未经作者许可,不得用于其它任何用途
*/

#define ALLOCATE_EXTERN
#include "HC89S003F4.h"
#include< intrins.h>






/**********************************************************
程序名称:LED摇摇棒显示64*16像素
简要说明:外部中断方式INT0显示;取模方式:纵向取模、字节倒序
(取点方式:纵向8点上高位,字节排列:上到下左到右)
**********************************************************/

sbit WS2812_IO = P2^2     ;


u8 KY;     //防止重影的控制变量    
u8 cont_rock=0;      
u8 cont_col=0;
u8 col_r,col_g,col_b;


// 你(0) 真(1) 棒(2)
code u8 dat_word1[]=
{
0x00,0x80,0x01,0x00,0x06,0x00,0x1F,0xFF,0xE0,0x00,0x02,0x08,0x04,0x30,0x18,0xC0,
0xF0,0x02,0x10,0x01,0x13,0xFE,0x10,0x00,0x10,0x80,0x14,0x60,0x18,0x18,0x00,0x00,/*"你",3*/
0x00,0x08,0x20,0x08,0x20,0x09,0x2F,0xFA,0x2A,0xAC,0x2A,0xA8,0x2A,0xA8,0xFA,0xA8,
0x2A,0xA8,0x2A,0xA8,0x2A,0xAC,0x2F,0xFA,0x20,0x09,0x20,0x08,0x00,0x08,0x00,0x00,/*"真",4*/
0x08,0x20,0x08,0xC0,0x0B,0x00,0xFF,0xFF,0x09,0x00,0x08,0x80,0x22,0x48,0x2A,0x88,
0x2B,0x28,0x2E,0x28,0xFA,0xFF,0x2A,0x28,0x2B,0x28,0x2A,0x88,0x22,0x48,0x00,0x00,/*"棒",5*/
};



//延时子函数-16Mhz 1ms延时
void delayMs_16Mhz(u16 ms)
{
     u16 j;
     for(; ms>0; ms--)
         for(j=1596; j>0; j--);
}

//延时函数-16Mhz 1us延时
void delayUs_16Mhz(u8 us)
{
     for(; us>0; us--)
     {
         _nop_();
         _nop_();
         _nop_();
     }    
}


void ws2812_rst(void)
{    

     WS2812_IO = 0;
     delayUs_16Mhz(80);
}

void ws2812_write_byte( u8 dat)
{    
     u8 i = 8;
     dat<< = 1;       //最高位进入CY
     while(i)
     {
           //高电平时间小于0.45uS为逻辑0,大于时为逻辑1
         WS2812_IO = 1;
         //如果主频较高可在此处适当增加_nop_();
         _nop_();
         _nop_();
         _nop_();
         _nop_();
         WS2812_IO = CY;
         _nop_();
         _nop_();
         _nop_();
         _nop_();
         //如果主频较高可在此处适当增加_nop_();
         WS2812_IO = 0;     //位发送完保持低电平,时间不大于50us。否则复位
         _nop_();
         _nop_();
         _nop_();
         _nop_();
         dat<< = 1;       //最高位进入CY
         i--;            
     }

}

/*显示关闭*/
void display_off(void)
{
     uchar i;
     i=0;
     while( i< 32 )
     {
         ws2812_write_byte( 0x00);
         ws2812_write_byte( 0x00);
         ws2812_write_byte( 0x00);
         i++;
     }
     ws2812_rst();
}
  
/*显示子程序 在上方16个LED上显示三个汉字*/
void display_3word(void)
{
     uchar i,j,temp;
     //ws2812_rst();
     i=0;
     j=0;

     while(j<96)       //3个汉字3*16*2个字节
     {
         i=0;
         while( i< 16 )       //下16不显示 可修改
         {
             //与普通LED主要更改点,有显示时发三个分量数据,否则发三个0
             ws2812_write_byte( 0x00);
             ws2812_write_byte( 0x00);
             ws2812_write_byte( 0x00);
             i++;
         }        
         temp = dat_word1[j+1];//上方16位先送第二字节(依取模方式而定)
         i=0;
         while( i< 8 )
         {
             if(temp&0x01)       //从低到高送显示位(依取模方式而定)
             {
                 //与普通LED主要更改点,有显示时发三个分量数据,否则发三个0
                 ws2812_write_byte( col_g);
                 ws2812_write_byte( col_r);
                 ws2812_write_byte( col_b);
             }
             else
             {
                 //与普通LED主要更改点,有显示时发三个分量数据,否则发三个0
                 ws2812_write_byte( 0x00);
                 ws2812_write_byte( 0x00);
                 ws2812_write_byte( 0x00);
             }
             i++;
             temp = temp >>1;     //下一位
         }
         temp = dat_word1[j]; //上方16位再送第一字节(依取模方式而定)
         while( i< 16 )
         {
             if(temp&0x01)       //从低到高送显示位(依取模方式而定)
             {
                 //与普通LED主要更改点,有显示时发三个分量数据,否则发三个0
                 ws2812_write_byte( col_g);
                 ws2812_write_byte( col_r);
                 ws2812_write_byte( col_b);
             }
             else
             {
                 //与普通LED主要更改点,有显示时发三个分量数据,否则发三个0
                 ws2812_write_byte( 0x00);
                 ws2812_write_byte( 0x00);
                 ws2812_write_byte( 0x00);
             }
             temp = temp >>1;   //下一位
             i++;
         }
      
       delayUs_16Mhz(200);  //延时量自行调整,当摇的速度一定时,延时越大,字越宽但能显示字数减少
         j +=2;     //汉字下一列
     }

     //发送完三个汉字后清屏    
     display_off();

}


/*中断服务程序*/
void intersvr0(void) interrupt 0 using 1
{

     //当从右向左摇时,产生中断,KY取反变为1,此时不显示,不运行下面的语句
     delayMs_16Mhz(10);
     if(~P0^0)//10mS消抖
     {
         cont_rock ++;       //判断中断次数
         if(cont_rock >= 20)
           cont_rock = 20;
     //每个摇动来回滚珠开关会在摆幅两端分别产生下降沿中断,只提取其中一次
           delayMs_16Mhz(30);         //延时量改变首字显示位置,越大越靠后
         if((cont_rock&0x01) == 0) //偶数时显示(或奇数次,依初值和开关方向而定)
         {
           display_3word();  
         }
         else
         {
             display_off();
         }
     }
   PINTF0& = 0xFE;//  HC89S003需软件清标志位INT0F
}



/**************************************************************************************
   * @实现效果     将Fosc设置为16MHz,Fcpu设置为16MHz
**************************************************************************************/
void main()
{

/************************************系统初始化****************************************/
     WDTCCR = 0x00;                         //关闭看门狗
                               //本例程为方便测试关闭看门狗,实际使用中,建议客户打开看门狗,详见WDT复位例程
     CLKSWR = 0x51;                         //选择内部高频RC为系统时钟,内部高频RC 2分频,Fosc=16MHz
     CLKDIV = 0x01;                         //Fosc 1分频得到Fcpu,Fcpu=Fosc

/**********************************相关配置初始化**************************************/

     P2M1 = P2M1&0xF0|0x08;                 //WS2812信号 P22设置为推挽输出
     P0M0 = P0M0&0xF0|0x06;               //滚珠开关P00设置为带施密特上拉输入     (作为外部中断)
     P00DBC = 0xFF;                   //滚珠开关P00端口消抖,约250uS

     PITS0 = PITS0&0xFC|0x01;       //外部中断0下降沿中断
     EX0=1;                               //开外部中断
     EA=1;                               //开总中断

     cont_col = 0;  //颜色索引初值
     display_off();

     while(1)     //主程序中只检测按键
     {
         cont_rock = 0;
         delayMs_16Mhz(1000);
         if(cont_rock == 0) //检测1秒内摇摆次数,如无则颜色回初值
         {
             cont_col = 0;
         }
         else
         {
             //颜色索引每秒加一改变一次颜色
             if(cont_col >=5)               //暂用6种颜色
             {
               cont_col = 0;
               }
               else
               {
                   cont_col ++;     //改变颜色
               }
               //按索引赋显示颜色分量值
             col_r = 0;
             col_g = 0;
             col_b = 0;
             switch(cont_col)
             {
               case 0: col_r = 0x20;break;
               case 1: col_g = 0x20;break;
               case 2: col_b = 0x20;break;
               case 3: col_r = 0x20;col_g = 0x20;break;
               case 4: col_g = 0x20;col_b = 0x20;break;
               case 5: col_b = 0x20;col_r = 0x20;break;
               default: cont_col=0; col_r = 0x20;break;
             }
         }        

     }

}


评分

黑币 +20
收起理由
+ 20
回帖助人的奖励!

查看全部评分

ID:328014发表于 2021-2-28 23:44|显示全部楼层
干的漂亮,能分享下程序吗?

手机版|小黑屋|51黑电子论坛|51黑电子论坛6群QQ管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网