; Макрокоманда восстановления контекстных регистров.
pop macro
swapf
StatBuffer, w
; Восстановить STATUS.
movwf
STATUS
swapf
WBuffer, w
; Восстановить регистр W.
endm
org 0
goto
Start
; Переход к началу программы.
Обработка нажатия клавиш.
ServKey
; Обнуляем флаг.
movf
NewKey, w
sublw
; NewKey > 3?
btfss
STATUS, С
; Если нет, пропускаем команду.
return
; иначе игнорируем нажатие.
raovf
NewKey, w
movwf
DisplayCh
; Переключаем канал.
movlw
ADTABLE
; Получаем адрес вершины таблицы АЦП.
addwf
DisplayCh,w
; Прибавляем смещение.
movwf
; Загружаем косвенный адрес (FSR).
movf
; Считываем код АЦП
movwf
L byte
; и помещаем в L byte.
clrf
H byte
call
B2 BCD
movf
R2,W
; Получаем младшие цифры.
movwf
LsdTime
; Сохраняем в LsdTime.
movf
R1,W
; Получаем младшие цифры.
movwf
HsdTime
; Сохраняем в Msd.
return
org 4
Первичная обработка прерывания.
Рекомендуется сохранить регистр W и регистр состояния на время прерывания.
Эта подпрограмма загружает результат преобразования (ADRES) в ячейку, определенную номером желаемого входа. Если он нулевой, ADRES поступает в ADTABLE,а если равен 1, ACRES поступает в ADTABLE+1 и т.д.
ServiceAD
Start
Loop
push
call
Servicelnterrupts
retfie
call
InitPorts
call
InitAd
call
InitTimers
btfsc
ServKey
Проверяем флаг ServKey.
call
ServiceKey ;
Если установлен, вызываем подпрограмму обработки.
btfsc
ADOver ;
Проверка флага ADOver.
call
ServiceAD ;
Если установлен, то переходим к обработке.
goto
loop
movf
ADCONO,w
movwf
TempC
Сохраняем во временном регистре.
movlw
B-00001000
Выбираем следующий канал.
addwf
ADCONO,w
btfsc
ADC0N0,5
Если <= ch3, то пропускаем.
movlw
B11000001
Выбираем chO.
movwf
ADCONO
Записать адрес в таблицу.
movlw
ADTABLE
movwf
FSR ; Загрузить в регистр косвенного адреса адрес вершины
TempC
TempC
TempC,w
andlw
Маскируем все биты, кроме двух младших.
addwf
Прибавляем смещение.
movf
ADRES,w
Считываем результат АЦП
movwf
и помещаем в таблицу по косвенному адресу.
ADOver
; Обнуляем флаг АЦП.
call
SampleAd
Сканируем АЦП каждые 20 мс.
call
LoadAD
; Загружаем результат в регистр дисплея.
call
UpdateDisplay
Обновляем дисплей.
return
return
InitPorts
STATUS, RPO
; Выбираем банк 1 ОЗУ.
; Сканируем клавиатуру 4x4 и.
если нажата клавиша, переден ее номер в NewKey.
movlw
; Задаем RAO - RA3 как цифровые порты.
; Если нет, указатель keyhit обнуляем. Подпрограмма осуществляет также
movwf
ADC0N1
; защиту от дребезга контактов . Клавиатура сканируется каждые 20 мс.
clrf
TRISA
; Определяем RAO - RA4 как выходы.
clrf
TRISB
; Определяем RBO - RB7 как выходы.
ScanKeys
STATUS,RPO
; Выбираем банк 0.
btfss
DebnceOn
Бит DebnceOn равен 1?
clrf
PORTA
; Обнуляем все выходы.
goto
Scanl
Если нет, сканируем клавиатуру.
clrf
PORTJ
decfsz
Debnce
в противном случае продолжаем счет.
P0RT A.3
; Разрешить отображение старшей цифры.
return
return
return
DebnceOn
По окончании сбрасываем флажок. Возвращаемся.
; При тактировании частотой 4,096 МГц внутренняя частота микроконтроллера
Scanl
; составляет 1,024 МГц, что при делении на 32 обеспечивает инкрементирование
call
SavePorts
Сохраняем значения портов.
; таймера (RTCC) каждые 31,25 мкс.
rncvlw
BlllOllir
Инициируем TempD.
; Переполнение таймера (при значении 96) будет происходить каждые 5 мс.
movwf
TenpD
; прерывания будут генерироваться с той же периодичностью.
ScanNext
movf
PORT B,w
Считываем порт для инициализации.
InitTimers
INTCON, RBIF
Сбрасываем флаг прерывания по изменению порта
clrf
MsdTime
; Сброс регистров таймера.
TempD
Сдвигаем вправо.
clrf
LsdTime
btfss
STATUS,С
Перенос равен 1?
clrf
DisplayCh
; Отобразить результат измерения канала 0.
goto
NoKey
Если нет, заканчиваем.
clrf
Flag
; Обнулить все флажки.
movf
TempD,w
иначе выдаем на порт В.
STATUS, RPO
; Банк 1.
iTiovwf
PORT B
movlw
ВЮОООЮО-
; Определяем коэффициент предделителя.
movwf
OptionReg
; Коэффициент равен 32.
btfss
INTCON,RBIF
Проверяем флаг прерывания RBIF
STATUS,RPO
; Банк 0.
goto
ScanNext
Если не установлен, продолжаем.
movlw
В00100000
; Разрешаем прерывание по переполнению таймера.
btfsc
keyhit
Клавиша нажата?
raovwf
INTCON
goto
SKreturn
Если нет, выходим.
movlw
; Загружаем начальное значение таймера (rtcc)
keyhit
Устанавливаем флаг нажатия клавиши.
movwf
RTCC
; и запускаем его.
swapf
PORT B,w
Считываем порт В.
retfie
movwf
TempE
Сохраняем в TempE.
Servicelnterrupts
call
GetKeyValue
Получить значение клавиши (0 - F).
btfsc
INTCON, RTIF
; Проверяем флаг прерывания по таймеру.
movwf
NewKey
Сохранить в NewKey.
goto
ServiceRTCC
; Если флаг равен 1, то обслуживаем,
ServKey
Установить флаг обслуживания.
clrf
INTCON
; иначе запрещаем все прерывания.
DebnceOn
Установить антидребезговый флаг.
INTCON,RTIE
; Разрешаем прерывание по таймеру.
nravlw
return
movwf
Debnce
Задаем время ожидания установления колебаний.
ServiceRTCC
SKreturn
movlw
; Устанавливаем исходное состояние таймера.
call
RestorePorts
Восстанавливаем порты.
movwf
RTCC
return
INTCON,RTIF
; Сбрасываем флаг прерывания таймера.
NoKey
btfsc
PORT A,0
keyhit
Сбрасываем флаг.
call
ScanKeys
; Сканируем клавиши каждые 20 мс.
goto
SKreturn
btfsc
P0RT A,3
<
; Нумерация клавиш.
СТОЛБЦЬ
1 2
3 4
(RB3) (RB2)
(RBI) (RBO)
; СТРОКИ
; 1(RB4)
0 1
2 3
; 2(RB5)
4 5
6 7
3(RB6)
8 9
A В
; 4(RB7)
С О
E F
GetKeyValue
clrf
TempC
btfss
TempD,3
; Первый столбец.
goto
RowValEnd
incf
TempC
btfss
TempD,2
; Второй столбец.
goto
RowValEnd
incf
TempC
btfss
TempD, 1
; Третий столбец.
goto
RowValEnd
incf
TempC
; Последний столбец.
RowValEnd
btfss
TempE, 0
; Верхняя строка?
goto
GetValCom
; Если да, получаем 0,1,2 и 3.
btfss
TempE, 1
; Вторая строка?
goto
Get4567
; Если да. получаем 4,5,6 и 7.
btfss
TempE, 2
; Третий ряд?
goto
Get69ab
; Если да. получаем 8,9,а и Ь.
Getcdef
TempC,2
; Устанавливаем младшие (msb) биты.
Get89ab
TempC, 3
goto
GetValCom
; Выполняем общую часть.
Get4567
TempC,2
GetValCom
movf
TempC,w
addwf
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw 7
retlw 8
retlw 9
retlw Oa
retlw Ob
retlw Oc
retlw Od
retlw Oe
retlw Of
Сохранение состояния портов A и В во время сканирования клавиатуры.