![]() |
發布時間: 2023-11-12 17:22
正文摘要:多功能秒表系統設計 設計要求: (1)兩位LED顯示,顯示時間為00~99秒。 (2)具有開始、暫停、復位功能。 (3)在秒表工作過程中能通過按鍵多次(不少于4次)記錄當前的時間。 (4)可以通過按鈕查看記錄的 ... |
鵜鶘 發表于 2023-11-17 15:27 試了,符合我想的功能 |
呵呵你試沒試,結果怎樣?你是不是這個意思,達沒達到目的? 另外,我的那個中斷程序中前半部分不甚合理,應該把對stp_run的判斷放在最外層,還有就是count和miao的+1都沒不要單獨存在,都可以合并到條件判斷中,這樣程序就更簡潔清晰,也更符合C風范: void time0() interrupt 1 { static bit dp; TH0=(65536-10000)/256; TL0=(65536-10000)%256; P0=0x00; //xiao timer++; if (stp_run) { if(++count==100) { count=0; if (++miao==100) { miao=0; } } } if (dp=~dp) { P0=table[c]; w0=0,w1=1; } else { P0=table[d]; w1=0,w0=1; } } |
鵜鶘 發表于 2023-11-15 21:30 太牛了,大佬 |
原理更重要吧,清楚了原理怎樣做是很自由的,我先把原理說下,一個修改方案提供給你,你也不必照搬的,可隨意修改試驗。 這種LED數碼管的直接驅動都是以掃描方式實現的,且掃描的頻率要穩定不受其他程序部分的干擾,你的程序之所以僅在秒表時看起來正常,是因為它就是在快速重復掃描,但你這種掃描太易受到干擾而停頓,即在主函數的while中循環,當你不按按鍵或只按s1-s3時,scankeys可以快速返回,顯示會連續,但按下s4或者s5我上面那貼說過因為延遲和判斷是否抬起它就會延遲返回或者按著不放它就不返回,顯示就不正常。 所以這種數碼管的顯示一般都是分兩個部分,驅動和賦值是分開的,驅動部分只是將顯示緩沖區的內容依次輪換送數碼管顯示,而向顯示緩沖區賦值是另一部分,可以在程序的任何地方、任何時候執行(在這里顯示緩沖區就是c、d兩個無符號字符變量)。驅動部分又必須等頻率不斷重復執行,這樣數碼管才會看起來常亮且不受干擾而停頓,要做到這點驅動部分就只能放在計時器的中斷程序里,這樣,你的display函數就要修改,把它分成兩部分,計算和賦值部分(實際只有兩句)留下,其余都移到中斷程序中。 但這還不夠,引起這個中斷的是計時器,而你啟停秒表是靠啟停這個計時器實現的,這又不行,因為計時器一停中斷就消失,數碼管沒了驅動就立即不亮了,所以這個也要改,計時器只要一上電初始化后就必須立即工作直到斷電,這樣才能使顯示驅動不停地等間隔刷新數碼管,并且頻率要足夠高以使眼睛覺察不出閃爍。這又引來了一個問題,看你的程序參數,你用的是12兆的晶振,計時器0,模式1,中斷頻率是20Hz,作為秒表用,這個沒問題,但兼作顯示驅動頻率太低,數碼管肯定會閃,,,所以兼顧編程方便和人眼的視覺暫留特性,這個頻率應該提高到100Hz,為此 timedr0init 函數中的50000應改成10000,對應的,中斷函數中的 if(count==20)改成 if(count==100),即每100次中斷為一秒到。由于計時器一上電初始化后就要立即工作,所以這個函數中的另一處TR0=0;要改成TR0=1;。既然TR0不能再=0了,那么啟停秒表就用更常規的辦法:設置一個全局的標志位,比如Bit Stop_run,加在程序頭部的說明區中;而且作為顯示緩沖區的變量c、d也要全局化,因為主函數要向它賦值,中斷函數也要用到它,為此將他倆的定義從display函數中取出也放置在此處。啟停秒表就靠標志位Stop_run被置1/清零來實現,置1表示秒表啟動;清零表示暫停/停止,反過來當然也可以,,,相應的中斷程序中miao++;和下面的兩句改為: if (Stop_run) { miao++; if(miao==100) miao=0; } 如果Stop_run的01定義與此相反的話前面加個非號就行了。Stop_run的置1/清零就用你的scankeys函數中的s1-s3處理語句來執行,將TR0=0或1改成相應的Stop_run=0或1。 另外,你也沒說你想達到什么目的,秒表就不用說了,主要是回顯那幾個記錄值用什么方式、要達到什么效果,根據你貼出的程序看,你大概想以這樣的方式回顯:按下s5健,就立即在數碼管上依次顯示所有記錄值,每個記錄值顯示的時間由delay(100);控制。你的display函數在scankeys函數中的這種用法根本達不到目的,且邏輯還很混亂,并且delay函數的性能究竟怎樣,delay(100)究竟能延時多長時間這都不知道,直覺看它遠不會達到1秒,如果你真想用這種方式回顯,那么每個記錄值顯示的時間怎么也應該超過1秒吧。 根據這些條件我給你提供一個修改方案供你參考: 在變量聲明區后面再附加兩句: bit stp_run=0; uchar c,d,timer; 函數timedr0init改為: void timedr0init() { TMOD=0x01; TH0=(65536-10000)/256; TL0=(65536-10000)%256; TR0=1; ET0=1; EA=1; } 增加一個延時函數: void wait(unsigned char t)//t單位為10ms,當t=200時,即延時2秒。 { timer=0; while (timer<t); } 函數display改為: void display(uchar n) { c=n/10; d=n%10; } 函數scankey改為: void scankeys() {static bit recordFlag = 0; //聲明了一個靜態的位變量 recordFlag,并將其初始化為 0 static unsigned char recordIndex = 0;//靜態無字符變量 if(s1==0)//啟動 { stp_run=1; } if(s2==0)//暫停 { stp_run=0; } if(s3==0)//清零 { stp_run=miao=count=0; } if (s4 == 0) { // 記錄 if (!recordFlag && recordIndex < 4) { recordFlag = 1; recordTimes[recordIndex++] = miao; while (s4 == 0); delay(100); // 等待按鍵釋放,防止重復記錄 } } else { recordFlag = 0; } if (s5 == 0) { // 查看記錄 if (recordIndex > 0) { uchar i; for (i = 0; i < recordIndex; i++) { display(recordTimes[ i]); wait(150); //延時1.5秒,即每個數字顯示1.5秒。 } } } } 中斷程序改動比較大,但大部分代碼可以復制/粘貼過來: void time0() interrupt 1 { static bit dp; TH0=(65536-10000)/256; TL0=(65536-10000)%256; P0=0x00; //xiao timer++; count++; if(count==100) { count=0; if (stp_run) { miao++; if (miao==100) miao=0; } } if (dp=~dp) { P0=table[c]; w0=0,w1=1; } else { P0=table[d]; w1=0,w0=1; } } 未提及的,就保留原文。 |
1556544 發表于 2023-11-14 21:19 上面呢位大佬講的二維數組沒有聽說過,剛學得新手 ![]() |
鵜鶘 發表于 2023-11-14 11:19 大佬,可以幫忙修改一下嗎,新手不是特別懂 |
他已經建立數組了,只是沒必要二維吧,序號就可以作為記錄的數據是第幾個。問題是他這個程序實在是太勉強了,直接驅動數碼管不是這種方法,他的 display 函數這樣寫是不對的,只能在不按S4和S5的情況下正常,但也只是看似正常,這就是我說的“勉強”的意思,當按下S4或S5時,在按下的這段時間里有一個數碼管會滅,而亮的那個數碼管會保持,不會變化,尤其是S4,只要不抬起來一直保持這樣不變,這恐怕并不是你需要的功能吧,按下S5鍵情況就更復雜了,按下不動基本上是亂顯示,這取決于你的delay函數,delay(100)究竟會延遲多長時間,如果時間很短,那就是亂顯示,如果時間很長比如超過0.5秒,會看到兩個數碼管閃亮幾次,次數由記錄的次數決定,最多4次,閃亮的時間很短由display函數中的delay(5);決定,基本也看不清,如果按著S5不放就是這個過程反復循環。 由這個分析能夠猜出你的用意,想的是挺美,但這個程序做不到,僅僅是秒表勉強能用。要修改的話,量也不是很大,但框架就變了。。。 |
本帖最后由 yzwzfyz 于 2023-11-15 09:36 編輯 1、建立一個二維數組【P,2】,P記錄你歷史上記錄的秒表數據是第幾個。2秒表讀數0-99。 2、建立三個指針P1\P2\P3:P1=當前的秒表P號,P2=【記錄】按鍵指向的P號,P3=【查詢】按鍵指向的P號。 3、顯示程序,只從【P1,2】取數字顯示,也即只顯示P1所指向的數據。 鍵操作: 1、按下【記錄】鍵:P2=P2+1(表示進行到第幾個記錄了),P1=P2(顯示指向新的P2記錄)。 2、按下【查詢】鍵:P3=P3+1(表示查詢到第幾個記錄了),P1=P3(對查詢到的記錄進行顯示)。 3、按下【開始、清0、暫定】鍵:加一條 P1 = P2 (顯示改為【記錄】所指定的記錄號,并在此記錄上進行操作,這樣保證【查詢】后,能回到之前的記錄號,不致混亂),其它操作與你的定義相同。 如此: 能讓你記錄到P組秒表數據(循環使用1-P),做到P組數據互不干擾,可查可詢,且查詢不影響當前的操作,甚至在讀秒時查詢也不影響當前的秒表計秒工作。 |
建產數組存儲數據,再修改按鍵程序,上下翻看 |
wulin 發表于 2023-11-12 20:12 求大佬指導,純萌新 |
wulin 發表于 2023-11-12 20:12 if (s4 == 0) { // 記錄 if (!recordFlag && recordIndex < 4) { recordFlag = 1; // 將記錄后移 for ( i = 3; i > 0; i--) { recordTimes[ i] = recordTimes[i-1]; } // 記錄當前時間 recordTimes[0] = miao; while (s4 == 0); delay(100); // 等待按鍵釋放,防止重復記錄 } } else { recordFlag = 0; } |
wulin 發表于 2023-11-12 20:12 大佬,程序添加在哪里,求指導,純新手,不是特別熟練 |
按下記錄鍵,緩存recordTimes[3]=recordTimes[2];recordTimes[2]=recordTimes[1];recordTimes[1]=recordTimes[0];全部后移,再將當前秒數存在recordTimes[0]。始終保存最近4次的記錄 |