計時器跑太慢?? |
答題得分者是:bernie_w39
|
mtmkid12
一般會員 發表:2 回覆:4 積分:1 註冊:2007-10-06 發送簡訊給我 |
想做一個計時器,精密度是1ms,顯示於LCD上
用組語寫出來了,但是實際跑起來卻比較慢 十秒它才跑到約九秒,不知道是哪裡出錯了 使用的是Time0的MODE2模式 程式碼如下,煩請高手解惑一下!!!! 小弟感激不盡!!! |
㊣
版主 發表:261 回覆:2302 積分:1667 註冊:2005-01-04 發送簡訊給我 |
|
mtmkid12
一般會員 發表:2 回覆:4 積分:1 註冊:2007-10-06 發送簡訊給我 |
|
bernie_w39
資深會員 發表:3 回覆:199 積分:280 註冊:2007-10-07 發送簡訊給我 |
看起來您的程式在 DELAY 副程式中, 每 call 一次就會等候 1mS.
但是其它的指令, 也是會耗用時間的. 所以就造成其它指令加上去之後, 一個 LOOP 跑完, 用掉了超過 1mS 的時間, 使得計時器不準. 比較好的作法, 應該是 timer 去產生中斷, 由中斷程式去 update 顯示數值 的暫存器. 在 LOOP 中去判斷, 只要暫存器被異動了, 就顯示在 LCD 上, 如此 就不會有這麼大的誤差. 不過因為市售的 12MHz crystal 本來就沒那麼準. 所以無論如何都會有相當程度的誤差. 以前我自己在測的時候, 一天大約 會差個十幾秒左右. |
mtmkid12
一般會員 發表:2 回覆:4 積分:1 註冊:2007-10-06 發送簡訊給我 |
感謝bernie_w39大的指點!!!
小弟在思考過後也是認為其它的指令耗用掉時間,每次耗用一點時間,多次累積起來就有誤差了!!! 所以計時器會變慢的主因就在這邊!!! 另外在文中你提到用timer 去產生中斷,老實說小弟沒實際使用過這方法去寫過這類的程式!!! 所以不大清楚該如何下手!!!小弟會去找這方面的資料來研讀!!!但是否可請bernie_w39大能再仔細指點一番呢!!讓小弟能減少摸索的時間...... bernie_w39大在測的時候, 一天大約會差個十幾秒左右.我覺得這是在我可以忍受的範圍內了!!!因為我的計時器大約都只是測試在幾分鐘內的時間!!! 當然如果能有將誤差變更小的方法是更好啦!!!!還期待高手提供囉!!!感激!!! |
bernie_w39
資深會員 發表:3 回覆:199 積分:280 註冊:2007-10-07 發送簡訊給我 |
A... 好久沒用 8051 了, 忘了差不多, 剛才翻了一下文件, 邊回憶邊回覆, 如果有誤, 還請見諒.
將 tiemr0 設為 mode 2, 它會自動 reload 計數器的值, 就用您原本定的 6 ( 250 uS 中斷一次) 即可. 在中斷程式中, 固定去 INC R5, 加完了之後, 再作 R5 and 0x03, 讓 R5 計數僅在 0-3, 當 R5 and 0x03 為 0 時, 即可去增加 R1, 當 R1 加至 3A 時再加 R2 ... 這部份就會原程式的 邏輯很類似, 但切記中斷程式中僅去變換 R1 - R5 的值, 不要去 call LCD 的顯示程式, 以免一個中斷程式跑太久, 超過 250uS 就糟了. 在原本的 LOOP 中, 用 R6 去記錄 R5 的值, 如果 R6 != R5 時, 再去 update LCD 一次, 同時令 R6 = R5, 繼續等候下一次 R6 != R5 即可. 中斷程式中, 不要破壞佔存器的內容, 所有用到的暫存器 (除了 R1 - R5 原本就是要 其它程式讀到值之外), 都要先 push 起來, 中斷程式結束前再 pop 回去. |
mtmkid12
一般會員 發表:2 回覆:4 積分:1 註冊:2007-10-06 發送簡訊給我 |
感謝bernie_w39大的回覆!!!!
小弟我自己也用 time0 的中斷寫了一個程式,效果是有比較好一點了!!! 但是跑五十多秒後就會差大約一秒的誤差出現!!!!我在想應該是我寫入LCD的指令用太頻繁了!!導致出現誤差 來用看看bernie_w39大的方法好了 但是須要思考消化一下,不大了解這種方法......也感謝bernie_w39大的幫忙!!!! 我的程式在如下 [code cpp] LCD_RS REG P3.0 ;RS=P3.0. LCD_READWRITE REG P3.1 ;R/W=P3.1. LCD_ENABLE REG P3.2 ;ENABLE=P3.2. LCD_BUS REG P2 ;DB0-DB7=P2. ORG 00H JMP INITIAL ORG 0BH JMP LOOP INITIAL: MOV SP, #60H ; ;-------------------LCD 驅動程式------------------------------------------ ; MOV A, #38H ;設定8 BIT 位元寬度 CALL WRITELCDCOMMAND MOV A, #0CH ;設定資料及游標均顯示. CALL WRITELCDCOMMAND ; MOV R1, #30H ;LCD顯示0 MOV R2, #30H MOV R3, #30H ;LCD顯示0 MOV R4, #30H MOV R5, #30H MOV R6, #30H CALL LCD_CLS ;清除LCD. MOV TMOD,#00000001B MOV TH0,#>(65536-1000) MOV TL0,#<(65536-1000) MOV IE,#10000010B SETB TR0 WAIT: MOV A,#06H ;設定字串2在第2行57H處顯示. MOV B,#0 CALL LCD_LOCATE MOV A,R6 CALL WRITELCDDATA MOV A,R5 CALL WRITELCDDATA MOV A,R4 CALL WRITELCDDATA MOV A,#2EH CALL WRITELCDDATA MOV A,R3 CALL WRITELCDDATA MOV A,R2 CALL WRITELCDDATA MOV A,R1 CALL WRITELCDDATA JMP WAIT LOOP: PUSH A MOV TH0,#>(65536-1000) MOV TL0,#<(65536-1000) INC R1 CJNE R1,#3AH,LOOP1 MOV R1,#30H INC R2 CJNE R2,#3AH,LOOP1 MOV R2,#30H INC R3 CJNE R3,#3AH,LOOP1 MOV R3,#30H INC R4 CJNE R4,#3AH,LOOP1 MOV R4,#30H INC R5 CJNE R5,#3AH,LOOP1 MOV R5,#30H INC R6 LOOP1: POP A RETI [/code]
編輯記錄
mtmkid12 重新編輯於 2007-10-07 23:17:54, 註解 無‧
|
bernie_w39
資深會員 發表:3 回覆:199 積分:280 註冊:2007-10-07 發送簡訊給我 |
問題的成因應該不是您說的那樣.
問題在於您的 timer0 並不是 auto-reload 的作法, 而是用程式去 load 一個 64536 的值. 所以當 timer0 被 load 進這個值之後, 會在 1mS 之後觸發中斷沒有錯, 但是中斷之後, 並 沒有立即 reload 這個 64536 的值, 因為中斷發生之後, 只是設定中斷旗號, 當到達 指令週期時, 才會引發中斷, 中斷產生後, 還要先將 PC 塞入 stack, 才會執行到 0B 的位址. 再 jump 到中斷程式, 然後才 reload 了 64536 到 timer0. 剛才這些動作, 可能用去了大約 20uS 的時間, 所以造成您的計時器, 每 1000uS 就延後了 15-20uS 所以 50 秒後, 就有一秒的誤差產生. 建議您將 timer0 改成 auto-reload 的模式, 這樣就可以確保每個中斷有著準確的間隔. |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |