Смекни!
smekni.com

Микропроцессорная система управления предназначенная для использования на лесопильном заводе (стр. 5 из 6)

Подпрограмма B2D переводит целое двоичное число в регистре C (0..FFH) в 2-10 код, расположенный в регистровой паре HL. Перевод производится в соответствии с формулой:

HL=(…((c7)×2+c6)×2+…+c1)×2+c0,

в которой ci – разряды числа в регистре C, а удвоение и сложение с битами ci происходит по правилам десятичной арифметики (с командой DAA после операции).

Листинг 14: подпрограмма B2D

; – – – перевод байта (целого) в 2-10 код

; операнд C – переводимое число, результат в HL

; сохраняет DE

B2D LD B, 8 ;

B2D1 SLA C ; CY¬C (получаем последний бит операнда)

LD A, L ; удвоение HL с учетом переноса CY

ADC L ; по правилам десятичной арифметики

DAA ;

LD L, A ;

LD A, H ;

ADC H ;

DAA ;

LD H, A ;

DJNZ B2D1 ; конеццикла

RET ;

Подпрограмма B2D_F переводит дробное число в формате 0.L в 2-10 код из трех тетрад в формате 0.ABC (учитываются три цифры после запятой). Регистры A, B, C содержат в конце каждый по одной десятичной цифре. Перевод происходит так. Число 0.L умножается на 10, результат в паре H.L. Его целая часть (H) и будет первой цифрой A результата. Затем H обнуляется, полученная дробь 0.L снова умножается на 10 и т.д.

Для быстрого умножения на 10 сделана отдельная подпрограмма MUL10, умножающая пару HL (где H=0) и получающая результат в той же HL. Она использует равенство:

10×HL=2×HL+8×HL, а умножения на 2 и на 8 делаются с помощью команды ADD HL, HL.

Листинг 15: подпрограммы B2D_F и MUL10

; – – – перевод байта (дробного) в 2-10 код

; операнд C – число с фиксированной перед старшим разрядом точкой, результат в ABC

; изменяются все регистры

B2D_F LD H, 0 ;

CALL MUL10 ; получить в H первую цифру

LD A, H ; скопировать ее в A

LD H, 0 ; иобнулить H

CALL MUL10 ;

LD B, H ; вторую цифру – в регистр B

LD H, 0 ;

CALL MUL10 ; третью – в C

LD C, H ;

RET

; – – – умножение на 10

; операнд в HL (имеет значение только L) и результат в HL

; сохраняет A, BC

MUL10 ADD HL, HL ; HL×10=HL×2+HL×8

LD D, H ;

LD E, L ;

ADD HL, HL ;

ADD HL, HL ;

ADD HL, DE ;

RET ;

Преобразование двоичный®семисегментный код

Это преобразование с помощью таблицы перекодировки уже встречалось в тестовой программе ОЗУ. Сейчас оформим ее как отдельную подпрограмму (в тесте ОЗУ нельзя вызывать подпрограммы, т.к. команда вызова CALL использует стек). Операнд подпрограммы – двоично-десятичная цифра в регистре A (0..9, старшая тетрада нулевая).

Листинг 16: подпрограмма D27

; – – – перевод байта в семисегментный код

; операнд (0..9) и результат в A

; сохраняет BC, DE

D27 LDH, #07 ;

LD L, A ;

LD A, (HL) ;

RET ;


Обработчики прерываний

Всего их шесть – по числу прерываний. Обработчик обязательно должен сохранить в стеке все изменяемые им регистры и в конце восстановить их. Выход из обработчика выполняется не стандартным RET, а командой RETI.

Обработчик IRQ0 (начало измерений)

Функция обработчика – обнулить таймеры T1 и T2, а также специальную ячейку памяти D_NUM (2 байта). Эта ячейка инкрементируется всякий раз после чтения напряжения Ud с датчика диаметра. По приходу запроса IRQ0, когда приходит новое бревно, она должна быть обнулена.

Листинг 17: обработчик запроса IRQ0

; – – – обнулитьT1, T2, D_NUM

IR0_H PUSH BC ;

PUSH AF ;

LD BC, 0 ;

LD (T1), BC ; обнулить T1

LD (T2), BC ; обнулить T2

LD (D_NUM), BC ; обнулить D_NUM

POP AF ;

POP BC ;

RETI ;

Обработчик IRQ2 (информация с АЦП готова)

Функция обработчика – если бревно сейчас под пластиной датчика (можно судить, прочтя порт фотоэлементов с адресом 0B), считать два байта напряжения из портов 00 (младший) и 01 (старший). Записать их в массив напряжений, под который отведена область памяти начиная с адреса 0100Н до конца ОЗУ (всего 2К). Перед записью проверить, не заполнен ли этот массив. Инкрементировать ячейку D_NUM, содержащую число элементов этого массива.

Листинг 18: обработчик запроса IRQ2

; – – – считать и обработать байт с АЦП

IR2_H PUSH BC ;

PUSH HL ;

PUSH AF ;

IN A, (#0B) ;

AND #02 ; наложить маску 000000010

JR Z, IR2_H1 ; если второй бит нулевой, то выход

LD HL, #1000 ; рассчитать адрес очередного элемента массива

LD C, (D_NUM) ; считать D_NUM

LDB, (D_NUM+1) ;

SLA C ; умножить его на 2

RL B ;

ADD HL, BC ; теперь адрес в HL

LDA, H ;

CP #18 ;

JR NC, IR2_H1 ; если вышли за пределы массива, то выход

IN A, (#00) ; считать первый байт с АЦП

LD (HL), A ; и отправить его в память

INC HL ;

IN A, (#01) ; считать второй

LD (HL), A ; отправить

INC BC ; увеличить переменную D_NUM на единицу

LD (D_NUM), BC ;

IR2_H1 POP AF ;

POP HL ;

POPBC ;

RETI ;

Обработчик IRQ3 (от генератора 16 Гц)

Функция обработчика – произвести инкремент часов реального времени и условный инкремент таймеров. Часы реального времени – это 4 байта в памяти:

TIME 1/16 секунды (0..15);

TIME+1 секунды (0..59);

TIME+2 минуты (0..59);

TIME+3 часы (0..23);

Все величины хранятся в двоичном формате.

Таймерам T1 и T2 отведено по 2 байта с начальными адресами T1 и T2. Условия, при которых они инкрементируются, были приведены в п. 3.4.

Листинг 19: обработчик запроса IRQ3

; – – – инкремент часов реального времени и условный инкремент таймеров

IR3_H PUSH BC ;

PUSH HL ;

PUSHAF ;

; часы реального времени

LD HL, TIME ;

INC (HL) ; инкремент 1/16 секунд

LDA, (HL) ;

CP 16 ; проверить на достижение максимума JR C, IR3_H1 ; условный выход из подпрограммы

LD (HL), 0 ; иначе обнулить 1/16 секунды и продолжить

INC HL ;

LD B, 2 ; инкремент секунд и минут делается в цикле

IR3_H2 INC (HL) ;

LD A, (HL) ;

CP 60 ;

JR C, IR3_H1 ;

LD (HL), 0 ;

INC HL ;

DJNZ IR3_H2 ; конеццикла

INC (HL) ; инкрементчасов

LD A, (HL) ;

CP 24 ;

JRC, IR3_H1 ;

XOR A ; если счетчик часов=24

LD (HL), A ; то обнулить все 4 байта часов реального времени

DEC HL ;

LD (HL), A ;

DEC HL ;

LD (HL), A ;

DEC HL ;

LD (HL), A ;

; таймеры

IR3_H1 IN A, (#0B) ; загрузить слово статуса фотоэлементов

AND 1 ;

JR Z, IR3_H3 ; если не установлен 1-й бит, то выход

LD HL, T2 ; иначе инкремент Т2

INC (HL) ;

JR NZ, IR3_H4 ; если инкремент не обнулил

; первый байт Т2, то идем дальше

INC HL ; иначе увеличить на 1 и второй байт

INC (HL) ;

IR3_H4 IN A, (#0B) ;

AND 2 ; проверить 2-й бит статуса ФЭЛ

JR Z, IR3_H3 ; если он не установлен, то выход

LD HL, T1 ; иначе инкремент Т1

INC (HL) ;

JR NZ, IR3_H3 ;

INC HL ;

INC (HL) ;

IR3_H3 POP AF ;

POP HL ;

POP BC ;

RETI ;

Обработчик IRQ4 (от кнопки “+Час”)

Функция обработчика – увеличить на единицу часы реального времени (ячейка TIME+3).

Листинг 20: обработчик запроса IRQ4

; – – – инкремент часов

IR4_H PUSH HL ;

PUSH AF ;

LD HL, TIME+3;

INC (HL) ; инкрементчасов

LD A, (HL) ;

CP 24 ;

JRC, IR4_H1 ;

XOR A ; если счетчик часов=24

LD (HL), A ; то обнулить часы и минуты

DEC HL ;

LD (HL), A ;

IR4_H1 POP AF ;

POP HL ;

RETI

Обработчик IRQ5 (от кнопки “+Мин”)

Функция обработчика – увеличить на единицу минуты реального времени (ячейка TIME+2).

Листинг 21: обработчик запроса IRQ5

; – – – инкремент минут

IR5_H PUSH HL ;

PUSH AF ;

LD HL, TIME+2;

INC (HL) ; инкрементминут

LD A, (HL) ;

CP 60 ;

JRC, IR5_H1 ;

XOR A ; если счетчик минут=60

LD (HL), A ; то обнуление минут

INC HL ; и инкремент часов

INC (HL) ;

LD A, (HL) ; с проверкой часов на 24

CP 24 ;

JRC, IR5_H1 ;

XOR A ; если счетчик часов=24

LD (HL), A ; то обнулить и часы

IR4_H1 POP AF ;

POP HL ;

RETI

Обработчик IRQ1 (от фотоэлемента Фэл2)

Обработчик IRQ1 выполняет самую важную функцию. Его задача – вычислить объем бревна. Последовательность следующая: вычисляем диаметр бревна, длину, вычисляем объем Vi, находим объем VS.

Для вычисления диаметра все значения, прежде считанные в массив напряжений с АЦП, усредняются: суммируются и делятся на количество (D_NUM). При суммировании может произойти переполнение суммы (а она двухбайтная), чтобы этого не было, массив разбивается на группы по 16 измерений в каждой. Если осталась остаточная группа с числом меньше 16, то она отбрасывается. В каждой из них подсчитывается среднее, затем рассчитывается искомое как среднее средних.

Из среднего напряжения находится угол

a=

.

Затем находим диаметр d=0,625 – 0,5cos a=00,A0H – 00,80Hcos a. Занести его в ячейку DIAM (2 байта в памяти). Сравнить диаметр с допустимыми пределами [0,2..0,5]=[0,33H..0,8H]. Если он выходит за эти пределы, то выдать на отбраковку (порт 02H) единицу.

Объем Vi находится как Vi=(p/4)d2×T1/T2=0,C9H×d2×T1/T2.

Листинг 22: обработчик запроса IRQ1

; – – – найти объем бревна и суммарный объем

; усреднение всех напряжений с датчика диаметра в массиве по адресу 1000H

IR1_H PUSH AF ;

PUSH BC ;

PUSH DE ;

PUSH HL ;

LD L, (D_NUM) ;

LD H, (D_NUM+1) ;

LD B, 4 ; делим D_NUM на 16

IR1_H1 SRL H ;

RR L ;

DJNZIR1_H1 ;

LD C, L ; в результате C=число групп по 16

PUSH BC ; сохранить С в стеке

LD HL, #1000 ;

LD DE, 0 ; DE – начальная сумма групп

PUSH DE ; отправить ее в стек, C станет второй в стеке

PUSH DE ; DE – начальная сумма отдельной группы,

; отправить®в стек, сумма групп вторая в стеке

; C – третья в стеке

IR1_H4 LDB, 16 ;

IR1_H2 LD E, (HL) ; читаем в DE элемент массива

INC HL ;

LD D, (HL) ;

INC HL ;

EX (SP), HL ; текущую сумма в HL, текущий адрес в стеке

ADDHL, DE ;

EX (SP), HL ; новая сумма в стеке, текущий адрес в HL

DJNZIR1_H2 ;

; в итоге сумма одной группы по 16 – в стеке

; начальный адрес следующей группы – в HL

POP DE ;

LD B, 4 ; находим среднее одной группы,

IR1_H3 SRL D ; деля сумму в DE на 16

RR E ;

DJNZ IR1_H3 ;

POP HL ; берем из стека сумму групп

ADDHL, DE ;

PUSH HL ; снова отправляем в стек: сначала сумму групп

PUSH DE ; затем сумму одной группы

DEC C ; С – счетчик групп

JR NZ, IR1_H4 ; следующая группа…

POP HL ;

POP HL ; извлечь найденную сумму групп

POP BC ; извлечь счетчик групп C

LD D, C ; DE=C.0

LD E, 0 ;

CALL DIV ; делим сумму групп на число групп

; теперь HL=Ud=среднее всего массива напряжений датчика

; следующий шаг – нахождение угла a, cos a, d

LDD, 4 ; DE=491H

LD E, #91 ;

LD B, H ; сохранить Ud в BC