Name: | Mr. John W Nall |
Web Site: | |
Code:
delay.htm Precision delay routine for 18F452 at 40 MHz. Entry points for delays of 1 second, 100 milliseconds, 10 milliseconds and 1 millisecond. Voluminous comments. Easily adapted to other clock speeds.; ; General delay routine, for delaying 1 millisecond, 10 milliseconds, ; 100 milliseconds, or 1 second. Written specifically for the 18F452 chip ; running at 40Mhz. ; ; As written, the routine is set up to be assembled as relocable object code, ; and linked with other object routines. To use as absolute code, just extract ; the pertinent code and paste it into your routine. ; Use: call d_1_ms (or any of the other entry points) from your routine ; ; Any change in clock speed will require changes to the constants used. ; ; We are using Timer0 for the delay, loading a constant value into the counter which ; the timer increments once each instruction cycle. Therefore, the only things that ; need to be changed are the constants. Since the delay routine offers a choice of ; 1ms, 10ms, 100ms or 1 second delays, there are four constants generated. Each constant ; represents 65535 minus the number of instructions cycles to be performed until the ; specific time value is reached. Since the timer increments a 16-bit counter and sets ; a bit when the counter overflows, then we merely have to start the value of the counter ; at 65535 less the number of instruction cycles. ; ; EXAMPLE: With a 40MHZ clock (10 MHz crystal using the PLL option of the 18F452), the ; instructions are executed with a 10Mhz clock (40MHZ/4) since the clock speed is divided ; down by a factor of 4. Therefore, 10 million instructions are executed every second. ; One instruction is executed in 100 nanoseconds. ; 6 -6 -9 ; (1 second)/(10 * 10 ) = .1 * 10 = 100 * 10 ; ; Incrementing a 16-bit counter every 100 nanoseconds, it would not take very long before it ; overflows. Luckily, Timer0 has the capability to prescale, using factors of 2, 4, 8, 16, ; 32, 64, 128 or 256. If we use the 256 prescale, then the counter is only incremented ; once for each 256 instruction cycles, which makes things a bit more doable. Specifically, ; the 16-bit counter would not overflow for 1.664 seconds, if we started at zero. ; ; If, on the other hand, we used the 128 prescale factor, the timer would overflow in 832 ; milliseconds. So we would have to make another run to get up to 1 second (although it ; would work for the others). So we use 256 to make sure we can get everything up to and ; including 1 second during just one run of timer. ; ; Now, since we are dividing our actual clock speed (10 MIPS) by 256, the effective ; clock speed (for the purpose of incrementing the counter) will be 39.0625 KHz. ; 6 ; (10 * 10 )/256 = 39062.5 instructions per second ; ; This means, of course, that rather than being incremented every 100 nanoseconds, ; the counter is incremented every 25.6 microseconds ; 3 -3 -6 ; (1 second)/(39.0625 * 10 ) = 0.0256 * 10 = 25.6 * 10 ; ; Since 39062.5 instructions execute in one second, then what we need to do is to set our ; one second counter to 65535 - 39063 (rounding up) = 26472. If it starts there, and we ; then activate the timer, it will do an additional 39063 increments and set the overflow ; bit. ; ; This makes it easy to set the constants for 100 ms, 10 ms and 1 ms, since we just have ; to divide by some power of ten. ; ; 100 ms = .1 seconds, 10 ms = .01 seconds, and 1 ms = .001 seconds. ; ; To get the figure for 100 ms, we have 65535 - 3906 = 61629. ; ; Likewise, for 1 ms, the constant is 65496 ; 10 ms, 65144 ; 1 second, 26472 ; ; All of which means that we have finally gotten to the routine. #include <p18f452.inc> global d_1_ms, d_10_ms, d_100_ms, d_1_sec radix dec ; ; Generate the constants which will be loaded into TMR0L and TMR0H ; These will have to be changed if a different clock speed is used. ; Just use the technique as outlined above to calculate new constants. ; Also note the "radix dec" statement above. These are decimal numbers. :) d_1ms_h equ 65496/256 ; generate the high order byte d_1ms_l equ 65496 % 256 ; and the low order byte (modulus 256) d_10ms_h equ 65144/256 d_10ms_l equ 65144 % 256 d_100ms_h equ 61629/256 d_100ms_l equ 61629 % 256 d_1sec_h equ 26472/256 d_1sec_l equ 26472 % 256 d_code code d_1_ms movlw d_1ms_h ; if called to delay 1 millisecond movwf TMR0H movlw d_1ms_l bra delay d_10_ms movlw d_10ms_h ; if called to delay 10 milliseconds movwf TMR0H movlw d_10ms_l bra delay d_100_ms movlw d_100ms_h ; if called to delay 100 milliseconds movwf TMR0H movlw d_100ms_l bra delay d_1_sec movlw d_1sec_h ; if called to delay 1 second movwf TMR0H movlw d_1sec_l delay movwf TMR0L ; saved a few instructions :-) ; ; Set the necessary bits for the timer ; clrf T0CON ; start with a virgin ; ; 16-bit timer, use internal instruction clock, use prescaler, 1:256 ; movlw B'00000111' iorwf T0CON,1 bcf INTCON,TMR0IF ; clear the overflow bit tlp1 btfsc INTCON,TMR0IF bra tlp1 ; make sure overflow bit is clear bsf T0CON,TMR0ON ; enable the timer ; ; Now, just hang out, looking cool, and wait for the bit to be set ; tlp2 btfss INTCON,TMR0IF bra tlp2 bcf T0CON,TMR0ON ; disable timer return end
Interested: