找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5471|回复: 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 (927.33 KB, 下载次数: 182)

IMG_20210228_180827.jpg

IMG_20210228_181042.jpg (740.6 KB, 下载次数: 195)

IMG_20210228_181042.jpg

IMG_20210228_181129.jpg (737.48 KB, 下载次数: 179)

IMG_20210228_181129.jpg

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏4 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:328014 发表于 2021-2-28 23:44 | 只看该作者
干的漂亮,能分享下程序吗?
回复

使用道具 举报

板凳
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;
                        }
                }               

        }

}


评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

地板
ID:57657 发表于 2021-3-1 11:38 | 只看该作者
ws2812b 并不适合制作摇摇棒(最多只能显示出几种颜色),因为内部RGB芯片是通过PWM驱动的LED,只有线性驱动才可以摇出1600万种颜色。
回复

使用道具 举报

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

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

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

6#
ID:885138 发表于 2021-3-1 13:41 | 只看该作者
一手拿手机另一只手摇,视频有点晃眼哈

VID_20210301_132547.zip

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

回复

使用道具 举报

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

请教,为什么PWM的只能显示几种颜色,而线性的可以真彩,是什么原理呢?谢谢。
回复

使用道具 举报

8#
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

评分

参与人数 1黑币 +40 收起 理由
admin + 40 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

9#
ID:143767 发表于 2021-3-2 11:32 | 只看该作者
WS2812比较适合Arduino驱动,WS2812要求的频率要高一点
回复

使用道具 举报

10#
ID:58937 发表于 2021-3-2 17:07 | 只看该作者
好作品 謝謝分享
回复

使用道具 举报

11#
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
回复

使用道具 举报

12#
ID:390416 发表于 2021-3-2 22:07 | 只看该作者
xxd0708 发表于 2021-3-1 13:41
一手拿手机另一只手摇,视频有点晃眼哈

你需要DIY一个手机支架,推荐使用80mm的PVC排水管,荣耀10手机 插进去刚刚好
回复

使用道具 举报

13#
ID:390416 发表于 2021-3-2 22:11 | 只看该作者
npn 发表于 2021-3-1 11:38
ws2812b 并不适合制作摇摇棒(最多只能显示出几种颜色),因为内部RGB芯片是通过PWM驱动的LED,只有线性驱动 ...

关键是 PWM合成的颜色 也足够了,真要搞出1600万色,你眼睛能分辨出来?
回复

使用道具 举报

14#
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同时驱动,应该就是真彩了吧?
回复

使用道具 举报

15#
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色。
回复

使用道具 举报

16#
ID:63570 发表于 2021-3-3 14:04 | 只看该作者
xxd0708 发表于 2021-3-3 13:19
ws2812b有三路独立的8位pwm,如果灯珠静止,占空比就表现为该静止点的三路灯的亮度,理论可显24位真彩。
...

那是否可以理解为:低于400HZ可以显示真彩,高于400HZ,就是8位色?
回复

使用道具 举报

17#
ID:885138 发表于 2021-3-3 14:16 来自手机 | 只看该作者
yanhengbo 发表于 2021-3-3 14:04
那是否可以理解为:低于400HZ可以显示真彩,高于400HZ,就是8位色?

应该是指2.5mS周期内灯珠基本不动时可显真彩,与运动速度有关
回复

使用道具 举报

18#
ID:69115 发表于 2021-3-10 01:41 | 只看该作者
楼主说的很好 PWM 亮度,在运动中显示,就变成光点的运动长度了.
回复

使用道具 举报

19#
ID:698161 发表于 2023-3-27 14:31 | 只看该作者
沙发备用
回复

使用道具 举报

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

线性驱动用什么LED
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

Powered by 单片机教程网

快速回复 返回顶部 返回列表