Программирование точных задержек процессора PIC16F84A на ассемблере

У меня такой код - все светодиоды включаются и выключаются каждую 1 секунду (используется MPLAB X IDE, ассемблер, частота генератора 4МГц):

#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

Может ли кто-нибудь объяснить, как работает Delay_1s? Я пытался умножить 168 * 24 * 6 = 24192 мкс, но это неверно, я должен получить 1000000 мкс.

ИЗМЕНИТЬ:

Я приближаюсь - decfsz CounterA,1 занимает 1 мкс, а goto loop занимает 2 мкс для обработки. Поэтому я думаю, что ответ должен выглядеть так (168 * 3) * (24 * 3) * (6 * 3) = 653184 мкс. Конечно, я должен добавить 6 мкс при установке значений CounterA, CounterB и CounterC. Я что-то упускаю?

EDIT2:

Ниже я добавил значения времени для каждой операции. Я правильно понимаю?

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 ??

person Ernestas Gruodis    schedule 09.05.2014    source источник
comment
Прошло некоторое время с тех пор, как я много занимался ассемблером PIC, но я думаю, что хитрость может заключаться в том, что, например, CounterA будет только 168 в первый раз, а затем 256 во второй раз, потому что он не сбрасывается. Это складывается, если вы работаете таким образом?   -  person PeterJ    schedule 09.05.2014
comment
Да, может быть - если CounterA и CounterB начинаются с 256 (CounterC только стремится к нулю, а затем возвращается процедура) - тогда результат будет 390150, а если я умножу его на 3 мкс - то я получаю 1,170450 сек.   -  person Ernestas Gruodis    schedule 09.05.2014


Ответы (2)


Извините, что я не умею объяснять, но я надеюсь, что это даст вам некоторую подсказку:

  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
person Neujahr    schedule 19.11.2014

Я просмотрел эту программу и обнаружил, что количество циклов, которые эта процедура тратит, составляет 1 003 827, что эквивалентно 1,003827 секундам.

Я делал это тремя разными способами и всегда получал один и тот же результат.

Метод 1: Формула Метод 2: Моделирование в Python Метод 3: Использование симулятора MPLAB, установка точек останова и наблюдение за счетчиком циклов до и после вызова функции.

Формула выводится следующим образом

Давайте сначала спросим себя, сколько циклов занимает программа, подобная следующей:

цикл: decfsz x, f Эта строка выполняется x раз, x-1 раз не выполняется переход и 1 раз выполняется переход, поэтому количество циклов равно x-1) +2 цикл перехода Это выполняется x-1 раз, поэтому циклов 2 (x -1) всего циклов (x-1) + 2 + 2 (x-1) = 3x-1 циклов

Предположим, что x находится в диапазоне от 1 до 256 (включает в себя 1 и 256, если x равен 0, это равно 256)

Таким образом, количество циклов полной программы равно

Циклы счетчика A Первый раз, когда B имеет начальное значение 3A-1 Следующие времена счетчика B (B-1) * (3 * 256-1) Следующие времена счетчика C (C-1) * 256 * 767 Счетчик Циклы B Первый раз, когда C равно 6 3B-1 Последующие времена C (C-1) * 767 Циклы счетчика C Первый и единственный раз 3C-1 Вызов, Возврат и 6 строк инициализации 10 ----- -------------------- итого: 3А+770В+197 122С-197879

Подстановка A вместо 168, B = 24 и C = 6 дает значение 1 003 837, лучшими значениями были бы A = 172 B = 19 C = 6, что дает 999 999, добавление nop в инициализацию переменной дало бы 1 000 000

person user13819772    schedule 26.06.2020