摘要隨著人們生活水平的提高和生活節奏的加快,對時間的要求越來越高,精準數字計時的消費需求也是越來越多。
我國生產的電子萬年歷有很多種,總體上來說以研究多功能電子萬年歷為主,使萬年歷除了原有的顯示時間,日期等基本功能外,還具有鬧鈴,報警等功能。商家生產的電子萬年歷更從質量,價格,實用上考慮,不斷的改進電子萬年歷的設計,使其更加的具有市場。
本設計為軟件,硬件相結合的一組設計。在軟件設計過程中,應對硬件部分有相關了解,這樣有助于對設計題目的更深了解,有助于軟件設計。基本的要了解一些主要器件的基本功能和作用。
此次課程設計使用專門的時鐘芯片DS1302在液晶顯示器LCD12864上顯示時鐘,并能通過按鍵對其進行調試和校準以及實現年月日。DS1302是一種高性能、低功耗、帶RAM的實時時鐘芯片,它能夠對時分秒進行精確計時。將RST、SCLK、I/O引腳分別與STC12C5A60S2單片機P2^0、P2^1、P2^2相連,使單片機對其進行讀寫操作,把讀出的數據送到LCD12864上顯示,通過4個按鍵實現對時間的調整和鬧鈴的設定和調整,具有顯示直觀、電路簡潔、使用方便簡單等優點。
第1章 緒論1.萬年歷簡介電子萬年歷是一種非常廣泛的日常計時工具,它可以對年、月、日、周、時、分、秒進行精確計時在日常生活中極為實用,DS1302是常用的時鐘芯片,價格低廉,精度高且對與數字電子萬年歷采用直觀的數字顯示,還具有時間校準等功能。
1.2設計主要內容1.2.1設計方案- 顯示部分:通過12864液晶顯示模塊顯示年、月、日、時、分、秒,并可以切換顯示時間設置、鬧鐘設置和波形圖。
- 按鍵部分:本次設計將采用
1.003.jpg (21.67 KB, 下載次數: 104)
下載附件
2017-4-22 23:28 上傳
矩陣鍵盤作為功能按鍵,需要的功能按鍵有:日期/時間切換鍵,控制鍵,加鍵,減鍵,鬧鐘關閉鍵,貪睡鍵,方波輸出鍵,正弦波輸出鍵。
(3)時鐘模塊:采用時鐘芯片DS1302。美國DALLAS公司推出的具有涓細電流充電能的低功耗實時時鐘電路DS1302。它可以對年、月、日、周日、時、分、秒進行計時,還具有閏年補償等多種功能,而且DS1302的使用壽命長,誤差小。對于數字電子萬年歷采用直觀的數字顯示,可以同時顯示年、月、日、周日、時、分、秒,還具有時間校準等功能。利用單片機對其進行讀寫操作,然后將讀出的時間數據送到LCD12864上顯示。
- 查閱相關資料,了解老師所給的資料里面開發板的線路連接和各個模塊資料;
- 用protel實現硬件的仿真,畫出原理圖以及PCB圖;
- 參照老師所給示例程序和網上資料用keil 軟件進行單片機的編程設計,運行調試;
- 將keil生成的hex文件燒錄進入開發板,進行測試。
1.2.3主要功能(1)使用掃描式鍵盤,通過按鍵實現設定、修改日期和時間,省電(關閉顯示)等功能,鍵盤功能自行定義;
(2)實現倒計時功能,倒計時時間由鍵盤輸入設定,定時時間到LED閃爍;
(3)實現4路可調鬧鐘功能,當4路鬧鈴中的任一路時間到時,通過不同的鈴聲顯示鬧鈴時間到,且鈴聲持續時間不超過1分鐘。1分鐘以內若按下停止鍵,鈴聲停止;若按下貪睡鍵,鈴聲停止,3分鐘以后再次響鈴;1分鐘以內若不按任何鍵,鈴聲自動停止,3分鐘后再次響鈴。
(4)通過2個按鍵,分別實現輸出10Hz的正弦波及方波。
第2章 系統硬件設計
2.1硬件組成硬件以STC12C5A60S2單片機為核心,外部擴展LCD12864液晶顯示模塊、按鍵控制鍵盤模塊、DS1302時鐘芯片,蜂鳴器模塊實現動態顯示時間日期,鬧鈴設置,倒計時,波形圖顯示等功能。
基本硬件結構圖如圖2.1所示。
1.004.jpg (16.42 KB, 下載次數: 122)
下載附件
2017-4-22 23:28 上傳
圖2.1 萬年歷基本硬件結構圖
2.2顯示模塊
1.005.jpg (43.36 KB, 下載次數: 111)
下載附件
2017-4-22 23:28 上傳
圖2.2 數碼管
顯示模塊用的是兩個4位7段數碼管,切換顯示比分和時間,例如比分顯示為111--111,時間顯示為01-12-00:1為第一節,12-00為倒計時。
2.3時鐘電路、復位電路模塊
1.006.jpg (33.24 KB, 下載次數: 115)
下載附件
2017-4-22 23:28 上傳
圖2.3 時鐘電路、復位電路
時鐘電路在單片機系統中有著非常重要的作用,是保證系統正常工作的基礎。在一個單片機應用系統中,時鐘是保證系統正常工作的基準震蕩定時信號,主要由晶振和外圍電路組成,晶振頻率的大小決定了系統工作的快慢。圖中采用12MHZ的晶振,另外有兩個30P的電容,兩晶振引腳分別連到XTAL1和XTAL2振蕩脈沖輸入引腳。復位電路是單片機的初始化操作,圖中RST引腳是復位信號的輸入端。具體連接如圖2.3所示。
2.4按鍵模塊S2控制甲隊加分,S5控制甲隊減分;S3控制乙隊加分,S6控制乙隊減分;S8控制比分互換;S13控制比分切換到時間,S11控制時間切換到比分;S9為比分清零;S12為增加節數,S21為減少節數。具體連接分布如圖2.4所示。
1.007.jpg (51.1 KB, 下載次數: 127)
下載附件
2017-4-22 23:28 上傳
圖2.4 矩陣鍵盤電路
第3章 系統軟件設計3.1 主程序框圖當程序啟動時,先進入各個模塊初始化,初始化完成后,進入鬧鐘判斷,若是鬧鐘設置的時間到了,則進入鬧鐘中斷子程序中,處理鬧鐘中斷;若是沒有,則是在數碼管上顯示初始化程序里的時間。接著是調用鍵盤掃描程序,判斷控制鍵是否按下,若按下,則i的值加1,同時進入相應的功能程序。其中主要的功能程序有:4個鬧鐘時間的設置,波形輸出,時間的設置,以及倒計時功能。當它們執行完相應的子程序后,則返回時間顯示界面。
1.008.jpg (26.35 KB, 下載次數: 97)
下載附件
2017-4-22 23:28 上傳
圖3.1 主程序框圖
3.2控制鍵程序 控制鍵按下時,程序的變量i會相應地加1,而且同時進入相應的功能程序,例如i=1、2、3時,會進入相應地鬧鐘時間設置,分別設置鬧鐘1的時/分/秒。同理,i=4~12分別設置鬧鐘2、3、4的時間。然后i=13、14、15、16、17、18接下來是正常的時間設置,分別設置年/月/日/小時/分鐘/秒鐘。I=19時,進入波形輸出,i=20時,進入倒計時功能。最后程序返回時間顯示,同時i的值清零。
1.009.jpg (33.5 KB, 下載次數: 109)
下載附件
2017-4-22 23:28 上傳
圖3.2.控制鍵程序流程圖
1.010.jpg (1.86 KB, 下載次數: 94)
下載附件
2017-4-22 23:28 上傳
if(DP) RecDat|=0x01<<i; 讀入數據[="" align]" }[="" rst="0;" return(recdat);="" 返回數值[="" null,="" left][size="12pt]當鬧鐘設置的時間到了時,這時程序就會進入鬧鐘中斷程序。例如鬧鐘1設置的時間到了,就會使蜂鳴器響起鬧鈴,鍵盤掃描停止鍵是否按下,若在一分鐘內按下,則鬧鐘停止,同時鍵盤掃描判斷貪睡鍵是否按下,若按下,則三分鐘后再次響鈴,若一分鐘內沒有鍵按下,自動停止,然后3分鐘后響鈴;
1.013.jpg (19.88 KB, 下載次數: 105)
下載附件
2017-4-22 23:28 上傳
圖3.5鬧鐘中斷程序流程圖
第4章 實驗與分析為了實現籃球計分器的功能,我們必須通過不斷地測試和分析,實現軟件與硬件融為一體。從內容上,我們將它分為比分的測試和時間的測試。
4.1 籃球計分器的比分測試4.1.1相關功能鍵的測試- 按下S2鍵控制A隊加1分(2)按下S5鍵控制A隊減1分(3)按下S3鍵控制B隊加1分(4)按下S6鍵控制B隊減1分(5)按下S8鍵控制比分互換(6)按下S9鍵為比分清零
如圖4.1所示,當前比分為24比17 圖4.1籃球計分器比分測試圖
4.1.2出現的問題與分析分析:出現這種情況可能的原因:一、硬件方面,可能是矩陣鍵盤的S2和S3連線問題,使按下它們兩個鍵時,實現功能相同,二、軟件方面,可能是定義該功能時,重復使用了該鍵。沿著這兩個思路,我們首先將老師給的例程燒錄進去,該例程實現的功能就是按下不同的鍵,數碼管將會顯示不同的數字,當我們分別按下S2和S3時,出現的數字不同,那么證明硬件方面沒問題。然后查了一遍程序,果然是編寫程序時,重復使用了該鍵。
分析:可能原因一、S8鍵可能出現故障了,二,編寫程序時,比分交換的那段代碼邏輯結構出錯。因為已經檢測過矩陣鍵盤的所有按鍵,都是好的,那么只能時軟件方面出錯。最后發現果然是t=a1,a1=a2,a2==t這個邏輯關系順序寫錯了。
4.2籃球計分器時間測試4.2.1相關功能鍵的測試- 按下S13鍵控制比分切換到時間(2)按下S11鍵控制時間切換到比分(3)按下S12鍵為增加節數(4)按下S21鍵為減少節數。
如圖4.2所示,當前時間顯示為第一節還剩9分42秒。
圖4.2籃球計分器時間測試圖
4.2.2出現的問題與分析- 按下S13鍵比分切換到時間時,再次按時,卻無法將時間切換比分
分析:首先這種情況不可能是硬件問題,因為 S13鍵按下后能有反應,那么只能是程序問題。后面經過多次分析程序,發現還是自己程序結構問題,因為定義了兩種情況,f==0和f==1,從而實現比分和時間切換,用兩個鍵簡單快捷。當按下某一鍵只能實現f==0或f==1,所以需要兩個鍵。
分析:因為按照算數邏輯,節數一直減總會減到小于零,而數碼管無法顯示小于零的數,所以它只能是邏輯上存在而無法顯示,當我們按下S12鍵使節數加時,一直加到大于零時,它又將重新顯示出來。
參考文獻- 張建勛編著. C語言程序設計教程. 北京:清華大學出版社,2008.
- 曾屹、劉輝編著. 單片機原理及應用. 中南大學出版社,2009
心得體會剛選這個題目,我以為很簡單到網上一搜就有,誰知道自己真正做起來才知道這個課題要實現的功能很多,在網上找了好多類似的但都用不了,不是編譯錯誤就是功能太復雜不會改。這個星期由于是考試周的原因,對于這個課題我一心就想早點把它搞好,以后的時間好復習。但是和伙伴早晚一直待在實驗室連續做了4天還是沒有很大的進展,剛開始的時候用的是數碼管切換顯示時間和日期,但是考慮到還要加4個鬧鐘和倒計時、顯示波形等功能,我們改用了LCD12864來顯示這些東西,本來想把兩個結合起來,但一直搞不好,第三天的時候將時間和日期顯示到了液晶屏上,接下來我們想辦法設計程序來調節從DS1302讀出來的時間,參考網上的程序嘗試了好幾次,卻一直沒有想要的結果,就這樣一直到了第四天驗收,雖然通過了,但離題目要求還差很遠,自己還有好多需要學習的東西,還有好多沒有理解的東西,真正在做的時候才發現自己差的并不只是一點。
雖然這次課設過程很艱難,成果也很有限,但是還是學到了許多東西,以后在接觸到類似的東西就不會還是一頭霧水,遇到問題要一步一步來,不斷取得一些進展,才能激發自己前進的動力。
程序清單:
- #include
- #include
- #define uchar unsigned char
- #define uint unsigned int
- sbit DP=P1^6;
- sbit CLK=P1^5;
- sbit RST =P1^7;
- sbit DAT_595_PIN = P1^0; //串行數據輸入
- sbit SCK_595_PIN = P1^2; //移位時鐘脈沖
- sbit RCK_595_PIN = P1^1; //輸出鎖存器控制脈沖
- uint a1=0;
- uint a2=0;
- uint t=0;
- uint ft=0;
- uint jie=1;
- uchar Year,Month,Day,Week,Hour,Minute,Sec;
- uchar code num_buf[22]= {0xf5,0x05,0xb3,0x97,0x47,0xd6,0xf6,0x85,0xf7,0xd7,
- //0 1 2 3 4 5 6 7 8 9
- 0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xef,0xef,0x02,0x00};
- //0. 1. 2. 3. 4. 5. 6. 7. 8. 9.
- Uchar code bit_buf[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//0xf7,0xef,0xdf,0xbf,0x7f};
- uchar data led_buf[8] = {0,0,0,20,20,0,0,0};
- unsigned int num;
- // Function Declare ********************************************************************
- void Delay(void);
- void Write_595(void);
- uchar Scan_Key(void);
- void delay(int ms)
- {
- while(ms--)
- {
- uchar i;
- for(i=0;i<250;i++)
- {
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- }
- }
- }
- void mDelay(uchar DelayTime) //延時子程序,入口參數每加1約加2us
- { while(--DelayTime);
- }
- void SendByte(uchar Command,SendDat)
- { //字節發送子程序。入口參數:命令字,數據
- uchar i;
- RST=0;CLK=0;RST=1;
- for(i=0;i<8;i++) //發送命令字
- {
- DP=Command&0x01; //取一位送數據口
- CLK=0;CLK=1; //產生一個上升沿
- Command>>=1;
- }
- for(i=0;i<8;i++) //發送數值
- {
- DP=SendDat&0x01;
- CLK=0;CLK=1;
- SendDat>>=1;
- }
- RST=0;
- }
-
- uchar ReadByte(uchar Command) //讀字節子程序。入口參數:命令字
- { //出口參數:數值
- uchar i,RecDat=0;
- RST=0;CLK=0;RST=1;
- for(i=0;i<8;i++) //發送命令字
- {
- DP=Command&0x01;
- CLK=0;CLK=1;
- Command>>=1;
- }
- for(i=0;i<8;i++) //讀入數值
- {
- CLK=1;CLK=0; //產生一個下降沿
- if(DP) RecDat|=0x01<<i; 讀入數據
- }
- RST=0;
- return(RecDat); //返回數值
- }
-
- void OscCtrl(bit CtrlDat) //振蕩起動和停止控制,入口參數1(起動)或0(停止)
- {
- if (CtrlDat) SendByte(0x80,0x00);
- else SendByte(0x80,0x80);
- }
- // Main Function
- void main(void) //主程序
- {
- uchar key_value,cnt;
- uchar i;
- OscCtrl(1);
- SendByte(0x80,0x00); //送字節
- SendByte(0x82,0x20);
- SendByte(0x84,0x13);
- SendByte(0x86,2);
- SendByte(0x88,1);
- SendByte(0x8C,11);
- while(1){
- while(ft==0)
- {
- led_buf[0] = a1/100; //左側比分的百位
- led_buf[1] = (a1%100)/10; //左側比分的十位
- led_buf[2] = a1%10; //左側比分的個位
- led_buf[3] = 20; //短橫線
- led_buf[4] = 20; //短橫線
- led_buf[5] = a2/100; //右側比分百位
- led_buf[6] = (a2%100)/10; //右側比分十位
- led_buf[7] = a2%10; //右側比分個位
- Write_595();
- key_value = Scan_Key();
- //keydown();
- //Delay();
- switch(key_value) //鍵盤掃描函數
- {
- case 0:
- break;
- case 0x88: //按第一列第一行鍵a1+1
- a1++;
- break;
- case 0x84: //按第一列第二行鍵a1-1
- a1--;
- break;
- case 0x82: //交換比分
- t=a1;
- a1=a2;
- a2=t ;
- break;
- case 0x81: // ft=1,切換比分/時間
- ft=1;
- break;
- case 0x48: //按第二列第一行鍵a2+1
- a2++;
- break;
- case 0x44: //按第二列第一行鍵a2-1
- a2--;;
- break;
- case 0x42: //clear,比分置零
- a1 = 0;
- a2 = 0;
- break;
- case 0x41: //ft=0,按第二列第四行鍵切換比分
- ft=0;
- break;
- default:
- break;
- }
- }
- while(ft==1) //當ft=1時,即定義切換成時間顯示函數
- {
- Year =ReadByte(0x8D); //讀小時
- Month =ReadByte(0x89); //讀分鐘
- Day =ReadByte(0x87); //讀秒
- Hour =ReadByte(0x85); //讀小時
- Minute=ReadByte(0x83); //讀分鐘
- Sec =ReadByte(0x81); //讀秒
- if((Minute/16*10+Minute%16)<=21) {
- led_buf[0] = 0; //0
- led_buf[1] = jie; //節
- led_buf[2] = 20; //短橫線
- led_buf[3] = 1;
- led_buf[4] = 1-Minute%16; //11分
- led_buf[5] = 20; //短橫線
- led_buf[6] = 5-Sec/16;
- led_buf[7] = 9-Sec%16; //59秒
- }
- else{
- led_buf[0] = 0; //0
- led_buf[1] = jie; //jie
- led_buf[2] = 20; //-
- led_buf[3] = 0; //0
- if(11-Minute%16<10){
- led_buf[4] = 11-Minute%16;
- }
- else{
- led_buf[4] = 1-Minute%16; //1
- }
- led_buf[5] = 20; //-
- led_buf[6] = 5-Sec/16; //5
- led_buf[7] = 9-Sec%16; //9
- }
- Write_595();
- key_value = Scan_Key();
- //keydown();
- //Delay();
- switch(key_value) //鍵盤掃描函數
- {
- case 0:
- break;
- case 0x81: // 按第一列第四行鍵 ft=1; 比分和時間轉換
- ft=1;
- break;
- case 0x41: // 按第二列第四行ft=0;時間/比分轉換
- ft=0;
- break;
- case 0x21: //按第三列第四行鍵,jie+1
- jie++;
- break;
- case 0x11:
- jie--; //按第四列第四行jie-1
- break;
- default:
- break;
- }
- }
-
-
- }
- }
- // Some Functions
- void Delay(void) //延時子程序
- {
- unsigned char m,n;
- for(m=200;m>0;m--)
- for(n=200;n>0;n--);
- }
-
- //***************************************************************************************
- //* FunctionName : Write_595() **
- //* Descriptions : write 595 **
- //* Input : led_buf[]&bit_buf[] **
- //* Output : None **
- //***************************************************************************************
- void Write_595(void) //定義595寫入函數
- {
- uchar i,j;
- uint dat;
- for(i=0;i<8;i++) //發送命令字
- {
- RCK_595_PIN=0;
- dat =bit_buf[i];
- dat =dat<<8;
- dat |= num_buf[led_buf[i]];
- for(j=0;j<16;j++)
- {
- SCK_595_PIN = 0;
- if(dat & 0x8000)
- {
- DAT_595_PIN = 1;
- }else{
- DAT_595_PIN = 0;
- }
- dat=dat<<1;
- SCK_595_PIN = 1;
- }
- RCK_595_PIN = 1;
- }
- }
- //***************************************************************************************
- //* FunctionName : Num_change() **
- //* Descriptions : Num_change **
- //* Input : **
- //* Output : None **
- //***************************************************************************************
- uchar Scan_Key(void)
- {
- uchar sm; //存放行掃描代碼,該函數的返回值的低四位
- uchar fh; //該函數的返回值的高四位
- P2 = 0xf0;
- if((P2&0xf0)!=0xf0) //判斷是否有按鍵按下
- {
- Delay(); //去抖動延時(1~10ms)
- if((P2&0xf0)!=0xf0)
- {
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼完整論文下載(word格式可編輯):
籃球計分器.doc
(920.5 KB, 下載次數: 152)
2017-4-22 14:29 上傳
點擊文件名下載附件
下載積分: 黑幣 -5