實習十一      8051做1/100秒計時碼表

一•目的:瞭解 8051 Timer 計時功能原理及控制方法。

 

二•使用材料:8051 微電腦一片,4個共陰七段顯示器。

 

三•功能說明:Power ON Reset ( 冷開機 )後,4個七段顯 "0000";若接著按一次Reset

                   ( 第一次暖開機 ),則開始以1/100秒計時並由七段跳動顯示;此時再按一次Reset

                   ( 第二次暖開機 ),則停止計時,七段顯示出時間如 " 32 : 85 "為 32 秒 85 。再

                    按 Reset 相當冷開機動作。

 

四•程式流程圖

        (a) 主程式:       

       

        (b)中斷程式

        

五•接線及說明

        接線圖如實習六

        (1) J47 接 P3.0 ~ P3.3

        (2) J50 接 P1.0 ~ P1.7

六•程式及程式說明

                    . RSECT                                                 ; define register section

                    . ABSOLUTE                                         ; adsolute RAM address

                    . ORG           20H                                   ; offset address = 20h

RESET  _ COUNT           .DS             1                      ; reset switch hit counter

SECOND1_200               .DS             1                      ; unit = 1/200 S , 0-2

SECOND1_100               .DS             1                      ; unit = 1/100 S , 0-9 ,D0

SECOND1_10                 .DS             1                      ; unit = 1/10  S , 0-9  ,D1

SECOND1                       .DS             1                      ; unit = 1s , 0-9          ,D2 

SECOND10                     .DS             1                      ; unit = 10s , 0-9        ,D3

COUNT                           .DS             1                      ; scan digit counter

STACK _ BOTTOM          EQU           $                    ; stack bottom pointer

                     . CODE                                                  ; program code

                     . RELATIVE                                          ; relative address

                     ORG           000H                                   ; reset offset address

                     JMP            BEGIN                                 ; jump to main procedure

                     ORG           00BH                                   ; timer0 offset address

                     JMP            TIMER                                 ; jump to interrupt

BEGIN :                                                                       ; reset stare here

                     MOV           COUNT,#0                          ; clear scan counter                

                     MOV           SP,#STACK _ BOTTOM     ; set stack bottom pointer

                     MOV           R0,#RESET _ COUNT        ; load r0 with reset _ times

                     CJNE           @R0,#1,NEXT1                  ; first warm reset ?

                     INC              RESET _ COUNT               ; inc reset times

;first warm reset , activate timer0 , start to count , once/5000us

                     MOV            SECOND1_200,#0             ; clear clock buffer

                     MOV            SECOND1_100,#0             ; clear clock buffer (dis0)

                     MOV            SECOND1_10,0                 ; clear clock buffer (dis1)

                     MOV            SECOND1,#0                     ; clear clock buffer (dis2)

                     MOV            SECOND10,#0                   ; clear clock buffer (dis3)

                     MOV            TMOD,#00000001B           ; set time0 ; mode1 , 16-bit

                     MOV            TH0,#> - 5000                    ; load TH0 with high byte

                     MOV            TL0,#< - 5000                     ; load TL0 with high byte

                     MOV            IE,#100000010B                 ; enable timer0 interrupt

                     SETB            TR0                                     ; turn timer0 on

                     JMP              $                                          ; do nothing , loop here

NEXT1:   

                     CJNE           @RO,#2,CLEAR                  ; second warm reset ?

                     INC              RESET_ COUNT                 ; inc reset times

HOLD:                                                                          ;

;second warm reset , show how many seconds , get from display buffer

                    CALL            DISPLAY                            ; scanning one display

                    CALL            DELAY - 5000us                ; delay about 5000us

                    JMP               HOLD                                 ; keep scanning display

CLEAR:                                                                        ;

; cold reset start or third warm reset , show 00:00

                    MOV             RESET_ COUNT,#1           ; initial reset _ counter=1

                     MOV            SECOND1_100,#0             ; clear clock buffer (dis0)

                     MOV            SECOND1_10,0                 ; clear clock buffer (dis1)

                     MOV            SECOND1,#0                     ; clear clock buffer (dis2)

                     MOV            SECOND10,#0                   ; clear clock buffer (dis3)

show_0:                                                                        ;

                     CALL            DISPLAY                           ; scanning one display

                     CALL            DELAY - 5000us               ; delay about 5000us

                     JMP               SHOW_0                            ; keep scanning display

DELAY _ 5000US:                                                       ; delay for scan each digit

                     MOV             R7,#10                               ; delay time about

$1:                MOV             R6,#250                             ;   =  R7*(R6*2us)

                     DJNZ             R6,$                                   ;   = 10 *(250*2us)

                     DJNZ             R7,$1                                 ;   = 5000US

                     RET                                                          ;

; timer0 mode1 overflow interrupt procedure , 5000us / once=(200hz)

TIMER:                                                                          ;

                      PUSH            ACC                                   ; save accumulator value

                      PUSH            PSW                                   ; save program status

                      SETB             RS0                                    ; select register bank1

                      CLR               TR0                                    ; stop timer0

                      MOV              A,#< (-5000+7)                  ; compensate 7u seconds

                      ADD               A,TL0                                ;   = MOV TH0 - TL0,#(-5000+7)

                      MOV               TL0,A                                ; 7 one cycle instructions

                      MOV               A,#> (-5000+7)                 ; =MOV, ADD, MOV , MOV ,

                      ADDC             A, TH0                              ; ADDC, MOV , SETB,

                      MOV               TH0,A                               ; reload , include overflow

                      SETB               TR0                                   ; restart timer0 .

                                                                                        ;

                      INC                  SECOND1_200                 ; count per 5000u=1/200 S

                      MOV                A, SECOND1_200            ; A = times of (1/200 s)

                      CJNE                A, #2,NEXT                      ; non- equal 2, jmp away

                      MOV                SECOND1_200,#0            ; 1/100 S = 2*(1/200 S )         

                                                                                         ;

                      INC                  SECOND1_100                 ; increment per 1/100S

                      MOV                A, SECOND1_100            ; A = times of (1/100 s)

                      CJNE                A, #10,NEXT                    ; non- equal 10, jmp away

                      MOV                SECOND1_100,#0            ; 1/10 S = 10*(1/100 S )         

                                                                                         ;

                       INC                  SECOND1_10                   ; increment per 1/10S

                       MOV                A, SECOND1_10              ; A = times of (1/10 s)

                       CJNE                A, #10,NEXT                    ; non- equal 10, jmp away

                       MOV                SECOND1_10,#0              ; 1 S = 10*(1/10 S )         

                                                                                          ;  

                       INC                  SECOND1                          ; increment per 1 S

                       MOV                A, SECOND1                     ; A = times of (1 s)

                       CJNE                A, #10,NEXT                     ; non- equal 10, jmp away

                       MOV                SECOND1,#0                     ; 10 S = 10*(1 S )         

                                                                                           ;  

                       INC                   SECOND10                        ; increment per 10 S

                       MOV                 A, SECOND10                   ; A = times of (10 s)

                       CJNE                 A, #10,NEXT                     ; non- equal 10, jmp away

                       MOV                 SECOND10,#0                   ; 1 min = 10*(10 S )         

                                                                                            ;  

NEXT:

                       CALL                DISPLAY                            ; go to scan dislpay

                       POP                   PSW                                    ; get back program status

                       POP                   ACC                                    ; get back accumulator

                       RETI                                                             ; return main program

DISPLAY:  

                       MOV                  R0,#COUNT                       ; load r0 with scan counter

                       CJNE                  @R0,#0,DIS1                     ; if count not 0,jmp dis1

                       INC                     COUNT                              ; count = count +1

                       MOV                   P3,#111111110B               ; enable digit 0

                       MOV                   DPTR, #TABLE_7_SEG    ; get 7-segment table address

                       MOV                   R0,#SECOND1_100          ; index = 1/100 s buffer addr

                       MOV                   A,@R0                               ; load A with buffer content

                       MOVC                 A, @A + DPTR                  ; convert number to 7-seg code

                       MOV                    P1,A                                  ; display from port 1

                       RET                                                               ; return caller

                                                                                             ;      

DIS1:                      

                      MOV                   R0,#COUNT                       ; load r0 with scan counter

                      CJNE                   @R0,#1,DIS2                     ; if count not 1,jmp dis2

                      INC                      COUNT                              ; count = count +1

                      MOV                    P3,#111111101B               ; enable digit 1

                      MOV                    DPTR, #TABLE_7_SEG    ; get 7-segment table address

                      MOV                    R0,#SECOND1_10            ; index = 1/10 s buffer addr

                      MOV                    A,@R0                               ; load A with buffer content

                      MOVC                  A, @A + DPTR                  ; convert number to 7-seg code

                      MOV                     P1,A                                  ; display from port 1

                      RET                                                                 ; return caller

                                                                                              ;         

DIS2:                      

                      MOV                    R0,#COUNT                        ; load r0 with scan counter

                      CJNE                   @R0,#2,DIS3                       ; if count not 2,jmp dis3

                      INC                      COUNT                                ; count = count +1

                      MOV                    P3,#111111011B                 ; enable digit 3

                      MOV                    DPTR, #TABLE_7_SEG      ; get 7-segment table address

                      MOV                    R0,#SECOND1                    ; index = 1 s buffer addr

                      MOV                    A,@R0                                 ; load A with buffer content

                      MOVC                  A, @A + DPTR                    ; convert number to 7-seg code

                      MOV                     P1,A                                    ; display from port 1

                      RET                                                                   ; return caller

                                                                                                ;

DIS3:                      

                      MOV                    R0,#COUNT                        ; load scan count with zero         

                      MOV                    P3,#111110111B                 ; enable digit 3

                      MOV                    DPTR, #TABLE_7_SEG      ; get 7-segment table address

                      MOV                    R0,#SECOND10                  ; index = 10 s buffer addr

                      MOV                    A,@R0                                 ; load A with buffer content

                      MOVC                  A, @A + DPTR                    ; convert number to 7-seg code

                      MOV                     P1,A                                    ; display from port 1

                      RET                                                                   ; return caller

;7-segment LED 0-9 display code , PABCDEFG , "0"=LED ON.

TABLE_7_SEG                          DB   10000001B,11001111B,10010010B,1000110B

                                                   DB   11001100B,10100100B,10100000B,1000111B

                                                   DB   10000000B,10000100B;0-9

                                                   END

程式說明

1•4 ~ 6  行  :設定暫存器段(Register Section),且聯結時偏移位址設為絕對 20H。

2•7 ~ 14  行:由RAM位址20H開始保留名變數之記憶位址。其中20H設定為判斷

       Reset次數之記憶位址。冷開機(cold start)時, RAM內含值不定,依程式則做

       clear 碼表動作,並設20H內含為1,再按 Reset 則設 2,再按則設3,以後20 H

       之內就隨 Reset 鈕而成1,2,3 之變化。

3•16 ~ 21行 : 程式段開始,並以相對方式組譯指令。安排斷向量位址。

4•23 ~ 26行 :先判斷是暖開機嗎?若 RAM 20H 為 1 表示暖開機。

5•27 ~ 37行 :變更RAM 20H值,清除存放碼表計數的 RAM 記憶體,設定Timer 0

       工作方式為 16 位元上數計時器,每 1us 上數一次,設 -5000 表示 5000us 溢位

       一次。致能 Timer 0 溢位中斷。

6•38 ~ 39 行:啟始 Timer 0,計時開始。程式原地執行表示不做任何事。

7•40 ~ 42 行:按 Reset 後,20H 不是 1而是2,表示第三次 Reset, 做下一 hold 動作。

       並將位址 20H 遞增成為 3。

8•43 ~ 47 行:將目前顯示器各計數的 RAM 位址持續多工掃描顯示。須注意,此時

       之 Timer 0 是在停止狀態,因為 Reset 後,直接到此處執行程式而末曾啟始 Timer 0

       。每 5000 us 致能一個七段顯示器。

9•48 ~ 58 行:將顯示器計數的 RAM清除,再掃描顯 "0000"。此段為冷開機或每隔

       3次 Reset 之動作。

10•59 ~ 64 行:延遲 5000us之副程式。

11•66~108行:中斷副程式,負責碼表計時遞顯器計數RAM 之值,再做多工掃描顯示

        器工作。其中 72~78 行為重新將 -5000 載人TH0、TL0;但是為求準確計時,Timer 0

        溢位後,又超越遞增若干應一併補償,71行先停止上數,72行之7為停止Timer 0 到

        再次啟動 Timer 0 間 (72~78行)共花費之指令時間為7us,73行是TL0 計數過頭也一併

        加人,加完若進位也會在76行中加人 TH0 。反正,Timer 溢位直到進人中斷,一定少

        許過數( overrun);若純粹用來多工掃描鍵盤或顯示器是不必計較的,做為時鐘計則可

        比照此段指令補償之。

12• 109 ~ 155 行:多工掃描顯示器副程式,請參考第三章3.5節實驗四說明。