        ; Include file, change directory if needed
        include "p16f628.inc"
;       константы
RB0             EQU     0h
RB1             EQU     1h
RB2             EQU     2h
RB3             EQU     3h
RB4             EQU     4h
RB5             EQU     5h
RB6             EQU     6h
RB7             EQU     7h

RA0             EQU     0h
RA1             EQU     1h
RA2             EQU     2h
RA3             EQU     3h
RA4             EQU     4h
RA5             EQU     5h
RA6             EQU     6h
RA7             EQU     7h

;       ячейки ОЗУ(переменные)
CNT             EQU     20h     ; DELAY
CNT1            EQU     21h     ; DELAY
ROW_CNT         EQU     22h
COL_CNT         EQU     23h
COL_DAT         EQU     24h     ;load_col
COL_DAT2        EQU     25h     ; ???
TMR1_INT        EQU     26h     ; INTERRUPT PROCESSED
H_byte          EQU     27h
L_byte          EQU     28h
LED0            EQU     30h     ; Область вывода данных
LED1            EQU     31h     ; для индикатора
LED2            EQU     32h
LED3            EQU     33h
LED4            EQU     34h
LED5            EQU     35h
LED6            EQU     36h
LED7            EQU     37h
LED8            EQU     38h
LED9            EQU     39h
;TenK           EQU 0x3A-
;Thou           EQU 0x3B-
;Hund           EQU     0x3C-
;Tens           EQU     0x3D-
;Ones           EQU     0x3E-
Overflow        EQU     0x3E
Over        EQU 0x3F
NumH            EQU     0x40
NumL            EQU     0x41
TMR1_adcnt  EQU 0x42
TMR0_over       EQU 0x43
Led_hiloop  EQU 0x44
temp_W          EQU     70h     ; прерывания, ячейка не зависят от банка
temp_S          EQU     71h     ; прерывания, ячейка не зависит от банка

; переменные процедуры преобразования 24bin-8BCD
bin0    equ     0x41            ;lsb
bin1    equ     0x40
bin2    equ     0x3f            ;msb
dec0    equ     0x45            ;lsd
dec1    equ     0x46
dec2    equ     0x47
dec3    equ     0x48
dec4    equ     0x49
dec5    equ     0x4a
dec6    equ     0x4b
dec7    equ     0x4c            ;msd
bitcnt  equ     0x3a
deccnt  equ     0x3b
cycles  equ     0x3c
octcnt  equ     0x3d

;       начало исполняемого кода
        ORG     0
        GOTO    BEGIN
        ORG     04h
INTPROC                         ; Обработчик прерываний
; Сохраняем регистры
        MOVWF temp_W ; сохраняем аккумулятор
        SWAPF temp_S,F ; Сохраняем статус в перевернутом виде
; Выясняем источник прерывания
        BCF STATUS,RP0  ; Выбор банка 0

        btfsc   PIR1,0  ; регистр прерываний периферии, флаг прерывания TMR1
        goto int_tmr1   ; Прерывание не от TMR1, значит от TMR0
        
int_tmr0   ; Прерывание от таймера TMR0
                INCFSZ TMR0_over        ; Накопление старшего разряда результата
                bsf Overflow,7   ; произошло переполнение счетчика, результат неверный.
        BCF INTCON,2
        goto int_return

int_tmr1   ; Прерывание от таймера TMR1
        movlw 01              ; количество полных циклов tmr1.
        subwf TMR1_adcnt, W
        BTFSC STATUS,0        ; возник перенос - продолжить цикл, иначе - обработка прерывания
        goto int_tmr1cont
;tmr1_tick
        INCF TMR1_adcnt
        bcf     PIR1, TMR1IF ; Сброс флага прерывания от таймера TMR1
    goto int_return
int_tmr1cont
        BCF     PORTA,3     ;перед переключением в режим выхода сброс RA3 = 0
    BSF     STATUS,RP0  ;Выбор банка 1
        BCF     TRISA,3     ;RA3 = out, запрет входных импульсов
                            ; здесь заканчивается цикл измерения, это надо учесть !!!!
        BCF     STATUS,RP0  ;Выбор банка 0
        BCF     T1CON,0     ;СТОП таймер TMR1
        CLRW
        call LOAD_COL           ; гасим индикатор на время измерения, чтобы разряд не мерцал.
; Считать накопленное значение таймера.
        movf    TMR0,W
        movwf   H_byte  ; Сохранить значение таймера 0. Старший байт результата.
                        ; Для частоты 1Mгц значение ячеек равно 10 000.
; Извлечение значения предделителя TMR00.
        clrf    L_byte          ; Обнулить счетчик.
pre_cicl
        bsf     PORTA,3    ; Сформировать тактовый импульс
        bcf     PORTA,3    ; на входе таймера TMR0.
        decf    L_byte,F   ;Декремент счетчика.
        movf    H_byte,W
        xorwf   TMR0,W
        btfsc   STATUS,2   ; Значение таймера 0 изменилось?
        goto    pre_cicl   ; Нет, повторить цикл.
;NOP
;NOP
;NOP
;NOP
;NOP
;NOP
;NOP
; Регистры H_byte и L_byte хранят измеренное значение частоты

        MOVLW   0FFh       ; любое число <> 0
        MOVWF   TMR1_INT   ; Прерывание произошло, H_byte и L_byte можно пользоваться.
        MOVF COL_DAT2, W   ; восстанавливаем что горело на индикаторе до обработки
        call LOAD_COL
        bcf     PIR1,TMR1IF ; Сброс флага прерывания от таймера TMR1
int_return
        SWAPF temp_S,W
        MOVWF STATUS    ; Восстанавливаем регистр статуса
        SWAPF temp_W,F  ;переворачиваем
        SWAPF temp_W,W  ;еще раз переворачиваем и восстанавливаем аккумулятор, признаки не изменены!
        RETFIE
DELAY10MS       ;20*500
        MOVLW   02h
        MOVWF   CNT1
DELAY10MS_
        MOVLW   32h
        CALL    DELAY10X
        DECFSZ  CNT1,F
        GOTO    DELAY10MS_
        RETURN
DELAY10X        ;OSC1=5MHz T = 9.6 mks
        MOVWF   CNT
DELAY_10X
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        DECFSZ  CNT,F
        GOTO    DELAY_10X
        RETURN
;                                 e a c f h b d g
;                a b c d e f g    7 6 5 4 3 2 1 0

;  a          0  1 1 1 1 1 1 0    1 1 1 1 0 1 1 0
;f   b        1  0 1 1 0 0 0 0    0 0 1 0 0 1 0 0
;  g          2  1 1 0 1 1 0 1    1 1 0 0 0 1 1 1
;e   c        3  1 1 1 1 0 0 1    0 1 1 0 0 1 1 1
;  d   h      4  0 1 1 0 0 1 1    0 0 1 1 0 1 0 1
;             5  1 0 1 1 0 1 1    0 1 1 1 0 0 1 1
;             6  1 0 1 1 1 1 1    1 1 1 1 0 0 1 1
;             7  1 1 1 0 0 0 0    0 1 1 0 0 1 0 0
;             8  1 1 1 1 1 1 1    1 1 1 1 0 1 1 1
;             9  1 1 1 1 0 1 1    0 1 1 1 0 1 1 1
;             A  1 1 1 0 1 1 1    1 1 1 1 0 1 0 1
;             B  0 0 1 1 1 1 1    1 0 1 1 0 0 1 1
;             C  1 0 0 1 1 1 0    1 1 0 1 0 0 1 0
;             D  0 1 1 1 1 0 1    1 0 1 0 0 1 1 1
;             E  1 0 0 1 1 1 1    1 1 0 1 0 0 1 1
;             F  1 0 0 0 1 1 1    1 1 0 1 0 0 0 1
;-------------------------------------------------
;                a b c d e f g    7 6 5 4 3 2 1 0
;             -  0 0 0 0 0 0 1    0 0 0 0 0 0 0 1
;             _  0 0 0 1 0 0 0    0 0 0 0 0 0 1 0
;             ?  1 1 1 1 1 1 1    1 1 1 1 1 1 1 1
;             ?  1 1 1 1 1 1 1    1 1 1 1 1 1 1 1
;             ?  1 1 1 1 1 1 1    1 1 1 1 1 1 1 1
;             ?  1 1 1 1 1 1 1    1 1 1 1 1 1 1 1
;             ?  1 1 1 1 1 1 1    1 1 1 1 1 1 1 1
;             ?  1 1 1 1 1 1 1    1 1 1 1 1 1 1 1
SEGMENTPB
        CLRF    PCLATH
        ADDWF   PCL,F
        DT  B'011110110', B'000100100', B'011000111', B'001100111'
        dt      B'000110101', B'001110011', B'011110011', B'001100100'
        dt      B'011110111', B'001110111', B'011110101', B'010110011'
        dt      B'011010010', B'010100111', B'011010011', B'011010001'
        dt      B'000000001', B'000000010'

RESET_ROW ; RB6 - RESET ROW
;        BCF     STATUS,RP0       ;Выбор банка 0
        BSF     PORTB,RB6
        NOP
        BCF     PORTB,RB6
        RETURN
NEXT_ROW ;RB5 - ROW CLK, RESET COL_REG
;        BCF     STATUS,RP0       ;Выбор банка 0
        BSF     PORTB,RB7
        NOP
        BCF     PORTB,RB7
        RETURN
LOAD_COL ; RB5 -  RB0-RB3
;        BCF     STATUS,RP0     ;Выбор банка 0
        MOVWF   COL_DAT         ;Выводимые данные сохраним для дальнейших действий
                MOVWF   COL_DAT2        ;Сохранить хначение чтобы можно было временно погасить индикатор.
        MOVF    PORTB,W         ;Очищаем PB0-PB3 не трогая PB4-PB7
        ANDLW   B'11110000'
        MOVWF   PORTB
        MOVF    COL_DAT,W
        ANDLW   B'00001111'     ;В W - младший полубайт данных
        IORWF   PORTB,F         ;Устанавливаем PB0-PB3 соответственно младшему полубайту
        BSF     PORTB,RB5       ;Загрузка RB0-RB3 в первый регистр
        MOVF    PORTB,W         ;Очищаем PB0-PB3 не трогая PB4-PB7
        ANDLW   B'11110000'
        MOVWF   PORTB
        SWAPF   COL_DAT,W       ;Загрузка в W выв.данных и замена полубайтов
        ANDLW   B'00001111'     ;В W - только старший полубайт данных
        IORWF   PORTB,F         ;Устанавливаем PB0-PB3 соответственно старшему полубайту
        BCF     PORTB,RB5       ;Загрузка RB0-RB3 во второй  регистр
        RETURN
Convert ;Takes hex number in bin2:bin1:bin0  Returns decimal in dec7:dec6:dec5:dec4:dec3:dec2:dec1:dec0

    clrf dec0
    clrf dec1
    clrf dec2
    clrf dec3
    clrf dec4
    clrf dec5
    clrf dec6
    clrf dec7
    clrf cycles
    movlw 08
    movwf octcnt
ctloop:
    incf cycles
    movlw 03
    movwf bitcnt
bitloop:
    rlf bin0
    rlf bin1
    rlf bin2
    movlw dec0
    movwf FSR
    movfw cycles
    movwf deccnt
decloop:
    rlf INDF
    movlw 0xF6
    addwf INDF,0
    btfsc STATUS,0
    movwf INDF
    incf FSR
    decfsz deccnt
    goto decloop
    decfsz bitcnt
    goto bitloop
    decfsz octcnt
    goto ctloop
        RETURN

; Начало измерения частоты!
TIMER1_START
        BCF     STATUS,RP0      ;Выбор банка 0
; Подразумеваем что процедура вызывается в банке 0
; частота переключения TMR1 = Fosc/4 (каждую инструкцию)
; период = количество тактов * 1/(частота переключения TMR1)
; количество тактов = период * частота переключения TMR1
; 125000 тактов = 100мс * (5Мгц/4)
; 125000 = 1E848h
    MOVLW   017h            ;Константа периода измерения,
    MOVWF   TMR1H
    MOVLW   0CAh
    MOVWF   TMR1L
; Разрешение прохождения импульсов для TMR0
    BSF     STATUS,RP0  ;Выбор банка 1
    BSF     TRISA,3     ;RA3 = in, разрешение входных импульсов на TMR0 через внешние элементы
; здесь начинается цикл измерения, задержку надо учесть и компенсировать.
    BCF     STATUS,RP0  ;Выбор банка 0
    CLRF    TMR0            ;сброс таймера и предделителя
    BSF     T1CON,0     ;запуск таймера TMR1
    bsf Overflow,7
    clrf TMR0_over     ; Сброс счетчика переполнений
        clrf TMR1_adcnt
        RETURN

; ************************************************************
BEGIN
;    Инициализация портов
        CLRF    PORTA
        CLRF    PORTB
;       CLRF    TMR0
        BSF     STATUS,RP0       ;Выбор банка 1
        MOVLW   B'00010000'      ; RA3 = out, запрет входных импульсов
                                 ; RA4 = Input
        MOVWF   TRISA
        MOVLW   B'00000000'
        MOVWF   TRISB
;    Инициализация таймеров
        BSF     PIE1,TMR1IE      ;Прерывания от TMR1 разрешить.
        MOVLW   B'11100111'      ;таймер 0 внеш + предделитель 256, такт 0->1
;        MOVLW   B'11000111'      ;таймер 0 внутр + предделитель 256, такт 0->1
        MOVWF   OPTION_REG
        BCF     STATUS,RP0       ;Выбор банка 0
        MOVLW   B'00000100'      ;таймер 1 внутр + предделитель 1, стоп
        MOVWF   T1CON
;    Разрешение прерываний
        MOVLW   B'11100000'      ; Разрешаем прерывания TMR0, и переферию (TMR1)
        MOVWF   INTCON

Hi_loop
        CALL TIMER1_START       ; запуск следующего цикла таймера TMR1
        CLRF TMR1_INT
        MOVLW   10h           ; цикл 16 раз   (16 периодов отображения, затем измерение.)
        MOVWF   Led_hiloop
MAIN_CYCLE    ; Вывод нв индикатор производится из ячеек LED0 - LED9 в автономном режиме.
        MOVLW   0Ah           ; цикл 10 раз
        MOVWF   ROW_CNT
                CLRW
                CALL LOAD_COL           ; очистить регистр сегментов перед выводом
        CALL RESET_ROW
ROW_LOOP
                MOVF    ROW_CNT,W       ; обратный счетчик в аккумулятор
                SUBLW   0Ah             ; Вычитаем счетчик из 10 (начальное значение)
                BTFSS   STATUS,2        ; Проверяем, если 0 (первая цифра) то вызов не выполняется
                 CALL NEXT_ROW          ; переходим к следующей строке ...
                ADDLW LED0              ; В аккумуляторе - смещение, вычисляем адрес ячейки
                MOVWF FSR               ; адрес ячейки в индекс
                MOVF INDF,W             ; Содержимое ячейки - в аккумулятор
                CALL LOAD_COL           ; загрузить W в регистр сегментов
                CALL DELAY10MS
                DECFSZ  ROW_CNT,F
                GOTO    ROW_LOOP
    DECFSZ  Led_hiloop
        GOTO    MAIN_CYCLE

        CLRW
        call LOAD_COL       ; гасим индикатор на время измерения,
WAIT_1RES               ; синхронизация. Ожидаем результатов измерения если оно еще не закончилось.
        MOVF TMR1_INT,W
        BTFSC   STATUS,2        ; Проверяем TMR1_INT = 0 ? да, крутимся по кругу.
        GOTO WAIT_1RES          ; Нет прерывания, крутимся по кругу.

; Обновление информации о текущей частоте в конце общего цикла вывода на индикатор.
;  BCF INTCON,7              ; Запретить прерывания
        movf    H_byte,W                ; Копируем измеренную частоту
        MOVWF   NumH
        movf    L_byte,W
        MOVWF   NumL
    movf        TMR0_over,W
        MOVWF   Over
;  BSF INTCON,7                         ; разрешить прерывания
        Call Convert            ; Преобразование частоты в знаки
;гасим незначащие нули кроме индикации 1 цифры до точки и остальные после точки.
    clrf LED0
        movf dec7,W
    BTFSS STATUS,2
         goto show_led0
        clrf LED1
        movf dec6,W
        BTFSS STATUS,2
         goto show_led1
        clrf LED2
        movf dec5,W
        BTFSS STATUS,2
         goto show_led2
        clrf LED3
        movf dec4,W
        BTFSS STATUS,2
         goto show_led3
        clrf LED4
        movf dec3,W
        BTFSS STATUS,2
         goto show_led4
        goto show_led5
show_led0
        movf    dec7,W
        call SEGMENTPB
        MOVWF   LED0
show_led1
        movf    dec6,W
        call SEGMENTPB
        MOVWF   LED1
show_led2
        movf    dec5,W
        call SEGMENTPB
        MOVWF   LED2
show_led3
        movf    dec4,W
        call SEGMENTPB
        MOVWF   LED3
show_led4
        movf    dec3,W
        call SEGMENTPB
        MOVWF   LED4
show_led5
        movf    dec2,W
        call SEGMENTPB
        IORLW   b'00001000'    ; точка
        MOVWF   LED5

        movf    dec1,W
        call SEGMENTPB
        MOVWF   LED6

        movf    dec0,W
        call SEGMENTPB
        MOVWF   LED7
    
        clrw
        MOVWF   LED8
    clrw
        MOVWF   LED9

        GOTO Hi_loop

 ORG     2007h               ; Слово конфигурации
 DATA    3F62h
 ;ORG     2100h                ; EEPROM DATA
 ;DATA    3FFFh,3FFFh
 END
