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 13:40, local time: 2024/11/20 00:00,
18.221.80.42:LOG IN
|
©2024 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://linistepper.com/techref/scenix/lib/flow/delays_sx.htm"> SX Microcontroller Delay Program Flow Methods</A> |
Did you find what you needed? |