Here is an updated DelayCy() subsystem for generating precise "fixed" or "constant" delays which can be specified directly in cycles or specified in microseconds or milliseconds using operand multipliers. The subsystem uses a 9 word subroutine and a macro that generates an additional four instructions each time it's invoked.
Here is an example of how you might use the DelayCy() subsystem;
; ; example "beep" routine generates a precise 500 Hz tone using ; almost any clock (4, 8, 12, 16, or 20 MHz) ; bsf beep,5 ; do 32 msec new press beep dobeep movf PORTA,W ; read PORTA xorlw b'00001000' ; toggle speaker bit movwf PORTA ; toggle speaker pin DelayCy(1*msecs-6) ; 1 msec minus 6 cycle loop time decfsz beep,F ; done? yes, skip, else goto dobeep ; toggle speaker pin again
Here's the actual DelayCy() subsystem (macro and subroutine). The subroutine features Mike Bond's 16 bit 5 cycle timing loop using just four instructions and four 'nop' instructions in front to accommodate the delay%5 cycles. Note that the assembler preprocessor does most of the work for us in the macro.
You will need to set the 'clock' equate to your clock frequency (in MHz) if you intend to use the 'usecs' and/or 'msecs' delay operand multipliers.
radix dec clock equ 4 ; setup 4, 8, 12, 16, or 20 MHz usecs equ clock/4 ; cycles/microsecond multiplier msecs equ clock/4*1000 ; cycles/millisecond multiplier ; ; DelayCy() macro ; DelayCy macro pCycles ; cycles, 11..327690 range movlw high((pCycles-11)/5)+1 movwf TMRH movlw low ((pCycles-11)/5) call uDelay-((pCycles-11)%5) endm ; ; example code for simulation testing ; SimTest DelayCy(10*msecs-3) ; 10 msecs minus 3 cycles nop ; put simulator break point here ; ; uDelay(11..327690) subroutine Mike McLaren, K8LH, Mar '09 ; ; 9 words, 1 RAM variable, 14-bit core ; nop ; entry for (delay-11)%5 == 4 |B0 nop ; entry for (delay-11)%5 == 3 |B0 nop ; entry for (delay-11)%5 == 2 |B0 nop ; entry for (delay-11)%5 == 1 |B0 uDelay addlw -1 ; subtract 5 cycle loop time |B0 skpc ; borrow? no, skip, else |B0 decfsz TMRH,F ; done? yes, skip, else |B0 goto uDelay ; do another loop |B0 return ; |B0
Comments: