what is the best way to write a delay code in assembly

Thread Starter

walid el masry

Joined Mar 31, 2009
133
i want help to write a delay code which don't interrupt the current process so it it will be accurate in it's timing and as an example i wrote a program to show the time LCD and every character i write on LCD i wait for a delay 5msec till it not busy and after writing all characters i wait for the 1 sec and recalculate or increment the time and i found that the 5msec and the time taken by increment code make delay in the whole process and the time showed on the LCD is delayed by 5mins every 4 or 5 hours

i want a 1 sec delay code which works stand alone of the main code and when it reaches the 1 sec it makes interrupt and recalculate the time

what is the best way to do that ?

i write for microchip assembly for pic16f876
 

mik3

Joined Feb 4, 2008
4,843
You can't make a delay by code and not affect the whole program. You can use an external timer of 1 second which will interrupt the uP externally.
 

GetDeviceInfo

Joined Jun 7, 2009
2,196
set up a timer interrupt which vectors to an adding routine which upon a certain accumulated count, calls your update routine.

If you have an RTC in circuit, it can perform the timing function for you.
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
to mik3
in this case i will cost my self unneeded cost and i think i can do it with the mcu as i will replay to
GetDeviceInfo next

to GetDeviceInfo
in case i use 4 mhz crystal then 1 million instructions can be executed in 1sec so after make the prescaler calculation
and assume that it is 1:256 it will be like this
10^6 pulse = 1.0 sec
256*x pulse = 1.0 sec

x pulses = 10^6/256 = 3906.25 and after ignoring the fraction then 3906 pulses must counted to indicate a 1sec

what did you mean with timer interrupt? do you mean the interrupt of the over flow or what ?
and dose this applies the calculation above?
 

Tahmid

Joined Jul 2, 2008
343
Hi,
why you don't make a subroutine for 1Sec delay including call and return? You can make with timer or using variable counter and then verify the time with Stopwatch in MPLAB.
Thanks.
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
no i want the timer do work stand alone with the main code so that i can execute instruction in the same time the timer counts cause if i make a subroutine make the controller wait for the 1 sec and then continue the main program it will makes delay in the program timing cause i waited the 1 sec + the time of the execution of the main program
 

mik3

Joined Feb 4, 2008
4,843
to mik3
in this case i will cost my self unneeded cost and i think i can do it with the mcu as i will replay to
GetDeviceInfo next



I am sorry I thought you you were using a microprocessor. In your case you can setup an interrupt which fires every second.
 

GetDeviceInfo

Joined Jun 7, 2009
2,196
yes, interrupt on overflow. I'm not familiar with the pics so I can't tell you if they have timer prescale, but if any of the timers don't give you the full second count, you will have a few steps inbetween.

If the time of day is of concern, go with the RTC
 

Tahmid

Joined Jul 2, 2008
343
Hi,
If you want to count for 1second while the program counter is running and you are doing some other work simultaneously, you would need to use one of the internal timer modules. Then you can wait for interrupt (if interrupt is enabled), else you can wait for the interrupt flag to be set high by "polling".
E.g. If you are using a 4MHz clock, and using 16 bit timer1. Each instruction takes [1/(4MHz/4)] = 1uS. So you would need 1000*1000, ie, 1million instruction time for 1second. Set timer prescaler to 16. So, your timer would overflow every 65536*16 = 1048576 instructions. So you have a 1.048576 second delay. You can enable the interrupt bit and go to the interrupt vector and carry out your required tasks each 1.048576 seconds. (Make sure you clear the interrupt flag). If you need more accuracy, set TMR1H:TMR1L for 3036, resulting in (65536-3036)*16=62500*16 = 1 sec. Set timer value to 3036 every interrupt.
Hope this helps.
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
thnx THE_RB for the link but i'm afraid iam not 100% understand the sequence due to some syntax i don't know like

tstf
skpnz
skpnc

but i tried to write a code and that's it

Rich (BB code):
    LIST P=16F876
    #INCLUDE<P16F876.INC>
    __CONFIG _CP_OFF&_LVP_OFF&_BODEN_OFF&_PWRTE_ON&_WDT_OFF&_XT_OSC
    CBLOCK 0x20
TMR0_LOW    ;0X40
TMR0_MID    ;0X42
TMR0_HIGH    ;0X0F
    ENDC
    ORG 0X00
    GOTO initialize
    ORG 0X04
;interrupt_subrutine
    BCF INTCON,GIE 
;****************************************************************************************
;test 1sec delay code
;decrement code
    DECF TMR0_LOW,1
    MOVLW 0XFF
    XORWF TMR0_LOW
    BTFSS STATUS,Z    
    GOTO out_interrupt;NO
    DECF TMR0_MID,1;YES
    MOVLW 0XFF
    XORWF TMR0_MID
    BTFSS STATUS,Z
    GOTO out_interrupt;NO
    MOVLW 0XFF;YES
    XORWF TMR0_LOW
    BTFSS STATUS,Z
    GOTO out_interrupt;NO
    DECF TMR0_MID,1;YES
;zeros test code
    MOVLW 0X00
    XORWF TMR0_LOW,W
    BTFSS STATUS,Z
    GOTO out_interrupt;NO
    MOVLW 0X00;YES
    XORWF TMR0_MID,W
    BTFSS STATUS,Z
    GOTO out_interrupt;NO
    MOVLW 0X00;YES
    XORWF TMR0_HIGH,W
    BTFSS STATUS,Z
    GOTO out_interrupt;NO
    MOVLW 0X40;YES
    MOVWF TMR0_LOW
    MOVLW 0X42
    MOVWF TMR0_MID
    MOVLW 0X0F
    MOVWF TMR0_HIGH
;****************************************************************************************
;code to be executed every 1sec
;bla
;bla
;bla    
;****************************************************************************************
out_interrupt
    BCF INTCON,T0IF
    BSF INTCON,GIE
    RETFIE
initialize
;****************************************************************************************
;initialize_variables
    MOVLW 0X40
    MOVWF TMR0_LOW
    MOVLW 0X42
    MOVWF TMR0_MID
    MOVLW 0X0F
    MOVWF TMR0_HIGH
;****************************************************************************************
;initialize_INTCON
;GIE: Global Interrupt Enable bit                = 1 = Enables all unmasked interrupts
;PEIE: Peripheral Interrupt Enable bit            = 0 = Disables all peripheral interrupts
;TMR0IE: TMR0 Overflow Interrupt Enable bit    = 1 = Enables the TMR0 interrupt
;INTE: RB0/INT External Interrupt Enable bit    = 0 = Disables the RB0/INT external interrupt
;RBIE: RB Port Change Interrupt Enable bit    = 0 = Disables the RB port change interrupt
;TMR0IF: TMR0 Overflow Interrupt Flag bit    = 0 = TMR0 register did not overflow
;INTF: RB0/INT External Interrupt Flag bit        = 0 = The RB0/INT external interrupt did not occur
;RBIF: RB Port Change Interrupt Flag bit        = 0 = None of the RB7:RB4 pins have changed state
    BANKSEL INTCON    ;goto OPTION_REG bank
    MOVLW B'10100000'
    MOVWF INTCON        ;load data into OPTION_REG
    BANKSEL 0            ;back to normal bank 0
;****************************************************************************************
;initialize_OPTION_REG
;RBPU:        PORTB Pull-up Enable bit            =   1   = PORTB pull-ups are disabled
;INTEDG:    Interrupt Edge Select bit         =   0   = Interrupt on falling edge of RB0/INT pin
;T0CS:         TMR0 Clock Source Select bit    =   0   = Internal instruction cycle clock (CLKOUT)
;T0SE:        TMR0 Source Edge Select bit        =   0   = Increment on low-to-high transition on RA4/T0CKI pin
;PSA:        Prescaler Assignment bit        =   1   = Prescaler is assigned to the WDT
;PS2:PS0:    Prescaler Rate Select bits        = 000 = 1 : 128 for WDT Rate
    BANKSEL OPTION_REG    ;goto OPTION_REG bank
    MOVLW B'10001000'
    MOVWF OPTION_REG    ; load data into OPTION_REG
    BANKSEL 0                ; back to normal bank 0
;****************************************************************************************
;initialize_PORTB&TMR0
    CLRF PORTB
    MOVLW 0X00
    MOVWF TRISB
    MOVWF PORTB
    MOVWF TMR0
;****************************************************************************************
main
;bla
;bla
;bla
    GOTO main
    END
and for you Tahmid i think you are interested so let's study my code and i will study your idea also NOTE that used crystal in this example is 4mhz
 

Markd77

Joined Sep 7, 2009
2,806
You will need to put this code in your interrupt routine which is in section 12 of the datasheet.
It is needed because the interrupt routine can happen at any point in your main code and whatever is in the interrupt routine will change these registers which would give you very unpredictable results.
Hope this gets you a bit closer.
You can also write to the timer in the interrupt if you need to get closer to 1 second.

code:
MOVWF W_TEMP ;Copy W to TEMP register
SWAPF STATUS,W ;Swap status to be saved into W
CLRF STATUS ;bank 0, regardless of current bank, Clears IRP,RP1,RP0
MOVWF STATUS_TEMP ;Save status to bank zero STATUS_TEMP register
MOVF PCLATH, W ;Only required if using pages 1, 2 and/or 3
MOVWF PCLATH_TEMP ;Save PCLATH into W
CLRF PCLATH ;Page zero, regardless of current page
:
:(ISR) ;(Insert user code here)
:
MOVF PCLATH_TEMP, W ;Restore PCLATH
MOVWF PCLATH ;Move W into PCLATH
SWAPF STATUS_TEMP,W ;Swap STATUS_TEMP register into W
;(sets bank to original state)
MOVWF STATUS ;Move W into STATUS register
SWAPF W_TEMP,F ;Swap W_TEMP
SWAPF W_TEMP,W ;Swap W_TEMP into W
</code>
 

Markd77

Joined Sep 7, 2009
2,806
If you used timer1 instead and set the timer1 prescaler to 8 you would get about 2 interrupts per second. If you set the high byte of timer 1 to 0Bh and the low byte to DB in the interrupt I think it would be very close to 2 interrupts per second. Still use the register saving code.
 

Thread Starter

walid el masry

Joined Mar 31, 2009
133
good thinking Markd77 and i missed it :D

really thnx guys and that what i wrote after deep thinking and it is working
Rich (BB code):
    list    p=16F84A
    #include p16F84a.inc
    ERRORLEVEL -302
    __CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_OFF & _XT_OSC
;************declare variables************
    CBLOCK 0X0C
status_temp:1
w_temp:1
;-------------------------------------------
cpt:1
    ENDC
;************Reset vector************
    ORG 0X00
    GOTO INIT     
;*****************Interrupt vector**************************
    ORG 0X04 
;******************Interrup subrutine*****************
    movwf   w_temp; save W register value
    swapf    STATUS,w    
    movwf    status_temp; save STATUS register value
    BTFSS   INTCON,T0IF; is the interrupt accured is for TIMER0 or not ?
    GOTO    ENDI;NO
    BCF     INTCON,T0IF;YES
    DECF    cpt,f; decrement the counter
    btfss   STATUS,Z; test if  counter reaches the end - 1 second have just passed
    GOTO    ENDI;NO
    MOVLW   D'61';YES
    MOVWF   cpt; re-intiate counter value
;***********************Code Executed every second*************************
;bla
;bla
;bla
;***********************every time when leaving interrupt do this*************************
ENDI
    swapf    status_temp,w; get the old value of the STATUS register    
    movwf   STATUS
    swapf       w_temp,f
    swapf       w_temp,w; get the old value of the W register    
    RETFIE; end of interrupt subrutine
;*****************Chip initialize**************************
INIT 
; initialize ports
    BSF     STATUS,RP0; goto bank1
    MOVLW   B'00000000' 
    MOVWF   TRISB      ; portb is output
;-------------------------------------------
; initialize special function registers
    movlw    0x85  ; interruption sur timer0  
    movwf    OPTION_REG
;RBPU        =1=     PORTB pull-ups are disabled
;INTEDG    =0=     Interrupt on falling edge of RB0/INT pin
;T0CS        =0=     Internal instruction cycle clock (CLKOUT)
;T0SE        =0=     Increment on low-to-high transition on RA4/T0CKI pin
;PSA        =0=     Prescaler is assigned to the Timer0 module
;PS2:PS0    =101=    1 : 64 for TMR0 Rate
;-------------------------------------------
    movlw    0xA0
    movwf    INTCON
;GIE    =1=     Enables all unmasked interrupts
;PEIE    =0=     Disables all peripheral interrupts
;TMR0IE    =1=     Enables the TMR0 interrupt
;INTE    =0=     Disables the RB0/INT external interrupt
;RBIE    =0=     Disables the RB port change interrupt
;TMR0IF    =1=     TMR0 register has overflowed (must be cleared in software)
;INTF    =0=     The RB0/INT external interrupt did not occur
;RBIF    =0=     None of the RB7:RB4 pins have changed state
;-------------------------------------------
;give ports and vaiables initiale values
    BCF     STATUS,RP0; return to bank0
    CLRF    PORTB
;-------------------------------------------
    MOVLW   D'61'
    MOVWF   cpt 
;************************main program********************           
START   
;bla
 ;bla
 ;bla
    goto START
    END
and it accepts this calculation
256 x 64 = 16384 usec
and
1 sec = 1000000 usec
and 1000000/16384 = 61.03515625 = 61 => D'61'

almost equal 1 sec

plz tell me if there any comments

 
Top