我的账户
中国电子DIY

科技成就未来

亲爱的游客,欢迎!

已有账号,请

如尚未注册?

【光立方】初级教程,含 原理图+源代码+经验

  [复制链接]
41853 94
爱上科技 发表于 2015-5-2 09:28:48 | 只看该作者 |阅读模式 打印 上一主题 下一主题

光立方,我在三年前从一个国外网站上就见到了。那时候刚开始玩电子,就心血一热,开始做光立方。费了一个星期的功夫才把主题的LED显示体搭建完成了,而且当时的焊接功底实在不敢恭维。(后面有图为证)

后来由于毕业的缘故,没有继续做下去,光立方被我当做装饰品放再书桌上。

今年上半年的时候,看到了很多人的作品,想起我那个光立方。回忆起当年的时光,决定将它继续做完。

很顺利,不管是硬件搭建还是软件编程。

我看了很多教程,相比来说,我最开始看的老外的比较好。他们用的元件并不是我们常用的元件,但是上面的理论讲解很重要。

如果真的想做好,必须懂得原理,而不是一味的仿造。不知道有哪些朋友已经做过很好的教程,我把我的想法分享出来,供大家参考借鉴。

概要

首先,我的作品并没有完成多么炫的效果,我只是搭建了一个设计的平台。尤其是比较容易修改的显示程序,要炫的效果,完全可以大家自己设计!!!!

第二,硬件上,可能与平时大家所见的不同(受多个设计方案的影响,没选好一个方案),但我会介绍如何元件替代(包含单片机、行列驱动芯片的替换)。

第三,内容写得比较抽象,希望大家仔细看,并且多看别人作品,多看程序代码,先思考了再问,不是说不想回答,只是不想回答没有思考过的问题。

第四,设计属于睡神耗子自己所想的,所以和你以前见过的光立方可以不一样的架构。一位网友给我看了另一种电路,确实是设计精妙。不过本设计对于设计程序,以及理解是比较容易的。可以作为初级的教程来看。

第五,设计使用了大量网络的上图片资源。由于自己在制作的时候没有留下照片,而且说实话,做得挺难看的!所以不多配自己的图了。

作品展示

设计的挺难看,各位大侠就别计较了,各位菜鸟就知道有这么几个部分组成就可以了。






这是我仿造的杜洋的光立方显示效果(懒,未仿造全部,部分效果也不好)

以上只是说明我能造出来啊!!!

这是源文件(修正电路图的错误):

光立方.rar (275.37 KB, 下载次数: 234)



下面是重头戏。

第一.光立方主体焊接

这个没有什么好法子,大家慢慢,仔细的焊接吧。考验焊接功夫和耐性的时刻到了。

给几个别人的图做参考。



先找个木板钻8*8=64个孔,(什么,你没有木板和电钻。那找个替换,真不行,上纸箱板)。每个孔的间距一样,具体多长,量一下LED的负极(短的管脚)。比那个长度小大概3~5mm就差不多了(具体值,大家量一量就行了)。

然后弯管脚。为了确保光立方是个正方体,一般情况,都是弯短脚(负极)。

注意方向任意,但是所有的LED是一个方向,具体方向,就看个人喜好了。

8个LED焊接在一块,一共焊接8条,然后将这8条的LED灯链的一端(短引脚没焊接)焊接在一块。

为了结实,再在中间及另一端焊接个铜线。注意,要保证铜线是焊接在负极(短管脚上)

这样,一层就完成了。

总结下,焊接的要领是将一层的负极接到一块。(当然你非要正极接一块,也是可以的)。

如此反复,总共焊接8层,然后,将相同的长管脚焊接在一起。(或者,你一层层向上盖楼也行~!~)。

你会发现每一层都会空余一个管脚未焊接,我就把这个管脚当做层的控制端用了。

如上图所示,会发现每一层相同位置的LED的正极(长管脚,红色所指的)连接在一起,相信聪明的童鞋,知道如何控制光立方的某一个灯亮了:

在正极上加正电压,在层的控制端上加负电压即可了。

第二:显示原理

为了下面层驱动与阵列驱动的讲解,想说明一下光立方的显示原理。

玩过LED点阵或多位数码管的童鞋,更容易理解——对,动态扫描原理。

其实不同层的灯是不可能同是亮的。那么人怎么感觉亮呢,只要LED等闪得足够快,就可以了。人眼的视觉暂留大概24帧/秒(这也是为什么电影大多是这个值,请查看你电影文件的属性)。那么只要你能够将LED灯闪到这个速度就没问题了。对于电路来书,μs(微妙)级是很容易实现的,所以,这不是问题。

光立方其实就相当于64*8的LED点阵。你理论上只能让一层(64)的灯可以随意亮灭(一直保持,并且不相互干扰)。

当一定的速度,先点亮第一层,然后再点亮第二层……一直循环,就达到你要的效果了。

写得抽象,不懂得童鞋,去看看LED点阵,或者多位数码管的显示原理就可以。

第三:层驱动电路

层选,是要求这一层的控制端加负电压(因为这一层的负极都接一块了)。那么我们很容易的想用三极管的开关作用就可以了。对我就直接使用的三极管。

****有热心网友发现了我的错误,8550是PNP型三极管,而我写文章,画电路都写的NPN,我查看了下,是我自己的疏忽,真实设计是PNP,程序也是按照PNP写的。在此,十分感谢给予批评帮助的人。*******

MCU是单片机控制,一般要串个电阻,用来限流,这里讲原理,就不画了(具体去看附件中的原理图)。Layer_x指某一层的控制端。加了一个上拉电阻,保证平时状态下控制端处在高电压(那样就不会亮灯了。)

当MCU输出高时,PNP三极管就导通了,Layerer_x就连接到地上,那么层选就打开了。

PNP型三极管有很多,比如我用的就是S8550,相信许多童鞋是用过的。

有些童鞋说,他们见别人用的不是三极管,而是ULN2803。我以前是没用过的,查了查:是八路NPN达林顿连接晶体管,也就是说其实里面就相当于集成了8个三极管,用起来更方便。所以,大家手头有什么就用什么呗。

啥,ULN2803怎么用?看下图,我懒得画封装图了,用一个插座代替了,管脚顺序可没有改,别照抄啊!!!!

我的设计里,用了16个S8550,2个一组。原因是为了防止一个三极管承受不了这么大的电流(64个LED灯的电流)。

第四.阵列驱动

这是我起的名字,也就是一层64个灯的驱动。

64个灯,驱动那是相当麻烦了,用单片机直接驱动是不现实的,管脚不够,电流太大。那么我们考虑拓展单片机的IO口。

用很多芯片是可以用的:例如HC164, HC377,HC573,HC574,HC595等等。只要有8位输出就可以。大家用的比较多的应该是HC573,最初的时候我照着葫芦画瓢,非要买HC574。它俩没有什么大区别,只是锁存的信号不一样罢了。

借用一个574的图(573一样的接法,CLK改为HC573的LE即可)。有八片HC574,每一个HC574可以输出8位,这样就可以同时输出64位了,对应64个灯。

HC138是为了节省管脚的,我图省事,就直接用单片机的管脚接每个片子。

数据线是共用的,一次给一个片子写数据,轮流写,将所有的片子写完。那么阵列驱动数据就完成了。

当使能输出(许多片子有OE端),层选打开时,就可以点亮特定的灯了。

附HC164和HC595的驱动图。这两个片子都是串行转并行了,使用的单片机管脚更少一些!!

注意:所有输出端要加限流电阻,至于加多大,要看你的LED灯了。一般情况下的直插LED灯,红色的加的电阻大一些,绿色的小一些,实际情况自己测试就可以了。

一定要先计算一下你需要多大的电流,因为这关系到你选用多大电流的电源。

当然,一般情况下,最多亮64个LED(瞬间只能亮64个)。一般的充电器类都能达到这个电流水平(什么,你要用电池!别扯了***)。

第五.控制板

可以选用的单片机是很多的。

考虑管脚够用,至少也要十几个IO口吧。用个DIP40,LQFP32妥妥的。

51.AVR.PIC……随便哪个都可以,方便、易学、好买上选择,用STC的51就行了。我用了库存的STC12C5A60S2,相信这个单片机很多人都在用。

当然你用STC89C系列或者STC15系列也是可以的,他们区别在定时上,我使用的是定时器,你可以用STC给的工具来修改定时时间。


第六.程序

相信很多人都不喜欢这个。

见好多童鞋做好的电路,到处找程序。为了不改程序,能照搬电路就照搬。当出了问题也不知道是硬件还是软件的问题。

好吧,恰好我是苦逼的程序员。好歹也写了两年程序。

以下是讲解,其实讲得不好,因为自己的水平,还有程序这事就是多磨多练的功夫。

我用的是KEILC51,相信很多童鞋,看到这么多文件就傻了。不用担心,文件多了,许多文件你根本不用理解。

Main,是主程序。App是应用文件,comAssistant是串口助手,stc12cIntProcess是中断函数。还有一堆displayxx是显示效果函数。

简单的说,主程序调用APP文件中的函数,App函数又调用displayxx(xx表示01,02什么的)函数,来显示特效。

由于我使用的是HC574+MCU层选,但是有很多其他方式可以使用。修改app.c文件中的CubeLoop函数即可。由于各种方案很多,如有需求,请留言请教之。

我将显示效果设计成8*8的数组。因为数组元素是unsigned char(uint8_t)型,也就是说每一位表示一个LED灯。你只要在displayxx函数里修改cubeBuf[8][8]这个数组即可。 说明一下,这个数组是如何对应的光立方的LED的。数组每一个元素(char型),对应每一层所有相同位置的LED灯(即正极相连的),请看第7图那个红色对应的一条灯链。 还有,我为了方便设计,将更新显示最小的单位是100ms,即0.1s。也就是说,你想显示刷新的速度最快是100ms,其实这个时间是相对比较长了,可以改短一点,程序在stc12cIntProcess.c中第61行:

if(++cubeCounter>10)

{

cubeCounter = 0;

cubeUpdateFlag = TRUE;

}

把10改小一点就可以了。




参与人数 3贡献 +8 刀币 +20 收起 理由
逆天小白兔 + 8 + 5
中心小学 + 5 赞一个!
diyhome + 10 支持DIY精神!

查看全部评分总评分 : 贡献 +8 刀币 +20

收藏
收藏26
分享
分享
支持
支持2
反对
反对0

精彩评论94

跳转到指定楼层
推荐
 楼主| 爱上科技 发表于 2015-5-2 09:29:07 | 只看该作者
  1. /* Extern Fuction -------------------------------------------------------------*/

  2. extern bool_t Display01(void);

  3. extern bool_t Display02(void);

  4. extern bool_t Display03(void);

  5. extern bool_t Display04(void);

  6. extern bool_t Display05(void);

  7. extern bool_t Display06(void);

  8. extern bool_t Display07(void);

  9. app.c文件中的void CubeBufReload()函数式调用显示函数的地方。

  10. /*Reload graphical or switch grahical*/

  11. switch(cubeGraphical)

  12. {

  13. case GRAPH_01:

  14. if( TRUE == Display01())

  15. {

  16. cubeGraphical = GRAPH_02;

  17. cubeStage = 0xFF;

  18. }

  19. break;

  20. case GRAPH_02:

  21. if( TRUE == Display02())

  22. {

  23. cubeGraphical = GRAPH_03;

  24. cubeStage = 0xFF;

  25. }

  26. break;

  27. case GRAPH_03:

  28. if( TRUE == Display03())

  29. {

  30. cubeGraphical = GRAPH_04;

  31. cubeStage = 0xFF;

  32. }

  33. break;

  34. case GRAPH_04:

  35. if( TRUE == Display04())

  36. {

  37. cubeGraphical = GRAPH_01;

  38. cubeStage = 0xFF;

  39. }

  40. break;

  41. case GRAPH_05:

  42. if( TRUE == Display05())

  43. {

  44. cubeGraphical = GRAPH_06;

  45. cubeStage = 0xFF;

  46. }

  47. break;

  48. case GRAPH_06:

  49. if( TRUE == Display06())

  50. {

  51. cubeGraphical = GRAPH_07;

  52. cubeStage = 0xFF;

  53. }

  54. break;

  55. case GRAPH_07:

  56. if( TRUE == Display07())

  57. {

  58. cubeGraphical = GRAPH_01;

  59. cubeStage = 0xFF;

  60. }

  61. break;

  62. default:

  63. cubeGraphical = GRAPH_01;

  64. cubeStage = 0xFF;

  65. break;

  66. }

  67. 函数很长,不用看这么多,看一个即可。

  68. case GRAPH_07:

  69. if( TRUE == Display07())

  70. {

  71. cubeGraphical = GRAPH_01;

  72. cubeStage = 0xFF;

  73. }

  74. break;

  75. 当前显示效果为DISPLAY07,如果显示完(TRUE==)成立,切换为显示效果GRAPH_01,cubeStage==0XFF指将显示阶段定位到:显示效果的第一个显示(显示效果是一连串的显示组成)。CubeStage==0xFF不懂得童鞋,就照抄就可以了。

  76. 继续,显示效果函数的格式也是好理解的,例如Display01()

  77. bool_t Display01(void)

  78. {

  79. uint8_t i,j;

  80. bool_t endFlag = FALSE;

  81. switch(cubeStage)

  82. {

  83. case 0: //Clear all

  84. for(i = 0;i<8;i++)

  85. {

  86. for(j=0;j<8;j++)

  87. {

  88. cubeBuf[i][j] = 0x00;

  89. }

  90. }

  91. break;

  92. case 1:

  93. cubeBuf[0][7] = 0x01;

  94. break;

  95. case 2:

  96. cubeBuf[0][6] = 0x01;

  97. break;

  98. case 3:

  99. cubeBuf[0][5] = 0x01;

  100. break;

  101. case 4:

  102. cubeBuf[0][4] = 0x01;

  103. cubeBuf[0][7] = 0x00;

  104. break;

  105. case 5:

  106. cubeBuf[0][3] = 0x01;

  107. cubeBuf[0][6] = 0x00;

  108. break;

  109. case 6:

  110. cubeBuf[0][2] = 0x01;

  111. cubeBuf[0][5] = 0x00;

  112. break;

  113. case 7:

  114. cubeBuf[0][1] = 0x01;

  115. cubeBuf[0][4] = 0x00;

  116. break;

  117. case 8:

  118. cubeBuf[0][0] = 0x01;

  119. cubeBuf[0][3] = 0x00;

  120. break;

  121. case 9:

  122. cubeBuf[1][0] = 0x01;

  123. cubeBuf[0][2] = 0x00;

  124. break;

  125. case 10:

  126. cubeBuf[2][0] = 0x01;

  127. cubeBuf[0][1] = 0x00;

  128. break;

  129. case 11:

  130. cubeBuf[3][0] = 0x01;

  131. cubeBuf[0][0] = 0x00;

  132. break;
  133. case 12:

  134. cubeBuf[4][0] = 0x01;

  135. cubeBuf[1][0] = 0x00;

  136. break;

  137. case 13:

  138. cubeBuf[5][0] = 0x01;

  139. cubeBuf[2][0] = 0x00;

  140. break;

  141. case 14:

  142. cubeBuf[6][0] = 0x01;

  143. cubeBuf[3][0] = 0x00;

  144. break;

  145. case 15:

  146. cubeBuf[7][0] = 0x01;

  147. cubeBuf[4][0] = 0x00;

  148. break;

  149. case 16:

  150. cubeBuf[7][0] = 0x03;

  151. cubeBuf[4][0] = 0x00;

  152. break;

  153. case 17:

  154. cubeBuf[7][0] = 0x07;

  155. cubeBuf[5][0] = 0x00;

  156. break;

  157. case 18:

  158. cubeBuf[7][0] = 0x0F;

  159. cubeBuf[6][0] = 0x00;

  160. break;

  161. case 19:

  162. cubeBuf[7][0] = 0x1F;

  163. break;

  164. case 20:

  165. cubeBuf[7][0] = 0x3F;

  166. break;

  167. case 21:

  168. cubeBuf[7][0] = 0x7F;

  169. break;

  170. case 22:

  171. cubeBuf[7][0] = 0xFF;

  172. break;

  173. case 25:

  174. endFlag = TRUE;

  175. break;

  176. default:

  177. break;

  178. }

  179. return endFlag;

  180. }

复制代码
至于显示效果的设计,修改displayxx.c文件即可。每一个文件中都只有一个bool_t Display01(void)程序,其中序号01对应displayxx.c文件的序号。该函数名一定要在display.h中声明,这样app.c文件才能调用。

这个有25个显示面组成的。

也就是每一个显示面都停留100ms,当然,你可以让多个显示面显示一个效果。

注意的是最后一个显示面一定要有这句话endFlag = TRUE;,这是说明这个显示效果结束了。

这样,程序我就解释完了,不过很抽象,大家想理解,就多研究程序,不懂就问。

我稍讲一下编译的问题,很多童鞋经常问为什么编译不出来,其实IDE已经告知的很清楚了。不懂就去网上搜搜,再不懂留言,至于像undefined这种编译错误最好不要问了。。。

还有很多人找不到代码的位置——啥,用搜索啊!KEIL工具栏有个望远镜的哪里有个输入框就是,windows下的程序基本上都是ctrl+F键可以直接调用搜索的!还有,跟踪函数,你看到一个函数,不知道函数体在哪里?点击到函数名中,右击选“go to define……”就可以了。睡神耗子先帮你到这了。

还有一个关键的地方,做显示库。也就是如何给cubeBuf[][]赋值。大家自己去研究下,看看显示出来什么样子就可以了。我写的显示函数是对应视频的显示效果。

可以确定的是cubeBuf[][]所有元素赋值为0xFF,就是光立方全亮,都是0x01就只显示一层,最上层或最下层,都是0x00,光立方全熄灭。

附件中有取模软件,兼容我的程序。有点抽象。大家要好好培养自己的立体感。。。
3#
安尚科技 发表于 2015-5-2 09:42:26 | 只看该作者
楼主帖子含金量高,支持一下
4#
zsoop 发表于 2015-5-2 10:46:47 | 只看该作者
感觉没什么用啊
只有一点观赏效果
5#
1399109998 发表于 2015-5-2 14:21:41 | 只看该作者
谢谢楼主分享、、、、、、、、、、、、、、、、、、、
6#
sdlcwhg 发表于 2015-5-2 14:29:47 | 只看该作者
高手作品,庞大的工程,欣赏。
7#
 楼主| 爱上科技 发表于 2015-5-2 14:32:54 | 只看该作者
zsoop 发表于 2015-5-2 10:46
感觉没什么用啊
只有一点观赏效果

现在很多东西都是用来欣赏的,
8#
a383793621 发表于 2015-5-2 15:29:43 | 只看该作者
大赞,高手!感谢分享
9#
电子爱好者6 发表于 2015-5-2 21:37:17 | 只看该作者
谢谢楼主分享
                 
10#
逆天小白兔 发表于 2015-5-2 23:53:05 | 只看该作者
赞赞赞脏1234567890每次都要编写字麻烦
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关注我们
中国电子DIY官方微信

客服电话:000-000-0000

客服邮箱:[email protected]

周一至周五 9:00-18:00

公司地址:深圳市南山区美丽湾大厦B座

Powered by Discuz! X3.4@ 2001-2013 Comsenz Inc.