線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:1984
推到 Plurk!
推到 Facebook!

計時器跑太慢??

答題得分者是:bernie_w39
mtmkid12
一般會員


發表:2
回覆:4
積分:1
註冊:2007-10-06

發送簡訊給我
#1 引用回覆 回覆 發表時間:2007-10-06 15:53:22 IP:122.123.xxx.xxx 訂閱
想做一個計時器,精密度是1ms,顯示於LCD上
用組語寫出來了,但是實際跑起來卻比較慢
十秒它才跑到約九秒,不知道是哪裡出錯了
使用的是Time0的MODE2模式
程式碼如下,煩請高手解惑一下!!!!
小弟感激不盡!!!
編輯記錄
mtmkid12 重新編輯於 2007-10-07 23:15:18, 註解 無‧
mtmkid12 重新編輯於 2007-10-07 23:18:44, 註解 無‧
mtmkid12 重新編輯於 2007-10-07 23:20:46, 註解 無‧
mtmkid12 重新編輯於 2007-10-07 23:21:12, 註解 無‧

版主


發表:261
回覆:2302
積分:1667
註冊:2005-01-04

發送簡訊給我
#2 引用回覆 回覆 發表時間:2007-10-06 17:11:36 IP:219.70.xxx.xxx 未訂閱
請先確認你的 crystal 是多少. 還有一個指令週期是多少 usec.
弄錯了 Timer 算錯是很平常的事. 而你這樣的情形應該是它跑太快.
------
-------------------------------------------------------------------------
走是為了到另一境界,停是為了欣賞人生;未走過千山萬水,怎知生命的虛實與輕重!?
mtmkid12
一般會員


發表:2
回覆:4
積分:1
註冊:2007-10-06

發送簡訊給我
#3 引用回覆 回覆 發表時間:2007-10-06 18:24:48 IP:122.123.xxx.xxx 訂閱
感謝版大的回應
小弟用的石英晶體是12M的
想請教一下如何得知一個指令週期是多少 usec呢???
小弟這各程式實際RUN起來真的是比實際時間慢的,不知道原因為何??
懇請前輩幫忙解惑!!!感激
bernie_w39
資深會員


發表:3
回覆:199
積分:280
註冊:2007-10-07

發送簡訊給我
#4 引用回覆 回覆 發表時間:2007-10-07 11:46:24 IP:59.121.xxx.xxx 訂閱
看起來您的程式在 DELAY 副程式中, 每 call 一次就會等候 1mS.
但是其它的指令, 也是會耗用時間的. 所以就造成其它指令加上去之後,
一個 LOOP 跑完, 用掉了超過 1mS 的時間, 使得計時器不準.

比較好的作法, 應該是 timer 去產生中斷, 由中斷程式去 update 顯示數值
的暫存器. 在 LOOP 中去判斷, 只要暫存器被異動了, 就顯示在 LCD 上, 如此
就不會有這麼大的誤差. 不過因為市售的 12MHz crystal 本來就沒那麼準.
所以無論如何都會有相當程度的誤差. 以前我自己在測的時候, 一天大約
會差個十幾秒左右.
mtmkid12
一般會員


發表:2
回覆:4
積分:1
註冊:2007-10-06

發送簡訊給我
#5 引用回覆 回覆 發表時間:2007-10-07 12:25:37 IP:122.123.xxx.xxx 訂閱
感謝bernie_w39大的指點!!!
小弟在思考過後也是認為其它的指令耗用掉時間,每次耗用一點時間,多次累積起來就有誤差了!!!
所以計時器會變慢的主因就在這邊!!!
另外在文中你提到用timer 去產生中斷,老實說小弟沒實際使用過這方法去寫過這類的程式!!!
所以不大清楚該如何下手!!!小弟會去找這方面的資料來研讀!!!但是否可請bernie_w39大能再仔細指點一番呢!!讓小弟能減少摸索的時間......
bernie_w39大在測的時候, 一天大約會差個十幾秒左右.我覺得這是在我可以忍受的範圍內了!!!因為我的計時器大約都只是測試在幾分鐘內的時間!!!
當然如果能有將誤差變更小的方法是更好啦!!!!還期待高手提供囉!!!感激!!!
bernie_w39
資深會員


發表:3
回覆:199
積分:280
註冊:2007-10-07

發送簡訊給我
#6 引用回覆 回覆 發表時間:2007-10-07 15:48:59 IP:59.121.xxx.xxx 訂閱
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

發送簡訊給我
#7 引用回覆 回覆 發表時間:2007-10-07 17:47:07 IP:122.123.xxx.xxx 訂閱
感謝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

發送簡訊給我
#8 引用回覆 回覆 發表時間:2007-10-07 20:32:26 IP:59.121.xxx.xxx 訂閱
問題的成因應該不是您說的那樣.

問題在於您的 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 的模式, 這樣就可以確保每個中斷有著準確的間隔.
系統時間:2024-05-14 9:52:47
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!