- •Содержание
- •1.Принцип работы проектируемого устройства
- •2. Алгоритм работы вычислительного устройства
- •3. Описание принципиальной электрической схемы
- •4. Электрический расчет устройства
- •4.1. Расчет входных усилителей.
- •4.2 Расчет выходного усилителя
- •4.3 Расчет выходного усилителя мощности
- •4.4 Программируемый усилитель
- •4.5 Акустический генератор
- •5. Описание программы
- •6. Исходные коды программ
- •7. Результаты моделирования работы системы
- •8. Выводы
- •9. Список использованной литературы
6. Исходные коды программ
.PROGRAM Kurswork
#include G:\Softune\Mb90V590.h
.EXPORT _main
.SECTION DATA_MAIN, DATA, ALIGN=2
YH .RES.W 1 //целая часть y
YL .RES.W 1 //вещественна часть y
XH .RES.W 1 //целая часть x
XL .RES.W 1 //вещественна часть x
CorrCH .RES.W 1 // 2 старших бита коэффициента усиления
CorrCL .RES.W 1 // 8 младших бита коэффициента усиления
//коэффициенты
C1 .DATA.W H'60
C2 .DATA.W H'01
C3 .DATA.W -96
C4 .DATA.W -1
C5 .DATA.W H'00
C6 .DATA.W H'62
C7 .DATA.W 10
InpS .DATA.W 40
.SECTION CODE_MAIN, CODE, ALIGN=2
/*Процедура сложения 2 вещественных чисел*/
_ADD4:
//Input: RW1 - целая часть 1 RW0 - вещественная часть 1, RW3 - целая часть 2 RW2 - вещественная часть 2;
//Output: RW5 - целая часть 3 RW4 - вещественная часть 3
//Сохранение нужных регистров в стеке, в конце процедуры мы их восттановим
PUSHW A
MOVW A, RW6
PUSHW A
MOVW A, RW1
PUSHW A
MOVW A, RW0
PUSHW A
MOVW A, RW3
PUSHW A
MOVW A, RW2
PUSHW A
// Приводим число от 4-х байтового к 2 байтовому, для этого умножаем целую часть на 100 и складываем с вещественной
MOVW RW6, #100
MOVW A, RW1
MULW A, RW6
ADDW A, RW0
MOVW RW1, A
// Приводим аналогичную процедуру со 2 числом
MOVW RW6, #100
MOVW A, RW3
MULW A, RW6
ADDW A, RW2
// Складываем оба числа
ADDW A, RW1
// Проверяем, является ли сумма отрицательным числом
BN ADDBEFORENULL
// Если положительное, то разделяем сумму на целую и вещественную части, для этого делим сумму на 100,
// результат деления - целая часть, остаток - вещественная. Вещественную часть приводим к числу не большему 99.
//это проводим деля остаток на 100, результат складываем с целой частью, остато записываем в вещественную часть
MOVW RW6, #100
DIVU A, R4
MOVW RW5, A
MOVW RW4, RW6
MOVW A, RW4
MOVW RW6, #100
DIVU A, R4
MOVW RW4, RW6
MOVW RW6, A
MOVW A, RW5
ADDW A, RW6
MOVW RW5, A
JMP EndADD4
ADDBEFORENULL:
// Если отрицательное, то изменяем знак операнда, проводим процедуру, описанную выше, и меняем знак операнда ещё раз
NEGW A
MOVW RW6, #100
DIVU A, R4
MOVW RW5, A
MOVW RW4, RW6
MOVW A, RW4
MOVW RW6, #100
DIVU A, R4
MOVW RW4, RW6
MOVW RW6, A
MOVW A, RW5
ADDW A, RW6
MOVW RW5, A
MOVW A, RW4
NEGW A
MOVW RW4, A
MOVW A, RW5
NEGW A
MOVW RW5, A
EndADD4:
// Восстанавливаем регистры
POPW A
MOVW RW1, A
POPW A
MOVW RW0, A
POPW A
MOVW RW3, A
POPW A
MOVW RW2, A
POPW A
MOVW RW6, A
POPW A
RET
/*Процедура умножения 2 вещественных чисел*/
_MUL4:
//Input: RW1 - целая часть 1 RW0 - вещественная часть 1, RW3 - целая часть 2 RW2 - вещественная часть 2;
//Output: RW5 - целая часть 3 RW4 - вещественная часть 3 PUSHW A
//Сохранение нужных регистров в стеке, в конце процедуры мы их восттановим
PUSHW A
MOVW A, RW6
PUSHW A
MOVW A, RW1
PUSHW A
MOVW A, RW0
PUSHW A
MOVW A, RW3
PUSHW A
MOVW A, RW2
PUSHW A
MOVW A, RW7
PUSHW A
MOVW RW7, #0
MOV R2, #0
// Проверяем, является ли произведение чисел отрицательным, это возможно только в случае, если один из сомножителей отрицателен, а другой положителен
// Одновременно с этим проверяем, является ли каждое число отрицательным, если да, то меняем знак этого числа, чтобы работать только с положительными числами
// Флаг отрицательного числа лежит в RW7
MOVW A, RW0
ADDW A, RW1
BN MULNEXT3
JMP MULNEXT4
MULNEXT3:
MOV A, R2
INC A
MOV R2, A
MOVW A, RW0
NEGW A
MOVW RW0, A
MOVW A, RW1
NEGW A
MOVW RW1, A
MULNEXT4:
MOVW A, RW3
ADDW A, RW2
BN MULNEXT5
JMP MULNEXT6
MULNEXT5:
MOV A, R2
INC A
MOV R2, A
MOVW A, RW2
NEGW A
MOVW RW2, A
MOVW A, RW3
NEGW A
MOVW RW3, A
MULNEXT6:
MOV A, R2
CMP A, #1
BEQ CHANGESIGN0
JMP MULNEXT1
CHANGESIGN0:
MOVW RW7, #1
// Умножаем последовательно целую и целую части, целую и вещественную, вещественную и целую, вещественную и вещественную
MULNEXT1:
// Целая и целая
MOVW RW6, #0
MOVW A, RW1
MULW A, RW3
// После перемножения помещаем в RW5
MOVW RW5, A
// Целая и вещественная
MOVW A, RW1
MULW A, RW2
// После перемножения необходимо разделить целую и вещественную части, для этого делимна 100, результат складываем с RW5, а остаток с RW4
MOV R4, #100
DIVU A, R4
ADDW A, RW5
MOVW RW5, A
MOVW RW4, RW6
MOVW A, RW0
MULW A, RW3
// После перемножения необходимо разделить целую и вещественную части, для этого делимна 100, результат складываем с RW5, а остаток с RW4
MOV R4, #100
DIVU A, R4
ADDW A, RW5
MOVW RW5, A
MOVW A, RW6
ADDW A, RW4
MOVW RW4, A
// вещественная и вещественная, результат округляем путём деления на 100
MOVW A, RW0
MULW A, RW2
MOV R4, #100
DIVU A, R4
ADDW A, RW4
//Вещественную часть приводим к числу не большему 99.
//это проводим деля остаток на 100, результат складываем с целой частью, остато записываем в вещественную часть
MOVW RW4, A
MOV R4, #100
DIVU A, R4
CMP A, #0
BEQ MULNEXT0
ADDW A, RW5
MOVW RW5, A
MOVW RW4, #0
MOV R0, R4
MULNEXT0:
MOVW A, RW7
CMPW A, #0
BNE CHANGESIGN1
JMP MULNEXT2
// В случае если установлен знак отрицательного числа RW7, изменяем знак реззультата
CHANGESIGN1:
MOVW A, RW4
NEGW A
MOVW RW4, A
MOVW A, RW5
NEGW A
MOVW RW5, A
MULNEXT2:
// Восстанавливаем регистры
POPW A
MOVW RW7, A
POPW A
MOVW RW1, A
POPW A
MOVW RW0, A
POPW A
MOVW RW3, A
POPW A
MOVW RW2, A
POPW A
MOVW RW6, A
POPW A
RET
/*Процедура округления числа*/
Trunc:
// Input: RW1 RW0; Output: RW2
//Сохранение нужных регистров в стеке, в конце процедуры мы их восттановим
PUSHW A
MOVW A, RW6
PUSHW A
MOV R1, #0
// Проверяем, являются ли числа отрицательными, в случае этого изменяем знак и устанавливаем флаг R1
MOVW A, RW0
BN TruncCHANGESIGN0
MOVW A, RW1
BN TruncCHANGESIGN0
JMP TruncNext2
TruncCHANGESIGN0:
MOVW A, RW1
NEG A
MOVW RW1, A
MOVW A, RW0
NEG A
MOVW RW0, A
MOV R1, #1
// В случае если вещественная часть больше 50, то прибавляем к целой части 1, то есть округляем к ближайшему целому
TruncNext2:
MOVW A, RW0
CMP A, #51
BLO TruncNext0
MOVW A, RW1
INCW A
MOVW RW1, A
TruncNext0:
MOV R0, #0
MOVW A, RW4
CMPW A, #0
// Если установлен флаг R1, то делаем число обратно отрицательным
BNE TruncCHANGESIGN1
JMP EndTrunc
TruncCHANGESIGN1:
MOVW A, RW1
NEG A
MOVW RW1, A
EndTrunc:
// Масштабируем число в диапазон 0 - FF
MOVW A, RW1
ADDW A, #1020
MOVW RW2, RW1
MOVW RW3, #0
POPW A
MOVW RW6, A
POPW A
RET
/*Процедура сравнения двух чисел. Если одно из них отличается от другого более чем на С1%, то R7 = 1, иначе R7 = 0*/
Compare:
// Input RW1, RW0; Output R7
//Сохранение нужных регистров в стеке, в конце процедуры мы их восттановим
PUSHW A
MOVW A, RW0
PUSHW A
MOVW A, RW1
PUSHW A
MOVW A, RW3
PUSHW A
MOVW A, RW2
PUSHW A
MOVW A, RW0
PUSHW A
// Умножаем первое число на 0.C7, Где С7 - заданная погрешность. Меняем знак результата и отправляем его в стек.
MOV R7, #0
MOVW RW0, #0
MOVW RW3, #0
MOVW RW2, C7
CALL _MUL4
POPW A
MOVW RW3, A
MOVW A, RW5
NEG A
PUSHW A
MOVW A, RW4
NEG A
PUSHW A
// Вычитаем одно число из другого, если результат отрицательный, то меняем знак.
MOVW RW2, #0
MOVW A, RW1
NEG A
MOVW RW1, A
MOVW RW0, #0
CALL _ADD4
MOVW A, RW4
BN CompareChangesign
MOVW A, RW5
BN CompareChangesign
JMP CompareNext0
CompareChangesign:
MOVW A, RW4
NEG A
MOVW RW4, A
MOVW A, RW5
NEG A
MOVW RW5, A
// Вынимаем ранее полученное значение из стека и складываем с предыдущим результатом (разницей 2-х чисел), если результат положительный, то устанавливаем R7 = 1
CompareNext0:
MOVW RW0, RW4
MOVW RW1, RW5
POPW A
MOVW RW2, A
POPW A
MOVW RW3, A
CALL _ADD4
MOVW A, RW4
BP SETFLAG
MOVW A, RW5
BP SETFLAG
JMP CompareNext1
SETFLAG:
MOV R7, #1
CompareNext1:
// Восстановление из стека
POPW A
MOVW RW0, A
POPW A
MOVW RW1, A
POPW A
MOVW RW3, A
POPW A
MOVW RW2, A
POPW A
RET
/*Процедура сравнения трёх чисел, если одно из них отличакется больше чем на 10% то выставляется номер датчика на R7*/
CompareThree:
// Input RW0, RW1, RW2; Output R7
PUSHW A
MOVW A, RW0
PUSHW A
MOVW A, RW1
PUSHW A
MOVW A, RW2
PUSHW A
MOVW A, RW4
PUSHW A
MOVW A, RW5
PUSHW A
MOVW A, RW6
PUSHW A
// Сравнение 1 и 3, 1 и 2, если есть отличия больше 10% то R7 = 1
MOVW RW4, RW0
MOVW RW5, RW1
MOVW RW6, RW2
CALL Compare
MOV R6, R7
MOVW RW1, RW2
CALL Compare
MOV A, R6
ADD A, R7
CMP A, #2
BEQ WITHOUTFIRST
// Сравнение 2 и 1, 2 и 3, если есть отличия больше 10% то R7 = 2
MOVW RW0, RW5
MOVW RW1, RW4
CALL Compare
MOV R6, R7
MOVW RW1, RW6
CALL Compare
MOV A, R6
ADD A, R7
CMP A, #2
BEQ WITHOUTSECOND
// Сравнение 3 и 1, 3 и 2, если есть отличия больше 10% то R7 = 3
MOVW RW0, RW6
MOVW RW1, RW4
CALL Compare
MOV R6, R7
MOVW RW1, RW5
CALL Compare
MOV A, R6
ADD A, R7
CMP A, #2
BEQ WITHOUTTHIRD
MOV R7, #0
JMP EndCompareDouble
WITHOUTFIRST:
MOV R7, #1
JMP EndCompareDouble
WITHOUTSECOND:
MOV R7, #2
JMP EndCompareDouble
WITHOUTTHIRD:
MOV R7, #3
JMP EndCompareDouble
EndCompareDouble:
POPW A
MOVW RW6, A
POPW A
MOVW RW5, A
POPW A
MOVW RW4, A
POPW A
MOVW RW2, A
POPW A
MOVW RW1, A
POPW A
MOVW RW0, A
POPW A
RET
_main:
// Начальное значение Y = 0.00
MOVW YH, #H'00
MOVW YL, #H'00
// Начальное значение X = 0.00
MOVW XH, #H'00
MOVW XL, #H'00
//Настраиваем порты на вывод и инициализируем порты
MOV DDR8, #H'FF
MOVW PDR8, #0
MOV DDR7, #H'FF
MOVW PDR7, #0
MOV DDR4, #H'FF
MOVW PDR4, #H'FF
MOV DDR5, #H'FF
MOVW PDR5, #H'3
MOV DDR3, #H'FF
MOVW PDR3, #0
// Коэффициент усиления
MOVW CorrCH, #H'3
MOVW CorrCL, #H'FF
//Настраиваем АЦП
MOV ADCS0,#H'00
MOV ADCS1,#H'00
MOV ADCR1,#H'E8
MOVW A, #H'00
MOV ADER, #H'01
MLOOP0:
// 1 датчик считываем и масштабируем
MOV ADER, #H'01
SETB ADCS1:1
CLRB ADCS1:1
WBTC ADCS1:7
MOVW A, ADCR0
ADDW A, #255
MOVW RW0, A
// 2 датчик считываем и масштабируем
MOV ADER, #H'02
SETB ADCS1:1
CLRB ADCS1:1
WBTC ADCS1:7
MOVW A, ADCR0
ADDW A, #255
MOVW RW1, A
// 3 датчик считываем и масштабируем
MOV ADER, #H'03
SETB ADCS1:1
CLRB ADCS1:1
WBTC ADCS1:7
MOVW A, ADCR0
ADDW A, #255
MOVW RW2, A
// Выясняем, какой датчик битый и удаляем его из рассмотрения, находим среднее значение
CALL CompareThree
MOV A, R7
CMP A, #1
BEQ DELETEFIRST
CMP A, #2
BEQ DELETESECOND
CMP A, #3
BEQ DELETETHIRD
MOVW A, RW0
ADDW A, RW1
ADDW A, RW2
MOV R0, #3
DIVU A, R0
JMP MNEXT0
DELETEFIRST:
MOVW A, RW1
ADDW A, RW2
MOV R0, #2
DIVU A, R0
JMP MNEXT0
DELETESECOND:
MOVW A, RW0
ADDW A, RW2
MOV R0, #2
DIVU A, R0
JMP MNEXT0
DELETETHIRD:
MOVW A, RW0
ADDW A, RW1
MOV R0, #2
DIVU A, R0
MNEXT0:
// Вычисление разностного уравнения
// 1 произведение
PUSHW A
MOVW A, #0
PUSHW A
MOVW RW0, A
MOVW RW1, #0
MOVW RW3, C2
MOVW RW2, C1
CALL _MUL4
//Сохранение результата
MOVW RW7, RW5
MOVW RW6, RW4
// 2 произведение
MOVW RW0, XL
MOVW RW1, XH
MOVW RW3, C4
MOVW RW2, C3
CALL _MUL4
//1 сложение
MOVW RW0, RW5
MOVW RW1, RW4
MOVW RW3, RW6
MOVW RW4, RW7
CALL _ADD4
MOVW RW7, RW5
MOVW RW6, RW4
// 3 умножение
MOVW RW0, YL
MOVW RW1, YH
MOVW RW3, C6
MOVW RW2, C5
CALL _MUL4
//2 сложение
MOVW RW0, RW5
MOVW RW1, RW4
MOVW RW3, RW6
MOVW RW4, RW7
CALL _ADD4
// Запись в Y и X
MOVW YL, RW4
MOVW YH, RW5
POPW A
MOVW XL, A
POPW A
MOVW XH, A
// Округление и вывод на ЦАП
MOVW RW0, RW4
MOVW RW1, RW5
CALL Trunc
MOVW A, RW2
MOVW PDR8, A
SWAP
MOVW PDR7, A
SWAP
// Сравнение ожидаемого результата с результатом на ЦАПе
MOVW A, RW0
MOV ADER, #H'00
SETB ADCS1:1
CLRB ADCS1:1
WBTC ADCS1:7
MOVW RW1, ADCR0
CALL Compare
MOV A, R7
BP Correct
JMP MNEXT1
// Коррекция коэффициента усиления. Проходим коэффициенты от 1 до 1024, если в результате разницу между сигналами
// не удалось снизить до приемлимого уровня, подаём 1 на PDR3 - включаем акустику.
Correct:
MOVW CorrCH, #H'3
MOVW CorrCL, #H'FF
MOVW RW2, #100
MOVW A, CorrCH
MULW A, RW2
ADDW A, CorrCL
MOVW RW2, A
MOVW RW4 R, #100
MLOOP2:
SETB ADCS1:1
CLRB ADCS1:1
WBTC ADCS1:7
MOVW RW1, ADCR0
CALL Compare
MOV A, R7
CMP A, 0
BEQ MNEXT1
MOVW A, RW2
DIVU A, R0
MOVW CorrCH, A
MOVW PDR5, CorrCH
MOVW CorrCL, RW4
MOVW PDR4, CorrCL
DWBNZ RW2, MLOOP2
MOVW PDR3, #1
MNEXT1:
// Задержка сигнала
MOVW RW0, #1000
MLOOP1:
NOP
DWBNZ RW0, MLOOP1
JMP MLOOP0
NOP
.END
