Also:
James Cameron says:
These SXs are just too fast, we often need a way to have the processor wait around for a while. A series of NOP (no operation) instructions is straightforward, but wasteful of instruction memory. A counted loop is the next common trick, because that lets us tune it.But what are some of the more exotic ways to delay?
) The Common NOP, a delay for one instruction cycle
DELAY nop ; delay one cycleAdvantages: extremely simple, obvious, maintainable, scaleable.
Disadvantages: is it really there for a reason?
) The Common Loop, four times the initial value
DELAY mov W, #95 ;1 380 cycle delay mov COUNTER, W ;2 decsz COUNTER ;3 7 11 15 jmp $-1 ;4 8 12 16Advantages: fairly simple, maintainable, scaleable up to 1024 cycles (counter initialized with zero); after that go for a nested loop.
Disadvantages: costs one file register; though there is a variant using just the W register.
) The Novel GOTO, three instruction cycles in one instruction
jmp $+1 ;three cycle delayAdvantages: third the space of three NOPs.
Disadvantages: obscure unless commented.
) The Call to Nowhere
org 0 jmp MAIN delay6 ret ;six cycle delay function [...] DELAY call delay6Advantages: 1/6 the space of six NOPs, the RET can be reused by other code.
Disadvantages: implementation separate from use, can look odd, uses one stack level.Scott Dattalo says:
...if you want a 4-cycle [ed: in compatible mode] single-instruction delay: call some_return_in_your_code Of course, you run the risk of stack overflow on [some processors]
) The Double Call to Nowhere, 12 cycles
org 0 jmp MAIN delay12 call delay6 delay6 ret [...] DELAY call delay12Advantages: looks simple, allows various size delays to be rapidly constructed during prototyping.
Disadvantages: uses two stack levels.[ed: See the "Stack Recursive Delay" below]
) The Do Something Useful Extension to the Common Loop, six times the initial value
DELAY mov W, #95 ;1 mov COUNTER, W ;2 mov W, TRISM ;3 9 15 fetch port direction mirror mov !RB, w ;4 10 16 reapply it decsz COUNTER ;5 11 17 jmp $-3 ;6 12 18Advantages: allows useful functionality to be placed within the delay.
Disadvantages: increased convolution of code, lower maintainability.
) The Long Delay Using Timer, more of a technique than a code fragment, set the timer, wait for it to roll over.
Advantages: immune to distortion by interrupts, easily scaled using a prescaler, even possible to tune the delay by modifying the preload value.
Disadvantages: allocates a timer.Paul B. Webster says:
I feel that many applications (real-time control, clocks) resolve to a fundamental "tick" or hierarchy thereof, often around a millisecond, which method {7} provides. Counting a thousand of these gives a second, at which point a train of countdowns (semaphores) can lead to various housekeeping actions i.e., if T1 then { T1--; if T1 == 0 then action1 };On the 1 ms "ticks" also, a debounce uses a counter which counts down from 20 (20 ms) to verify a keypress/ release. Other countdowns in ms are used for playing tunes or "tick", "Click" or "blip" noises.
It is highly undesirable to pre-load or fiddle with the TMR0 when you are using it this way, firstly because it interferes with the prescaler in a very inconvenient fashion, and secondly as the 1 ms countdowns can be used for a 500 Hz tone while the TMR0 MSB can be copied to a port for a 1 kHz tone, bit 6 for a 2 kHz tone, etc., controlled as above in even numbers of milliseconds.
You can similarly, wait on those individual bits by polling, for sub- delays. A sub-delay on bit 3 toggling could be used to time a phase accumulator (32 kHz clock) to generate quite a complete range of square wave tones.
So, you may say that method "uses" a timer-counter, but I submit that in a well-designed application, you get an awful lot of "use" out of it!
) The Watchdog Delay, go to sleep and get woken by the watchdog.
Advantages: extremely simple technique, can be varied by changing the WDT prescaler ratio.
Disadvantages: difficult to calibrate.
[ed: Set up a type of state machine that records where the processor should contine executing code after the reset. Make sure you clear it in your non-timed routines. Also see Using the watchdog timer to sense temperature]
) The Data EEPROM Delay, a typically 10ms delay that can be triggered by writing to data EEPROM and waiting for the interrupt.
Advantages: tests the endurance of the EEPROM.
Disadvantages: tests the endurance of the EEPROM.
Tony Nixon says:
Here's a a simple example [for the SX at 50Mhz], but it won't be accurate
to the second, so you may have to tweak it. Perhaps you could use it as a
basis for your code.
mov W, #x ; x = hours delay
mov hours, W
call Hours_Delay
; rest of code continues
Hours_Delay
call Hour_Delay
decsz hours
jmp Hours_Delay
ret
Hour_Delay
mov W, #60
mov mins, W
Rst_Loop
mov W, #60
mov secs, W
Hour_Loop
call Second_Delay
;
; maybe some processing in here
;
decsz secs
jmp Hour_Loop
decsz mins
jmp Rst_Loop
ret
Second_Delay
mov W, #5 ;50e6 / 4 = 12 500 000 = 100*100*250*5
mov NbHi, W
mov W, #250
mov NbLo, W
mov W, #100
mov NaHi, W
mov W, #100
mov NaLo, W
DeLoop0
decsz NaLo ;delay1 = NaLo*4 - 2
jmp DeLoop0 ;
decsz NaHi ;delay2 = (NaLo*4 - 2) * NaHi + (NaHi*4 - 2) =
jmp DeLoop0 ;= NaLo*NaHi*4 + NaHi*2 - 2
decsz NbLo
jmp DeLoop0
decsz NbHi ;totaldelay ~= 4*NaLo*NaHi*NbLo*NbHi
jmp DeLoop0
ret
The name of the lable you call indicates the number of cycles (Convert cycles to time) that will be executed before returning. This uses an amazingly small number of bytes and is probably more effecient than inline loops or nop's if you are going a lot of little delays of varying times through out your code.
Delay131072 call Delay16384 ; uses 6 stack levels
Delay114688 call Delay16384
Delay98304 call Delay16384
Delay81920 call Delay16384
Delay65536 call Delay16384
Delay49152 call Delay16384
Delay32768 call Delay16384
Delay16384 call Delay2048 ;uses 5 stack levels
Delay14336 call Delay2048
Delay12288 call Delay2048
Delay10240 call Delay2048
Delay8192 call Delay2048
Delay6144 call Delay2048
Delay4096 call Delay2048
Delay2048 call Delay256 ;uses 4 stack levels
Delay1792 call Delay256
Delay1536 call Delay256
Delay1280 call Delay256
Delay1024 call Delay256
Delay768 call Delay256
Delay512 call Delay256
Delay256 call Delay32 ;uses 3 stack levels
Delay224 call Delay32
Delay192 call Delay32
Delay160 call Delay32
Delay128 call Delay32
Delay96 call Delay32
Delay64 call Delay32
Delay32 call Delay8 ;uses 2 stack levels
Delay24 call Delay8
Delay16 call Delay8
Delay8 nop ;uses 1 stack level
nop
ret
James Newton says:
I also wrote this god-awful macro for the Parallax SX key asembler that may
be of use to someone: It produces the smallest and/or tightest loop delays
inline when you call it with the value and units of time you wish to delay
for; calculating the number of cycles based on the processor speed. The CpuMhz
equate must be adjusted to what ever is right for your chip. It should probably
be called CpuMips vice CpuMhz. The only redeming virtue is that it does not
use anything other than w (on the SX you can decrement W); no stack use,
no register use. :
device pins28, pages1, banks8, turbo, stackx, optionx, carryx
reset reset_entry
CpuMhz = 50
temp ds 1
usec equ -6
msec equ -3
sec equ 1
cycles equ 0
mynop MACRO
noexpand
page $>>8
ENDM
cyclefor MACRO 1
_cycles = \1
IF _cycles > 0
_temp = $//4
IF _temp = 2
IF _cycles < 5
REPT _cycles
expand
mynop
noexpand
ENDR
_cycles = 0
ELSE
expand
mynop
noexpand
_cycles = _cycles -1
ENDIF
ENDIF
IF _temp = 1
IF _cycles < 6
REPT _cycles
expand
mynop
noexpand
ENDR
_cycles = 0
ELSE
expand
mynop
mynop
noexpand
_cycles = _cycles -2
ENDIF
ENDIF
IF _cycles > 3
expand
mov w, #_cycles / 3
decsz 1 ;dec w
clrb 2.1 ;modify PC to jump back
noexpand
_cycles = _cycles // 3 ;cycles left over
ENDIF
IF _cycles > 0
REPT _cycles
expand
mynop
noexpand
ENDR
ENDIF
ENDIF
ENDM
reset_entry
mov w,#$7F
mov !OPTION,w
delayhelp MACRO
ERROR 'USAGE: delay value, [usec,msec,sec,cycles]'
ENDM
delay MACRO 2
noexpand
IF (\2=usec OR \2=msec OR \2=sec) AND (\1<1000 AND \1>0)
IF \2=sec
_cycles = (\1 * 1000000 / (1000/CpuMhz))
ENDIF
IF \2=msec
_cycles = (\1 * 1000 / (1000/CpuMhz))
ENDIF
IF \2=usec
_cycles = (\1 / (1000/CpuMhz))
ENDIF
IF \2=cycles
_cycles = \2
ENDIF
IF _cycles = 0
expand
;delay less than one cycle at this processor speed'
noexpand
ELSE
IF _cycles > 255
REPT (_cycles / 256)
cyclefor 256
_cycles = _cycles - 256
ENDR
ENDIF
cyclefor _cycles
ENDIF
ELSE
delayhelp
ENDIF
ENDM
delay 999, usec
delay 200, usec
delay 250, usec
delay 10, usec
delay 20, usec
delay 100, msec
| file: /Techref/scenix/lib/flow/delays_sx.htm, 12KB, , updated: 2004/6/10 14:40, local time: 2025/10/24 04:12,
216.73.216.20,10-1-5-169:LOG IN
|
| ©2025 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://massmind.ecomorder.com/techref/scenix/lib/flow/delays_sx.htm"> SX Microcontroller Delay Program Flow Methods</A> |
| Did you find what you needed? |
Welcome to ecomorder.com! |
|
Ashley Roll has put together a really nice little unit here. Leave off the MAX232 and keep these handy for the few times you need true RS232! |
.