POV(Persistence of Vision):是一種“視覺暫留”現象,每當人的眼睛在觀察物體之后,物體的映像會在視網膜上保留一段很短暫的時間。在這短暫的時間段里,當前面的視覺形象還沒完全消退,新的視覺形象有繼續產生時,就會在人的大腦里形成連貫的視覺錯覺。如將單片機控制的LED流水燈設備稍作改進,讓它動起來,就能神奇地顯示各種字符或圖案,其效果如漂浮在空中一般。 硬盤時鐘就是將淘汰、廢棄的硬盤改造或制作成一個時鐘。 這神奇的創意最早是由加拿大Alan Parckh提出的,在他的個人網頁里首次介紹了如何將一個廢舊的硬盤制作成時鐘,后來美國康奈爾大學的兩位大學生Jason Amsel和Konstantin Klitenik根據這個創意作了一個電子設計項目,這個項目中,除增加了一個帶觸摸功能的LCD屏,將雙色LED改成三色LED外,其他方面沒突破性的進展。真正讓這個創意耳目一新的是另一個美國人,他采用高亮度的RGB三色LED柔性燈條作光源,不但使顯示的亮度明顯增加,并能產生絢麗多彩的動態圖案。遺憾的是他的作品并非是真正意義上的時鐘,僅僅是演示而已。 這里做的硬盤時鐘將在他們的基礎上進行如下改進: 1) 使用專門的直流電動機驅動IC,讓硬盤的轉速可調,在降低轉速后,可進一步減小噪聲,同時有利于單片機的控制。 2) 將開機畫面與時鐘顯示有機結合,用mini型LED作為輔助顯示,一方面擴展顯示“年月日”信息,另一方面方便調時。 3) 時鐘的整個屏面一改過去的全黑局面,并增加時間刻度,方便辨識。 使制作的硬盤時鐘真正向實用性邁進了一大步。 一、POV項目 POV項目
| POV LED硬盤時鐘
| 發光體
| 18只RGB三色LED
| 運動方式
| LED處于靜止狀態,硬盤盤片旋轉
| 供電方式
| 外接電源,單電源,直流12V輸入
| 傳感器
| 光耦傳感器(光斷續器)
| 主控芯片
| AT89S52
| 調控方式
| 按鍵
| 功能
| 盤片上顯示“時分秒”,輔助顯示LED顯示“年月日”
|
1) 單片機:采用支持ISP下載功能的單片機,方便程序下載及調試。 2) LED:由于硬盤時鐘是靠透過一窄縫的光線來顯示發光顏色的,光的損失量很大,如果能選用高亮度的LED,考慮到為方便安裝LED,選用的是成品的高亮度RGB三色全彩柔性光條。 3) Mini型LED顯示模塊:為了讓硬盤時鐘更加方便實用,在硬盤時鐘前面另外增加一個輔助顯示屏,考慮到發光盤在視覺上的主導性,這個輔助屏盡量選用尺寸較小的mini型LED。 4) 傳感器:由于在硬盤的盤片上開有缺口,采用透射式光斷續器。 5) 主軸電動機驅動:主軸電動機為無刷無傳感器直流電動機,可以沿用原來硬盤板上的電路來驅動它。但這樣的方式問題很多:一是大多數情況下難以保證電動機常轉;二是轉速固定無法改變,相應噪聲和震動很大。采用專門的驅動IC驅動這個直流電動機。 6) 功能:除主要的發光盤面顯示很酷的“時分秒”信息外,輔助LED顯示屏還顯示“年月日”信息。另外,在開機狀態下,發光盤顯示多彩的色彩變換,輔助屏顯示如歡迎類的英文字符;在調試狀態時,輔助顯示屏提示和顯示調整項及調整值。 二、顯示原理及系統狀態轉移圖 1. POV LED硬盤時鐘的顯示原理 在高速旋轉的開口盤片下,用單片機控制LED的發光,并讓LED的閃爍與旋轉的細縫同步協調。也就是每當開細縫的圓盤轉到特定的位置,就讓LED閃現特定顏色的光,這樣就會讓我們的眼睛感覺到那個位置有一光條出現。 由于人眼有“視覺暫留”現象,只要我們在幾處特定的位置讓LED閃現所需要的光,就會讓我們眼睛產生圓盤上同時有幾個光條的錯覺。 將此原理進一步推廣,我們還可以讓整個圓盤發出五顏六色的光,在本制作中,我們以此原理,還在發光的表盤上增加時鐘刻度。
2. 系統狀態轉移圖 系統分為3種工作狀態:開機畫面狀態、正常顯示狀態和調整時間狀態,轉換通過“設置”按鍵來完成。
3. 系統框圖
三、硬件制作
1. 找一個廢棄或壞的硬盤,將硬盤廢物利用來制作時鐘。將其拆卸,取出所有零部件(電機除外),因為要利用的是硬盤的外殼、電機和盤片。
2. 直流電動機驅動電路原理圖
3. 主控部分原理圖
4. 找一塊鋁皮做成弧形,用來彌補硬盤盤片下方的空缺。
5. 準備背光光源,為了制作簡便,采用成品的RGB-LED全彩發光二極管柔性光帶,本例中光帶共用了18顆LED,此光帶自帶3M自粘膠,共陽極,DC12V驅動電源。
6. 將硬盤盤片用鋸條開一條鋸縫,該鋸縫有兩個作用,一是作為轉速計數用的基準點,二是作為透過背光顯示時鐘的重要顯示的必要條件。為了讓背光顯得稍微亮一點,再用白紙剪一個底圓作為背光襯底。
7. 將白色襯底粘于盤片底部,弧形鋁條沿弧形支撐固定于硬盤兩邊。
8. 準備兩塊印制板,一塊作為前面控制板(根據硬盤弧形開出印板的弧形),一塊作為背后的主控制板,這里采用了易購的洞洞板吧。
9. 準備光斷續器小板,為了檢測到硬盤的轉速和計算出時鐘指針的具體位置,用了遮蔽式光斷續器檢測硬盤盤片的那個鋸縫。
10. 將光斷續器小板安裝在硬盤盤體的左上角這個位置正好合適,再將柔性LED發光條安裝貼在硬盤沿盤片一周的盤體內側上。
11. 焊接前面控制板,由于前后板子連接線有點多,為了美觀,采用了接插件。
焊接排線
12. 焊接后面主控板
焊接飛線
13. 聯機通電,將程序燒寫進單片機,為了方便將主控板上預留了ISP燒錄接口。
14. 拼接裝配,將按鈕上寫上相應的文字。
15. 開機測試
視頻效果:youku視頻:
[size=14.399999618530273px]源程序如下:
[size=14.399999618530273px]ds12887.頭文件程序:[size=14.399999618530273px]- #include <absacc.h>
- //BCD碼轉換
- #define NUM2BCD(x) ((((x)/10)<<4)|(x%10))
- #define BCD2NUM(x) (((x)>>4)*10+((x)&0x0f))
- //時鐘寄存器
- #define TIME_SECOND XBYTE[0xff00]
- #define TIME_MINUTE XBYTE[0xff02]
- #define TIME_HOUR XBYTE[0xff04]
- #define TIME_DAY XBYTE[0xff06]
- #define TIME_DATE XBYTE[0xff07]
- #define TIME_MONTH XBYTE[0xff08]
- #define TIME_YEAR XBYTE[0xff09]
- //控制寄存器
- #define REGISTERA XBYTE[0xff0A]
- #define REGISTERB XBYTE[0xff0B]
- #define REGISTERC XBYTE[0xff0C]
- #define REGISTERD XBYTE[0xff0D]
- unsigned char Time[]={0,0,0,1,1,10}; //時鐘數組
- //設置DS12C887
- SetupDs12887(void)
- {
- REGISTERA = 0x70;
- REGISTERB = 0xa2;
- //設置時間
- TIME_SECOND= NUM2BCD(Time[0]);
- TIME_MINUTE= NUM2BCD(Time[1]);
- TIME_HOUR = NUM2BCD(Time[2]);
- TIME_DATE = NUM2BCD(Time[3]);
- TIME_MONTH = NUM2BCD(Time[4]);
- TIME_YEAR = NUM2BCD(Time[5]);
- //計時開始
- REGISTERA = 0x20; //開始走時
- REGISTERB = 0x22;
- }
- //讀出DS12C887
- void ReadDs12887(void)
- {
- Time[0] = BCD2NUM(TIME_SECOND);
- Time[1] = BCD2NUM(TIME_MINUTE);
- Time[2] = BCD2NUM(TIME_HOUR);
-
- Time[3] = BCD2NUM(TIME_DATE);
- Time[4] = BCD2NUM(TIME_MONTH);
- Time[5] = BCD2NUM(TIME_YEAR);
- }
復制代碼
[size=14.399999618530273px]主源程序:
- //-------------------------------------------------------------------------------
- //程序名: 硬盤時鐘程序
- //說 明: 單片機89S52 晶振24M
- //-------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------
- //**嵌入文件**
- //-------------------------------------------------------------------------------
- #include <reg52.h> //51單片機硬件資源參數說明
- #include <intrins.h> //調用"_nop_()"函數
- #include "ds12887.h" //實時時鐘IC驅動
- //-------------------------------------------------------------------------------
- //**宏定義函數**
- //-------------------------------------------------------------------------------
- //位置修正函數
- #define XZ 8 //傳感器位置與"十二點"位置間隔(指針走的步數)
- #define Ru(x) (x+XZ)>59? (x+XZ-60):(x+XZ)
- //延時函數
- #define Delay5Us {_nop_();_nop_();_nop_();_nop_();_nop_();\
- _nop_();_nop_();_nop_();_nop_();_nop_();}
- #define Delay50Us {Delay5Us;Delay5Us;Delay5Us;Delay5Us;Delay5Us;\
- Delay5Us;Delay5Us;Delay5Us;Delay5Us;Delay5Us;}
- //-------------------------------------------------------------------------------
- //**端口定義**
- //-------------------------------------------------------------------------------
- //字符LED顯示端口
- #define WORDPORT P2
- #define DIGPORT P1
- //RGB_LED端口定義
- sbit P_LED_R=P3^0;
- sbit P_LED_G=P3^1;
- sbit P_LED_B=P3^4;
- //設置鍵端口定義
- sbit Key1=P1^6;
- sbit Key2=P1^7;
- sbit Key0=P3^5;
- //指示LED端口定義
- sbit Put_LED=P3^3;
- //-------------------------------------------------------------------------------
- //**變量說明**
- //-------------------------------------------------------------------------------
- //定義顏色值
- unsigned char code LED_COL[8][3]=
- {
- 1,1,1, //白
- 1,0,0, //紅
- 0,1,0, //綠
- 0,0,1, //藍
- 1,1,0, //黃
- 1,0,1, //品紅
- 0,1,1, //青
- 0,0,0, //黑
- };
- //鐘盤及指針顏色模式
- unsigned char code COL_MOD[4][5]=
- {
- 4,0,3,2,1,
- 5,1,4,2,3,
- 6,2,3,4,1,
- 7,4,3,2,1
- };
- //開機畫面LED動態顯示的字符
- unsigned char code CH[]={
- 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, //全空格
- // 0x48,0x54,0x54,0x50,0x3A,0x2f,0x2f,0x48, //http://h
- 0x20,0x42,0x44,0x38,0x43,0x47,0x20,0x20, // BD8CG
- //0x49,0x2e,0x42,0x41,0x49,0x44,0x55,0x2e, //i.baidu.
- 0x44,0x49,0x59,0x3A,0x50,0x4f,0x56,0x20, //DIY:POV
- //0x43,0x4F,0x4D,0x2f,0x35,0x32,0x5f,0x44, //com/52_d
- 0x4c,0x45,0x44,0x43,0x4c,0x4f,0x43,0x4b, //LEDCLOCK
- //0x49,0x59,0x20,0x20,0x20,0x20,0x20,0x20, //iy
- 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
- 0x20,0x20 //
- };
- // 設置狀態LED顯示的字 符
- unsigned char code SD[5][6]={
- 77,73,78,85,84,69,
- 72,79,85,82,32,32,
- 68,65,84,69,32,32,
- 77,79,78,84,72,32,
- 89,69,65,82,32,32
- };
- //調整時鐘的限制量
- unsigned char code maxnum[]={59,23,31,12,99,7}; //調整值最大限量
- unsigned char code minnum[]={0,0,1,1,0,1}; //調整值最小限量
- //其它變量定義
- unsigned char t1,t2,t3; //時分秒中間變量
- unsigned char M1,M2,M3; //時分秒中間變量
- unsigned char PT_col[60]; //指針顏色
- unsigned char BL_col; //表盤顏色
- unsigned char KD_col; //刻度顏色
- unsigned char ST; //進程標志
- unsigned char CM; //表盤色彩組合模式
- unsigned char TZ; //調整項
- unsigned int Tn; //指針位置值
- unsigned int Tp; //定時中斷T1設置值
- unsigned char N; //實際表盤平分分割數
- unsigned char S; //預設表盤平分分割數,取值60
- unsigned char Cn; //色彩變量
- //-------------------------------------------------------------------------------
- //**函數定義**
- //-------------------------------------------------------------------------------
- /*外部中斷0*/
- void intersvr0(void) interrupt 0 using 1
- {
- unsigned char Q;
- unsigned int D;
- TH1=-1;TL1=-1; //讓定時中斷T1與外部中斷適當錯開,使屏顯示穩定
- D=D+(N-S); //修正值。實際值與預設值比較,作出校正
- Tp=50000+D; //得到定時中斷T1的初設值
- //50000大約是旋轉一周所需的時間,這樣在開機時可顯示
- //從1到60等分圓的動態過程
- if((N==S)&&(Q<500)){
- Q++;
- if(Q==99) ST=1;
- } //顯示穩定后進入下一進程
- N=0;
- Tn=0;
- Cn=0;
- }
- /*T1處理函數*/
- void timer1(void) interrupt 3 using 1
- {
- TH1=-Tp/256;
- TL1=-Tp%256;
- if(ST==0){ //開機畫面
- if(Cn<7) Cn++; else Cn=1; //只顯示7種色
- P_LED_R=LED_COL[Cn][0];
- P_LED_G=LED_COL[Cn][1];
- P_LED_B=LED_COL[Cn][2];
- }
- if(ST==1){ //正常工作狀態
- //產生指針顏色
- P_LED_R=LED_COL[PT_col[Tn]][0];
- P_LED_G=LED_COL[PT_col[Tn]][1];
- P_LED_B=LED_COL[PT_col[Tn]][2];
- //產生指針寬度
- Delay50Us;Delay50Us; Delay50Us;
- //產生背景顏色
- P_LED_R=LED_COL[BL_col][0];
- P_LED_G=LED_COL[BL_col][1];
- P_LED_B=LED_COL[BL_col][2];
- Tn++; //下一個顯示單元
- }
- N++; //從傳感器位置開始,定時中斷次數計數
- }
- /*延時(用于較長時間段)*/
- void Delay(unsigned int tt)
- {
- unsigned char ii;
- for(;tt>0;tt--)
- for(ii=94;ii>0;ii--);
- }
- /*主程序*/
- void main(void)
- {
- unsigned char i,j; //循環變量
- unsigned char Xz=3; //刻度校正
- S=60; //旋轉一周,定時中斷T1產生60個中斷
- CM=0; //使用顯示屏顏色組合,可有四種模式選擇
- BL_col=COL_MOD[CM][0]; //背景光顏色
- KD_col=COL_MOD[CM][1]; //刻度顏色
- //中斷初始化
- TMOD=0x11;
- TH1=0; TL1=0;
- TR1=1; ET1=1;
- IT0=1; EX0=1;
- EA=1;
- //顯示屏初始化
- for(i=0;i<60;i++) PT_col[i]=BL_col;
- PT_col[0+Xz]=0;
- PT_col[5+Xz]=0;
- PT_col[10+Xz]=0;
- PT_col[15+Xz]=0;
- PT_col[20+Xz]=0;
- PT_col[25+Xz]=0;
- PT_col[30+Xz]=0;
- PT_col[35+Xz]=0;
- PT_col[40+Xz]=0;
- PT_col[45+Xz]=0;
- PT_col[50+Xz]=0;
- PT_col[55+Xz]=0;
- DIGPORT=0xec; WORDPORT=32;
- DIGPORT=0xed; WORDPORT=32;
- DIGPORT=0xee; WORDPORT=32;
- DIGPORT=0xef; WORDPORT=32;
- DIGPORT=0xd3; WORDPORT=32;
- DIGPORT=0xd7; WORDPORT=32;
- DIGPORT=0xdb; WORDPORT=32;
- DIGPORT=0xdf; WORDPORT=32;
- P_LED_R=0;
- P_LED_G=0;
- P_LED_B=0;
- //SetupDs12887();
-
- //開機畫面
- Delay(6000);
- for(j=0;j<35;j++){ //LED動態顯示字符
- DIGPORT=0xec; WORDPORT=CH[7+j];
- DIGPORT=0xed; WORDPORT=CH[6+j];
- DIGPORT=0xee; WORDPORT=CH[5+j];
- DIGPORT=0xef; WORDPORT=CH[4+j];
- DIGPORT=0xd3; WORDPORT=CH[3+j];
- DIGPORT=0xd7; WORDPORT=CH[2+j];
- DIGPORT=0xdb; WORDPORT=CH[1+j];
- DIGPORT=0xdf; WORDPORT=CH[0+j];
- Delay(4000);
- }
- P_LED_R=1;
- P_LED_G=0;
- P_LED_B=0;
- //進入主循環
- for(;;){
- if(TZ==0){ //LED顯示年月日信息
- ReadDs12887(); //讀取時間值
- Put_LED=1;
- M1=Time[0];M2=Time[1];M3=Time[2];
- DIGPORT=0xec; WORDPORT=0x30+Time[3]%10;
- DIGPORT=0xed; WORDPORT=0x30+Time[3]/10;
- DIGPORT=0xee; WORDPORT=0x2d;
- DIGPORT=0xef; WORDPORT=0x30+Time[4]%10;
- DIGPORT=0xd3; WORDPORT=0x30+Time[4]/10;
- DIGPORT=0xd7; WORDPORT=0x2d;
- DIGPORT=0xdb; WORDPORT=0x30+Time[5]%10;
- DIGPORT=0xdf; WORDPORT=0x30+Time[5]/10;
- }
- else //LED顯示調整項
- {
- DIGPORT=0xec; WORDPORT=0x30+Time[TZ]%10;
- DIGPORT=0xed; WORDPORT=0x30+Time[TZ]/10;
- DIGPORT=0xee; WORDPORT=SD[TZ-1][5];
- DIGPORT=0xef; WORDPORT=SD[TZ-1][4];
- DIGPORT=0xd3; WORDPORT=SD[TZ-1][3];
- DIGPORT=0xd7; WORDPORT=SD[TZ-1][2];
- DIGPORT=0xdb; WORDPORT=SD[TZ-1][1];
- DIGPORT=0xdf; WORDPORT=SD[TZ-1][0];
- M1=Time[0];M2=Time[1];M3=Time[2];
- Put_LED=~Put_LED; //LED指示在設置狀態閃亮
- }
- Delay(50);Delay(50);
- Delay(50);Delay(50);
- //用背景色覆蓋原來的指針色
- PT_col[t1]=BL_col;
- PT_col[t2]=BL_col;
- PT_col[t3]=BL_col;
- //取指針數值
- if(M3>12) M3=M3-12;
- t1=Ru(M1);t2=Ru(M2);t3=Ru(M3*5+M2/12);
- //刷新時鐘刻度色
- PT_col[0+Xz]=KD_col;
- PT_col[5+Xz]=KD_col;
- PT_col[10+Xz]=KD_col;
- PT_col[15+Xz]=KD_col;
- PT_col[20+Xz]=KD_col;
- PT_col[25+Xz]=KD_col;
- PT_col[30+Xz]=KD_col;
- PT_col[35+Xz]=KD_col;
- PT_col[40+Xz]=KD_col;
- PT_col[45+Xz]=KD_col;
- PT_col[50+Xz]=KD_col;
- PT_col[55+Xz]=KD_col;
- //顯示時鐘
- PT_col[t1]=COL_MOD[CM][2];
- PT_col[t2]=COL_MOD[CM][3];
- PT_col[t3]=COL_MOD[CM][4];
- Delay(50);Delay(50);
- Delay(50);Delay(50);
- Delay(50);Delay(50);
-
- //鍵盤處理
- if(Key0==0){ //設置鍵
- Delay(120);
- if(Key0==0) {if(TZ>0) TZ--; else TZ=5;}
- if(TZ==0) SetupDs12887();
- Delay(1200);
- }
- Delay(50);Delay(50);
- Delay(50);Delay(50);
- if(Key1==0){ //加法鍵
- Delay(120);
- if(Key1==0) {
- if(Time[TZ]<maxnum[TZ-1]) Time[TZ]++; else Time[TZ]=minnum[TZ-1];
- }
- Delay(1200);
- }
- Delay(50);Delay(50);
- Delay(50);Delay(50);
-
- if(Key2==0){ //減法鍵
- Delay(120);
- if(Key2==0) {
- if(Time[TZ]>minnum[TZ-1]) Time[TZ]--; else Time[TZ]=maxnum[TZ-1];
- }
- Delay(1200);
- }
- Delay(50);Delay(50);
- Delay(50);Delay(50);
- }
- }
復制代碼
|