STATUS EQU 03h ;регистр статуса
PORTB EQU 06h ;порт В
TRISB EQU 86h ;регистр настройки порта В
RP0 EQU 5h ;бит выбора банка (статус)
DAT EQU 04h ;бит данных (порт В)
SYN EQU 05h ;бит синхронизации (порт В)
PCL EQU 02h ;регистр программного счетчика
;программные регистры (переменные)
X EQU 0ch ;выводимое число
CNT_1 EQU 0dh ;счетчики
CNT_2 EQU 10h
CNT_3 EQU 12h
CNT_4 EQU 13h
W1 EQU 0eh ;временные регистры для расчетов
W2 EQU 0fh
W3 EQU 11h
C EQU 0h ;номер бита С в статусе
ORG 0h ;точка входа
GOTO START
ORG 4h ;прерывание отсутствует
RETFIE
START ;начало программы
BSF STATUS,RP0 ;выбор банка 1
BCF TRISB,DAT ;используем на выход бит данных
BCF TRISB,SYN ;и бит синхро
BCF STATUS,RP0 ;банк 0
BSF PORTB,DAT ;установка битов в 1
BSF PORTB,SYN
CLRF X ;начинаем с X = 0
;основной цикл
M00 CALL DISPLAY ;рисуем Х
CALL PAUSE ;пауза
INCF X,1 ;Х = Х + 1
GOTO M00 ;и на повтор
;вывод числа в регистре Х на дисплей
DISPLAY
MOVLW d'4' ;4 цифры
MOVWF CNT_1 ;CNT_1 - счетчик цифр
MOVF X,0 ;W = X
MOVWF W1 ;W1 = W = X
;цикл вывода десятичных знаков
M01 MOVLW d'10' ;будем делить W1 на 10 и получать в W остаток
CALL DIVISION ; от деления - очередной младший разряд
CALL CODE_SEG ;конвертируем число в сегментный код
CALL OUT_SEG ;зажигаем нужные сегменты
DECFSZ CNT_1,1 ;CNT_1 = CNT_1 - 1, если 0, то на RETURN
GOTO M01 ;иначе повторяем
RETURN ;выход
;вывод цифры (отработка сегментов, заданных в регистре W)
OUT_SEG
MOVWF W2 ;W2 = W
MOVLW d'8'
MOVWF CNT_2 ;CNT_2 = 8 - число бит
;цикл по битам
M03 BCF PORTB,DAT ;установка в 0 RB4 (чтобы горело)
BTFSC W2,0 ;если 0 бит в регистре W2 = 0, то пропускаем
BSF PORTB,DAT ;команду, если нет, то установка RB4 в 1 (чтобы потухло)
; синхронизация PORTB
BCF PORTB,SYN
BSF PORTB,SYN
RRF W2,1 ;сдвиг вправо на 1 бит
DECFSZ CNT_2,1 ;по всем 8 битам
GOTO M03 ;повтор
RETURN
;деление W1 на W
;находим путем последовательного вычитания
;делителя из делимого
;результат: W1 - частное, W - остаток
DIVISION
MOVWF W2 ;сохраним W в W2, т.к. след команда его портит
MOVF W1,0 ;W = W1
MOVWF W3 ;W3 = W = W1 - делимое
MOVF W2,0 ;восстановим W = W2 - делитель
CLRF W1 ;W1 = 0 - частное, как количество вычитаний делителя
;цикл вычитания делителя из делимого
;вычитание заменяется сложением с кодом в дополнительном коде
;т.е. 5-2 = 5+0feh = 3 и С=1
; 1-2 = 1+0feh = 0ffh и C=0
;т.о., C=1 означает, что отнимается, а С=0 - нет
M04 SUBWF W3,1 ;W3 = W3 - W
BTFSC STATUS,C ;проверяем бит переноса, если C = 0, то на выход
GOTO M05 ;на инкремент частного
ADDWF W3,0 ;добавим лишний раз отнятый делитель, результат в W
RETURN ;имеем в W1 частное, а W - остаток
M05 INCF W1,1 ;считаем отнятые делители
GOTO M04 ;продолжаем
;кодировка кода на иникатор
;на входе W = 0-9
;на выходе код
CODE_SEG
ADDWF PCL,1 ;переход на адрес следующей команы + содержимое W
RETLW b'00000011' ;0
RETLW b'10011111' ;1
RETLW b'00100101' ;2
RETLW b'00001101' ;3
RETLW b'10011001' ;4
RETLW b'01001001' ;5
RETLW b'01000001' ;6
RETLW b'00011111' ;7
RETLW b'00000001' ;8
RETLW b'00001001' ;9
; RETURN ;лишнее
;pause
PAUSE ;программная задержка - три вложенных цикла
MOVLW D'155'
MOVWF CNT_2
P00 MOVLW D'100'
MOVWF CNT_3
P01 MOVLW D'2'
MOVWF CNT_4
P02 DECFSZ CNT_4,1
GOTO P02
DECFSZ CNT_3,1
GOTO P01
DECFSZ CNT_2,1
GOTO P00
RETURN
END
LIST p=16F84
#include <p16f84.inc>
; Биты регистра PORTB
DAT EQU 04h ; бит данных
SYN EQU 05h ; бит синхронизации
CBLOCK 0CH ; блок рабочих регистров
X
WAIT
W1
W2
W3
CNT1
CNT2
W_TEMP
STATUS_TEMP
ENDC
org 00h ; начало исполняемого кода
GOTO START
org 04h ; программа обработки прерываний
MOVWF W_TEMP
MOVF STATUS,W
MOVWF STATUS_TEMP
CLRF TMR0 ;очистка таймера
BCF INTCON,T0IF ;сброс флага прерывания
COMF WAIT,F
MOVF STATUS_TEMP,W
SWAPF W_TEMP,F
SWAPF W_TEMP,W
retfie
; Основная программа
START
; Инициализация PORTB
MOVLW B'11001111' ; настройка порта В
BSF STATUS,RP0 ; выбор банка 1
MOVWF TRISB ; установка RB4, RB5 на вывод
MOVLW B'01110010'
MOVWF OPTION_REG
BCF STATUS,RP0 ; выбор банка 0
;
BSF PORTB,DAT ; установка битов DAT, SYN
BSF PORTB,SYN ; в регистр PORTB
CLRF X ;X = 0
CLRF WAIT ;WAIT = 0
CLRF TMR0
MOVLW B'10100000'
MOVWF INTCON
MAIN ;основной цикл
BTFSS WAIT,0
GOTO MAIN
CALL VYVOD ;рисуем X
COMF WAIT,F
INCF X,F
GOTO MAIN
VYVOD
MOVF X,W
MOVWF W1
MOVLW 4
MOVWF CNT1
DIGITS
MOVLW 10
CALL DIVIDE
CALL CODING
CALL OUT
DECFSZ CNT1,F ; по всем 4 цифрам
GOTO DIGITS
RETURN
;=============================================
; Преобразование BCD -> 7 сегментный код
; получаем в W сегменты индикатора
; 0 - горит
;=============================================
CODING
addwf PCL,F ; W + PC -> PC
retlw b'00000011' ; ABCDEF.. = '0'
retlw b'10011111' ; .BC..... = '1'
retlw b'00100101' ; AB.DE.G. = '2'
retlw b'00001101' ; ABCD..G. = '3'
retlw b'10011001' ; .BC..FG. = '4'
retlw b'01001001' ; A.CD.FG. = '5'
retlw b'01000001' ; A.CDEFG. = '6'
retlw b'00011111' ; ABC..... = '7'
retlw b'00000001' ; ABCDEFG. = '8'
retlw b'00001001' ; ABCD.FG. = '9'
; Подпрограмма вывода
OUT
MOVWF W2 ; сохраним в W2
MOVLW D'8' ; 8 бит
MOVWF CNT2 ; в счетчик CNT2
SEGMENTS
BCF PORTB,DAT ; установка в 0 RB4 (чтобы горело)
BTFSC W2,0 ; если 0 бит в регистре W2 = 0, то пропускаем
BSF PORTB,DAT ; команду, если нет, то установка RB4 в 1 (чтобы потухло)
; синхронизация PORTB
BCF PORTB,SYN
BSF PORTB,SYN
RRF W2,F ; сдвиг вправо, через перенос
DECFSZ CNT2,F ; по всем 8 битам
GOTO SEGMENTS ; переход на метку SEGMENTS
RETURN ; возврат из подпрограммы
DIVIDE
MOVWF W2 ; сохраним в W2
MOVF W1,W
MOVWF W3 ; сохраним в W3
MOVF W2,W
CLRF W1
SUBLOOP
SUBWF W3,F
BTFSC STATUS,C
GOTO DIVRET
INCF W1,F
GOTO SUBLOOP
DIVRET
ADDWF W3,W
RETURN
END
Если Вы уже зарегистрированы на Портале - войдите в систему, если Вы еще не регистрировались - пройдите простую процедуру регистрации.