Ernestas Gruodis
Ernestas Gruodis

Reputation: 8787

Programming PIC16F84A processor precise delays with assembler

I have this code - all LEDs are turn on and off every 1 second (using MPLAB X IDE, assembler, oscillator frequency is 4MHz):

#include <p16f84a.inc>

    __CONFIG _WDTE_OFF & _PWRTE_OFF & _CP_OFF & _FOSC_HS

;General registers for delay
CounterA equ h'0c'
CounterB equ h'0d'
CounterC equ h'0e'

    org 0

Start:
    ; select bank 1
    bsf STATUS, RP0
    ; set port B as output
    movlw b'00000000'
    movwf TRISB
    ; select bank 0
    bcf STATUS, RP0

MainLoop:
    ; turn on LEDS
    movlw b'11111111'
    movwf PORTB
    call Delay_1s
    movlw b'00000000'
    movwf PORTB
    call Delay_1s
    goto MainLoop ;Repeat

Delay_1s:
    movlw d'6'
    movwf CounterC
    movlw d'24'
    movwf CounterB
    movlw d'168'
    movwf CounterA
loop:
    decfsz CounterA,1
    goto loop
    decfsz CounterB,1
    goto loop
    decfsz CounterC,1
    goto loop
    return

    end

Could someone explain how the Delay_1s is working? I have tried to multiply 168 * 24 * 6 = 24192 µS, but that is incorrect, I should get 1000000 µS..

EDIT:

I'm getting closer - decfsz CounterA,1 takes 1 µS, and goto loop takes 2 µS to process. So I think the answer should look like (168 * 3) * (24 * 3) * (6 * 3) = 653184 µS. Of cource I should add 6 µS while setting values to CounterA, CounterB and CounterC. Is there something I missing?

EDIT2:

I've added time valus to each operation below. Do I understand it right?

Delay_1s:
    movlw d'6' ; 1µS
    movwf CounterC ; 1µS
    movlw d'24' ; 1µS
    movwf CounterB ; 1µS
    movlw d'168' ; 1µS
    movwf CounterA ; 1µS
loop:
    decfsz CounterA,1 ; 1µS
    goto loop ; 2µS (the same while skipping)
    decfsz CounterB,1 ; 1µS
    goto loop ; 2µS (the same while skipping)
    decfsz CounterC,1 ; 1µS
    goto loop ; 2µS (the same while skipping)
    return ; 1µS ??

Upvotes: 1

Views: 3480

Answers (2)

user13819772
user13819772

Reputation: 11

I have reviewed this program and found that the number of cycles this routine spends is 1,003,827 which is equivalent to 1.003827 seconds.

I did it by three different methods and I have always got the same result.

Method 1: A formula Method 2: A simulation in Python Method 3: Using the MPLAB simulator, setting breakpoints and observing the cycle counter before and after the function call.

The formula is deduced as follows

Let's first ask ourselves how many cycles a program like the following takes:

loop: decfsz x, f This line runs x times, x-1 times does not jump and 1 time jumps, so the number of cycles is x-1) +2 goto loop This runs x-1 times so cycles are 2 (x-1) in total, cycles are (x-1) + 2 + 2 (x-1) = 3x-1 cycles

Let's consider that x is between 1 and 256 (includes 1 and 256, if x is 0, it equals 256)

So the number of cycles of the complete program is

Counter cycles A The first time when B has its initial value 3A-1 The following times of counter B (B-1) * (3 * 256-1) The next times of counter C (C-1) * 256 * 767 Counter B cycles The first time when C is 6 3B-1 The following times of C (C-1) * 767 Counter C cycles The first and only time 3C-1 The call, the Return and 6 initialization lines 10 ------------------------- total: 3A + 770B + 197 122C-197879

Substituting A for 168, B = 24 and C = 6 gives the value of 1,003,837 better values ​​would have been A = 172 B = 19 C = 6 which produces 999,999 adding a nop in variable initialization would give 1,000,000

Upvotes: 1

Neujahr
Neujahr

Reputation: 11

Sorry that I'm not good at explaining, but I hope this will give you some clue:

  Using a 4MHz Xtal OSC 
  Set OPTION_REG to b'11010100'
                     'xxxxx100' = 1 instruction :32 uSeconds
        32 uSeconds *    250 = 8 milliseconds
        8 milliseconds * 125 = 1 second 
        PORTB (all outs)     = B'00000000'                   

EIGHT_MS   EQU  0x10

INIT
      BSF  STATUS, RP0
      MOVLW      B'11010100'
      MOVWF      OPTION_REG
      MOVLW      B'00000000'
      MOVWF      TRISB
      BCF  STATUS, RP0
      CLRF       PORTB
      RETURN
START
L0    CLRF  TMR0
L1    MOVF  TMR0, W
      XORLW .250
      BTFSS STATUS, Z
      GOTO  L1
      CLRF  TMR0
      INCF  EIGHT_MS 
      MOVF  EIGHT_MS, W
      XORLW .125
      BTFSS STATUS, Z
      GOTO  L1
      CALL  LIGHT_LED
      GOTO  L1      

LIGHT_LED
      ...
      CALL DELAY
      ...

      RETURN


MAIN  
      CALL INIT
      CALL START
      GOTO MAIN

Upvotes: 1

Related Questions