UMBC | CMSC 391 -- Programming Microcontrollers |
Instruction | Nr of Cycles | Number of Executions | Total 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 secondI came up with a delay of 0.0010026 seconds, or 1.0026 milliseconds.
Actual delay - Desired delay Terror = ----------------------------- Desired delay
That gives us:
1.0026 - 1.0000 Terror = ---------------- = 0.26% 1.0000One 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.
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
InitValue = TL1 + (256 * TH1)
We will set up the timer and set up the interrupt, and then do whatever else we would like to do.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 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