UMBC CMSC 391 -- Programming Microcontrollers  


This lecture draws heavily on the material in:

Timing

We saw in the lecture on C programming that we can create a loop that will deal the program for some number of milliseconds. The number of milliseconds in this case is in the DPL register:
Timing Analysis
InstructionNr of CyclesNumber of ExecutionsTotal Cylces
        lcall delay       
2 1 2
delay:  mov     r0, dpl   
1 1 1
00001$: mov     r1, #230  
1 1 1
00002$: nop               
1 230 230
        nop               
1 230 230
        nop               
1 230 230
        nop               
1 230 230
        nop               
1 230 230
        nop               
1 230 230
        djnz    r1, 00002$
2 230 460
        djnz    r0, 00001$
2 1 2
        ret               
2 1 2

That gives a total of 1056 cycles. The formula for calculating the times is:

                    1848 x 12
Tinsts = --------------------------
                    22,118,400 per second
I came up with a delay of 0.0010026 seconds, or 1.0026 milliseconds.

Error

The formula for the error is:
         Actual delay - Desired delay
Terror = -----------------------------
               Desired delay

That gives us:

         1.0026 - 1.0000
Terror = ----------------  = 0.26% 
             1.0000
One quarter of one percent, that is good! Isn't it?

What are the requirements? If you are to perform a task for five milliseconds, plus or minus one percent, this represents failure. Back to the drawing board!

This is also not a good solution for another reason. While this delay is being performed, the microcontroller can do nothing else. (Of course, that may or not be a bad thing, especially if you have nothing else to do.

But what happens if there is an interrupt? There goes the our timing, right down the drain.

Hardware Timing

Going back to the math, our frequency is 22,1118,400 and there are 12 states (or clock pulses) per machine cycle. The number of machine cycles per second is: 22,118,400/12=1,843,200 or 0x1C2000 Now, if I want to do something once a second, I need a a counter that will countup to that value. I also need something that will be incremented once EVERY clock cycle. That sounds like I need a hardware timer for this!

If I want to use a 16-bit value in Timer1 for timing purposes (the largest possible using only one timer), the time delay is calculated:

            (12 * (65,536 -InitValue))
TimeDelay = -------------------------
                    22,118,400
Our initial value is set up as:
InitValue = TL1 + (256 * TH1)
That does not help us get our one second delay. So will will overflow the timer 1Ch times and have one time that only gives the 2000h. Sounds like a simple loop. (DONT DO UNTIL loop) We can use a counter and count down using the DJNZ instruction. When we reach zero, we have our delay.

We will set up the timer and set up the interrupt, and then do whatever else we would like to do.

Example

                   
                   
                   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                   ;; Equates                                  ;;
                   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0000:                       .EQU    MODE16, 0x33
0000:                       .EQU    TIMER1, 40h
                   
                   ;82C55 memory locations, Rev 4
0000:              .equ    port_a, 0xF800           ;access port A
0000:              .equ    port_b, 0xF801           ;access port B
0000:              .equ    port_c, 0xF802           ;access port C
0000:              .equ    port_abc_pgm, 0xF803     ;configure in/out of all th
0000:              .equ    port_d, 0xF900           ;access port D
0000:              .equ    port_e, 0xF901           ;access port E
0000:              .equ    port_f, 0xF902           ;access port F
0000:              .equ    port_def_pgm, 0xF903     ;configure in/out of all th
                   
                   ; Useful routines in PAULMON2 that you can call.  When you
                   ; later want a stand-alone application, you can copy them
                   ; from the PAULMON2 source code (or write you own if you lik
0000:              .equ    cout, 0x0030             ;print byte in acc to seria
0000:              .equ    cin, 0x0032              ;get byte from serial port 
0000:              .equ    phex, 0x0034             ;print acc in hex (2 digits
0000:              .equ    phex16, 0x0036           ;print dptr in hex (4 digit
0000:              .equ    pstr, 0x0038             ;print a string @dptr
0000:              .equ     esc, 0x003E             ;paulmon2's check for esc k
0000:              .equ    newline, 0x0048          ;print a newline (CR and LF
0000:              .equ    pint8u, 0x004D           ;print acc as unsigned int 
0000:              .equ    pint16u, 0x0053          ;print dptr as unsigned int
                   
                   
                   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                   ;; Code                                      ;;
                   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                   
                   
2000:                       .org    2000h
2000: 80 49                 sjmp    startup
                   
                   
                   ;
                   ; We are going to take advantage of PAULMON2 interrupt handl
                   ; Except for the interrupt timer 1, simply output a message 
                   ; the name of the interrupt.  That would demostrate that the
                   ; worked if we wished to test it.
                   ;
                   
2003:                       .org    0x2003
2003: 90 20 6A              mov     dptr, #ie0msg
2006: 12 00 38              lcall   pstr
2009: 32                    reti
                   
200B:                       .org    0x200B
200B: 90 20 6F              mov     dptr, #tf0msg
200E: 12 00 38              lcall   pstr
2011: 32                    reti
                   
2013:                       .org    0x2013
2013: 90 20 74              mov     dptr, #ie1msg
2016: 12 00 38              lcall   pstr
2019: 32                    reti
                   
201B:                       .org    0x201B
201B: 80 0D                 sjmp    tf1handler
201D: 32                    reti
                   
2023:                       .org    0x2023
2023: 90 20 7E              mov     dptr, #sermsg
2026: 12 00 38              lcall   pstr
2029: 32                    reti
                   
                   tf1handler:      
202A: D5 01 10              djnz    1, skipping
202D: EF                    mov     a, R7
202E: 04                    inc     a
202F: FF                    mov     R7, a
2030: 11 3E                 acall   ledout
2032: 75 01 1C              mov     1, #1Ch
2035: 75 8B 00              mov     TL1, #0
2038: 75 8D 00              mov     TH1, #0
203B: C2 8F                 clr     TF1
                   skipping:
203D: 32                    reti
                   
                   ledout:
203E: C0 83                 push    dph
2040: C0 82                 push    dpl
2042: 90 F9 01              mov     dptr, #port_e
2045: F0                    movx    @dptr, a
2046: D0 82                 pop     dpl
2048: D0 83                 pop     dph
204A: 22                    ret
                   
                   startup:
                   
                       ;
                       ; Set up the LEDs
                       ;
204B: 90 F9 03              mov     dptr, #port_def_pgm
204E: 74 80                 mov     a, #128
2050: F0                    movx    @dptr, a        ;make all D-E-F port pins o
                   
                       ;
                       ; Set up registers
                       ;
2051: 7F 00                 mov     R7, #0h                 ; Value to display 
2053: 79 1D                 mov     R1, #1Dh        ; Need to overflow this man
                   
                       ;
                       ; Set up the timers.  We need 1C2000h machine cycles, so
                       ;   the first time through so that we only do it 2000h t
                       ;   0000 - 2000 = 0E000 
                       ;   We will then have to the loop 1D times to get to our
                       ;
2055: 75 8B 00              mov     TL1, #0
2058: 75 8D E0              mov     TH1, #0E0h
                   
                       ;
                       ; Set up the Interrupts
                       ;
                            ;
                            ; Set up TMOD SFR -- NOT BIT ADDRESSABLE
                            ;
205B: 85 33 89              mov     TMOD, MODE16    ; Set it up as a 16-bit tim
                   
                   
                            ;
                            ; Set up TCON SFR -- Start the time
                            ;
205E: 85 40 88              mov     TCON, TIMER1
                   
                            ; 
                            ; Set up TCON
                            ;
2061: D2 8E                 setb    TR1             ; Start your engines
                            
                            ;
                            ; Set up IE
                            ;
2063: D2 AB                 setb    ET1
2065: D2 AF                 setb    EA
                   
                   ;
                   ; Just to prove that we can do something else and
                   ; let the timers do the work, we will do nothing,
                   ; once everything has been initialized.  Now it
                   ; is up to the interrupt handler.
                   ;
                   foo:     
2067: 80 FE                 sjmp    foo
2069: 22                   ret
                   
                   
                   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                   ;; Data                                      ;;
                   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
206A: 49 45 30 0D 
      00           ie0msg: .db      "IE0",      13, 0
206F: 54 46 30 0D 
      00           tf0msg: .db     "TF0",      13, 0
2074: 49 45 31 0D 
      00           ie1msg: .db     "IE1",      13, 0
2079: 54 46 31 0D 
      00           tf1msg: .db     "TF1",      13, 0
207E: 53 45 52 49 
      41 4C 0D 00 
                   sermsg: .db      "SERIAL",   13, 0


©2004, Gary L. Burt