我所設計的題目為“基于魔術棒的多功能單片機系統”,主要是在魔術棒的基礎上添加了單片機的其他功能,例如紅外遙控,蜂鳴器,溫度傳感器,LED燈等裝置。具體要求有以下幾點:
- 利用數碼管實現主要功能“魔術棒”。
- 利用紅外裝置控制溫度傳感器,并顯示溫度。
- 利用蜂鳴器使其能發出樂音。
- 利用LED燈實現跑馬燈功能。
- 利用按鍵控制以上幾種功能。
二、設計方案及論證
1、任務分析
我所做的主要部分為“魔術棒”,“魔術棒”的原理是利用人眼的視覺暫留原理,即物體在快速運動時, 當人眼所看到的影像消失后,人眼仍能繼續保留其影像0.1-0.4秒左右的圖像,因此,我們可以利用數碼管或LCD顯示屏,逐個控制每一位的點亮,并送入數據,再控制好相鄰位之間亮起的頻率,就可以實現一個動態顯示功能,但實際上在當前時刻只有1位點亮并送入數據,控制一定頻率使得人眼看起來每個位置都在同時點亮。
紅外傳感模塊和溫度傳感器單片機上已經存在,需要編寫程序控制溫度傳感器工作,并實時顯示溫度,并且編寫控制紅外遙控裝置的程序,令紅外裝置能接收信號和發出紅外線,通過紅外遙控器控制溫度傳感器的開啟。
蜂鳴器是將音符表和節拍表送入寄存器中,通過改變蜂鳴器的音調和延遲時間實現演奏歌曲。
LED燈發光可以通過改變P1端口8位來選擇不同的LED發光。
按鍵開關是單片機的一個基礎元件,可以通過開關控制許多功能的開啟和關閉,我用不同的按鍵開關控制以上功能的實現。
經過我們多次的設計方案討論,我們大致確定了2種設計方向。
①“魔術棒”用數碼管來實現,這個方案的優點是我們可以在一個時間點控制一個數碼管的點亮,控制好點亮頻率我們可清楚地觀察到“魔術棒”現象的生成。但缺點是數碼管只有4位,無法顯示多個字符,而且顯示內容較少,只有數字和部分英文字母。
②“魔術棒”用LCD顯示屏來實現,這個方案的優點是顯示的內容比數碼管多,且能顯示所有的英文字母和數字,但缺點是無法很好的觀察到現象,且可能會出現未知的顯示錯誤。
最后,我們確定了主體方案為方案1,因為數碼管可以更好地觀察到現象,可以將大于4的字符循環顯示,也可以觀察到魔術棒效果。
3、系統關鍵模塊設計
上圖為C51單片機數碼管原理圖,P2口為位選端口,P0口為段選端口,8個LED發光二極管為共陽極接法,不點亮時為高電平,點亮為低電平,即相應管腳送0為低電平,送1為高電平,低電平有效,因此控制P2端口地址0的位置可使相應數碼管點亮。
4、軟件算法流程(將完整代碼放在附錄1中)
下圖為控制數碼管依次顯示字符的算法流程圖,首先設次數為1,設置P2的值使第一個數碼管點亮,設置P0的值將數據送入第一個數碼管,再進行延遲,判斷次數是否大于3,是則關閉所有數碼管, 否則次數加1,并回到設置P2值的步驟。
三、開發及調試過程
1、開發過程
根據我們確定的主體方案以及我自己的設計方案,我開始了程序的開發過程,我利用了Keil軟件進行程序的開發和調試,我的程序運用到的編程語言為C51語言和匯編語言,我將程序的開發分為以下3個模塊:溫度傳感器工作及顯示函數,數碼管顯示函數,紅外傳感器控制及工作函數。其中紅外傳感器模塊是用匯編語言編寫的,其他模塊是用C51語言編寫的。
對于匯編語言我還不是特別精通,所以我把紅外傳感器模塊安排到了最后進行。首先進行數碼管的開發過程,數碼管的段選是由P0端口擴展的74HC573芯片控制的,74HC573芯片是擁有八路輸出的透明鎖存器,輸出為三態門的控制芯片,通過控制P0.0---P0.7管腳使a~g不同位置數碼管亮起,數碼管為共陽極接法,因此低電平有效,當一個管腳置0時,其代表的數碼管對應位置就會亮起,實現送數功能。數碼管的位選是由P2口控制的四個三極管-電阻電路,通過控制P2.0~P2.3端口控制哪一位數碼管開啟,低電平有效。根據數碼管原理特性,首先定義兩個數組,一個向P0口送數,一個向P2口送數,再編寫延遲函數,最后用循環執行代碼,首先P2=0xFE,即打開數碼管1,之后P0=0xF9,送入數據1,調用延遲函數將這一狀態延時。延時過后判斷是否滿足循環條件,若不滿足則繼續執行循環,直到滿足循環條件為止,滿足則跳出循環,進行下一項內容。調試時可以通過改變延遲時間觀察現象,直到利用視覺暫留原理達到人眼捕捉動畫的效果。基于上述原理,我又加了另外4個數字,使得數碼管能循環顯示8位數字,實現送入長度大于4的字符串功能。
C51單片機溫度傳感器型號為DS18B20,DS18B20內部由4個部分構成,分別是64位光刻ROM 、溫度傳感器、非揮發的溫度報警觸發器TH和TL、配置寄存器。它們可以實現溫度的測量,溫度值的存入和提取,溫度的轉換等功能。并可以將提取的溫度值通過數碼管顯示出來。溫度傳感器函數設計分為以下幾點:定義延時函數,初始化18B20,讀取18B20一個字節,向18B20寫入一個字節,讀溫度值,溫度處理,顯示溫度。將18B20初始化是給其一個工作條件。讀取18B20一個字節是要將數據從ROM中提取出來,向18B20寫入一個字節是要將測出來的數據寫入到ROM中,讀溫度值通過溫度傳感器特性得知環境實時溫度,溫度處理將溫度值變為4位有效數字的溫度值,溫度顯示是通過數碼管實現。遍譯好程序后經過不同溫度的測試,發現在誤差范圍內溫度測量精準,且溫度也在隨環境溫度實時變化。
以上兩個功能都可以通過按鍵控制的方式開啟,即設計一個按鍵去抖函數,當按鍵按下,按鍵就處于低電平有效狀態,相應的功能開始工作,當別的按鍵按下后上一個功能停止工作執行當前按下按鍵的功能。通過按鍵可實現功能切換的功能。
紅外傳感器模塊用匯編語言編寫,紅外傳感器和遙控器搭配使用,當在正常無遙控信號時,一體化紅外接收頭輸出是高電平,不執行相應功能。當接入信號后,首先要進行解碼,傳輸的紅外信號是以高低電平的形式送入的,于是設定外部中斷IR,觸發方式為下降沿觸發,將高低電平信號存入寄存器中,獲得16位地址碼和8位數據碼,從而實現解碼。之后進行遙控執行部分,設定遙控器按鍵1為LED燈閃爍程序。LED燈位選通過P1口控制,為低電平有效,當按下按鍵1后,執行LED燈循環亮起程序。首先將第一個LED燈亮起地址送入累加器A中,經過延遲后再將第二個LED燈亮起地址送入累加器A中,之后以此類推,實現LED跑馬燈功能。設定遙控器按鍵8為蜂鳴器播放樂音程序,蜂鳴器產生樂音原理是將預先設計好的節拍表和音符表送入蜂鳴器中,并進行定時,使蜂鳴器能完整播放一首樂音。當播放完后清除遙控值使連按失效。紅外遙控程序結束。通過測試,遙控器在對準紅外傳感器且距離在10cm以內可順利遙控,LED跑馬燈以及蜂鳴器均可正常工作,且交換順序也并不影響,說明程序符合預期設計目標。
①若想將循環結束后的數碼管每一位清零,只將數碼管位選信號全部置1是不行的,需設置P0的值使發光二極管全部置1,令發光二極管熄滅,原因是Keil中執行一條命令總在下一條命令開始執行時執行上一條命令,因此需加一條命令關閉發光二極管。
②溫度傳感器在環境溫度突變時顯示數據會有錯誤,這是其器件特性所致,只能通過改進溫度讀取函數來實現。
本次課設中用到的關鍵知識點為C51語言及匯編語言的應用,輸入輸出端口的應用,各種芯片元器件的應用,定時器,中斷以及許多數字電子技術和模擬電子技術上的知識。這些知識的綜合運用使我順利完成了本次課程設計。
為期4周的單片機課程設計結束了,我經歷了查閱資料,小組討論,設計方案選取,編寫調試代碼,單片機調試,代碼修改,小組及個人答辯等一系列流程,我學到的不僅是這門課傳授我的只是,更學到了團隊合作,多途徑查閱資料,分析問題能力和溝通能力,這些都是我成功做完這次課設的保證,我也要感謝我的隊友,是我們一起經過討論確定了選題和主體方案設計,當程序有問題或需要改進時我們也深入廣泛地交換了彼此的意見,每個人在這次課設中都收獲到了許多。我還要感謝多次熱心幫助我們的老師和助教,是他們多次幫助我們發現問題,提出建議,幫助我們在原有功能上增添了更多功能,并且還提供了許多參考資料給我們,令我們有豐富的知識儲備。但我們這次的課設還是有很多方面的不足,對于我仍然有很大的提升空間,礙于現在自身知識儲備和時間問題,我在一些方面上沒能做得更加細致,我會總結經驗教訓,努力完成以后的課程。
單片機課程設計是一門對于電子專業學生很重要的一門課,它培養了我們的獨立工作能力和小組協作能力,但可能一個小組中并沒有很好的創意,我覺得可以在確定選題前先開一個選題交流會,大家踴躍發言,集思廣益,可以增加我們題目創新性,也可以與別的組成員進行有效溝通,增加我們的完成機率。
單片機源程序如下:
- <font face="宋體"><font style="font-size: 10.5pt">#include<reg52.h>
- #define uchar unsigned char
- #define uint unsigned int
- extern void infrared(void);
- uchar display[ ]={0xF9,0x82,0xA4,0xF8};
- uchar display4[ ]={0xF9,0xC0,0xF8,0xC0};
- uchar code display2[ ]={0xff,0xC7,0x83,0xE1};
- //uchar code con[ ]={ 0xff,0xfe,0xfd,0xfb,0xf7};
- uchar code con[ ]={0xfe,0xfd,0xfb,0xf7};
- uchar code table[]={0xc0,0xf9,0xA4,0xB0,0x99,0x92,0x82,0xf8,0x80,0x90};
- //四位8段數碼管共陽0——9
- uchar code table1[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
- //四位8段數碼管帶小數點共陽0——9
- sbit s2=P3^3;
- sbit s3=P3^4;
- sbit s4=P3^5;
- void delay(uint i)
- {
- while(i--)
- ;
- }
-
- //**************按鍵處理*******************************
- char check_s2(void)
- {
- if(s2==0)
- {
- delay(2000);
- {
- if(s2==0)
- {
- return 1;
- }
- }
- }
- return 0;
- }
- char check_s3(void)
- {
- if(s3==0)
- {
- delay(2000); // 按鍵去抖
- {
- if(s3==0)
- {
- return 1;
- }
- }
- }
- return 0;
- }
- char check_s4(void)
- {
- if(s4==0)
- {
- delay(2000); // 按鍵去抖
- {
- if(s4==0)
- {
- return 1;
- }
- }
- }
- return 0;
- }
- //***********************溫度傳感器************************
- uint x;
- sbit DQ =P3^7; //DS18B20接P3^7口
- uint tvalue;
- uchar disdata[]={0,0,0,0};
- void delaytimer(void)
- {
- EA=1;//打開中斷
- TMOD=0x10;//
- TL1=(65536-500)%256;//設置定時器1低8位
- TH1=(65536-500)/256; //設置定時器1高8位
- TR1=0;//停止計數
- ET1=1;//打開定時器
- }
- void delay_18B20( uint i) //延時
- {
- while(--i);
- }
- void delay2(uchar n) //延時
- {
- uchar i,j;
- for(i=n;i>0;i--)
- for(j=20;j>0;j--);
- }
- void ds1820rst() //初始化DS18B20
- {
- unsigned char x=0;
- DQ = 1; //DQ復位
- delay_18B20(4); //
- DQ = 0; //單片機將DQ拉低
- delay_18B20(60); //
- DQ = 1; //拉高總線
- delay_18B20(14);//
- x=DQ; //稍做延時后 如果x=0則初始化成功 x=1則初始化失敗
- delay_18B20(20);
- }
- uchar ds1820rd() //從DS18B20讀取一字節
- {
- unsigned char i=0;
- unsigned char dat = 0;
- for (i=8;i>0;i--) //一位一位地讀,共8位
- {
- DQ = 0; //給一脈沖信號
- dat>>=1; //dat往右移一位
- DQ = 1; //給一脈沖信號
- if(DQ)
- dat|=0x80;
- delay_18B20(4);//
- } return(dat);
- }
- void ds1820wr(uchar wdata) //寫入一字節
- {
- unsigned char i=0;
- for (i=8;i>0;i--)
- {
- DQ = 0;
- DQ = wdata&0x01;
- delay_18B20(5);
- DQ = 1;
- wdata>>=1;
- }
- }
- uint read_temp() //讀取溫度
- {
- float aaa;
- uchar a,b;
- ds1820rst();
- ds1820wr(0xcc); //向DS18B20發跳過讀ROM命令
- ds1820wr(0x44); //啟動DS18B20進行溫度轉換命令,轉換結果存入內部RAM
- delay_18B20(80); //延時
- ds1820rst();
- ds1820wr(0xcc); //向DS18B20發跳過讀ROM命令
- ds1820wr(0xbe); //讀取溫度寄存器等(共可讀9個寄存器) 前兩個就是溫度
- delay_18B20(80); //延時
- a=ds1820rd(); //讀內部RAM 低位
- b=ds1820rd(); //讀內部RAM 高位
- aaa=(b*256+a)*6.25;
- tvalue=(uint)aaa;
- return(tvalue);
- }
- void display1(uchar a1,uchar a2,uchar a3,uchar a4) //顯示溫度
- {
- P2=0xfe;
- P0=table[a1];
- delay2(20);
- P2=0xfd;
- P0=table1[a2];
- delay2(20);
- P2=0xfb;
- P0=table[a3];
- delay2(20);
- P2=0xf7;
- P0=table[a4];
- delay2(20);
- }
- void ds1820disp( unsigned int tvalue1) //溫度處理
- {
- disdata[0]=tvalue1/1000; //十位
- disdata[1]=tvalue1%1000/100; //個位
- disdata[2]=tvalue1%100/10; //小數點后一位
- disdata[3]=tvalue1%10;; //小數點后兩位
- display1(disdata[0],disdata[1],disdata[2],disdata[3]);
- }
- //void stop(){
-
- void t18B20() //溫度傳感器顯示函數
- {
- uint temp;
- delaytimer();
- while(1)
- {
- temp=read_temp();
- ds1820disp(temp);
-
- }
- }
- /*void smg()
- {
- uchar shift,j,k,m;
- while(1)
- { for(m=1;m<101;m++)
- {for(j=0;j<4;j++)
- {
-
- P2=con[j];
- P0=display[j];
- delay(10000);
-
- }
- P2=0xFF;
-
- for(k=0;k<4;k++)
- {
- P2=con[k];
- P0=display4[k];
- delay(10000);
- }
- P2=0xFF;
- }
- P0=0xFF;
- P2=0xFF;
- }}*/
- //*************主函數***********************
- void main()
- { uchar shift,j,k,m;
- for(m=1;m<5;m++)
- { for(j=0;j<4;j++)
- {
-
- P2=con[j];
- P0=display[j];
- delay(10000);
-
- }
-
- P2=0xFF;
-
- /* for(j=0;j<3;j++)
- {
-
- P2=con[j];
- P0=display2[j];
- delay(1000);
- }*/
- for(k=0;k<4;k++)
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
- </font></font>
復制代碼
所有資料51hei提供下載(仿真+源碼+完整論文):
魔術棒.zip
(270.6 KB, 下載次數: 22)
2018-7-21 17:35 上傳
點擊文件名下載附件