Московский государственный институт электроники и математики
Кафедра информационно-коммуникационных технологий
Курсовая работа
«Двухбайтовый десятичный калькулятор»
по курсу «Микропроцессорные системы»
Выполнил:
Группа С-85
Проверил:
Москва 2011
Аннотация
В данной работе разрабатывается двухбайтовый десятичный калькулятор на базе микроконтроллера 51 семейства. Работа выполняется на прототипе.
Оглавление
Техническое задание. 4
Анализ технического задания. 5
Алгоритмы.. 6
Служебная информация. 6
Алгоритм основной программы.. 6
Обработчик прерывания по таймеру. 7
Обработчик прерывания от COM-порта. 8
Опрос матричной клавиатуры.. 8
Подсчёт операнда. 9
Вычисление. 9
Вывод результата. 10
Печать результата на экране. 10
Исходный код. 11
Список использованной литературы.. 28
Техническое задание
Написать программу для тестового стенда на базе микроконтроллера Intel 8051, позволяющую выполнять сложение, вычитание, умножение и деление положительных целых чисел. Дополнительные условия:
1. Числа вводятся с матричной клавиатуры в десятичной форме.
2. Операции вводятся с клавиатуры компьютера кнопками «+», «-», «*», «/», «=».
3. Результат выводится в десятичной форме в виде числа до четырёх знаков длиной.
Анализ технического задания
Результат вычислений – десятичное число до четырёх знаков длиной. Это означает, что для хранения данного числа требуется два байта памяти. То же самое касается вводимых данных: предполагается, что пользователь может ввести числа до четырёх знаков длиной.
Так как процессор используемого прототипа восьмибитный, то для вычисления в шестнадцати битах невозможно использовать стандартные операции сложения, вычитания, умножения и деления, и эти операции должны быть переопределены.
Программе потребуется банк регистров R0-R7 для хранения операндов, промежуточных вычислений и результата операции.
Также необходимы ячейки с побитовой адресацией для хранения служебных битов.
Приём символов от матричной клавиатуры производится с помощью прерываний по таймеру и анализа нажатой клавиши. Приём символов от компьютерной клавиатуры реализован с использованием прерываний от COM-порта.
Вывод результата на экран терминала производится посредством COM-порта.
Алгоритмы
Служебная информация
Для хранения служебной информации в течение всего цикла работы программы выделены два байта памяти с побитовой адресацией.
20h:
0-3 биты – длина вводимого числа.
4 бит – какое число вводится в данный момент (0 – первое, 1 – второе).
5, 6 биты – знак операции (00 – «+», 01 – «-», 10 – «*», 11 – «/»).
7 бит – индикатор, что клавиша нажата и держится. Используется для устранения проблемы дребезга контактов.
21h:
0 бит – этапы операции деления (см. соответствующий раздел).
1 бит – ошибка переполнения.
2 бит – получено отрицательное число.
3 бит – попытка деления на ноль.
Алгоритм основной программы

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

Обработчик прерывания от COM-порта

Опрос матричной клавиатуры
Для ввода цифр используется стандартная шестнадцатикнопочная матричная клавиатура. Чтобы определить, какая клавиша нажата в данный момент, в регистре P1 устанавливаются различные значения для линий P1.4 – P1.7. На проверяемой линии выставляется «0», на остальных – «1». После чего производится проверка на «0» на линиях P1.0 – P1.3. При обнаружении «0» на пересечении линий вызывается обработчик для соответствующей цифры.

Подсчёт операнда
В зависимости от количества введённых знаков вызывается одна из четырёх функций, вычисляющих значение операнда. Расчёт производится путём умножения каждой введённой цифры на 10n, где n – номер разряда, который представляет данная цифра. После попарного умножения полученные значения складываются.
В зависимости от номера операнда полученное значение записывается в соответствующие ему регистры.
Вычисление
В зависимости от вида операции вызывается одна из четырёх функций подсчёта результата: сложение, вычитание, умножение, деление. Так как операнды представляют собой двухбайтовые числа, операции по вычислению были переопределены.
При сложении младшие и старшие байты операндов попарно складываются. Если при сложении младших байтов происходит переполнение, бит переполнения добавляется к сумме старших байтов. Если при сложении старших байтов происходит переполнение, на экран выводится ошибка переполнения.
При вычитании младшие и старшие байты операндов попарно вычитаются. Если при вычитании младших байтов получилось отрицательное число, то бит переноса вычитается из разности старших байтов. Если при вычитании старших байтов получилось отрицательное число, то оно записывается как результат, и устанавливается флаг отрицательного числа в служебном бите.
При умножении производится попарное умножение старших и младших байтов операндов. Если оба старших байта не равны нулю, то выводится ошибка переполнения. Результат перемножения младших байтов записывается в младший байт результата, переполнение – в старший байт. Сумма произведений старших байтов с младшими записывается в старший байт результата. При переполнении старшего байта выводится ошибка переполнения.
Деление производится в области памяти с возможностью побитовых операций. Сначала производится проверка второго операнда на ноль. Если делитель равен нулю, то выводится ошибка. Деление состоит из двух фаз. В первой фазе второй операнд сдвигается влево до тех пор, пока он не станет больше первого операнда, после чего производится обратный сдвиг вправо на один бит. После каждого сдвига в регистры R записывается множитель делителя (фактически, число 2n, где n – количество сдвигов делителя). Вторая фаза заключается в том, что из первого операнда вычитается второй, и к результату прибавляется значение регистров R. После чего второй операнд сдвигается вправо, и снова производится попытка вычитания. Вторая фаза повторяется до тех пор, пока второй операнд в своём первоначальном виде не станет больше первого операнда. В регистре с результатом будет записан конечный результат деления.
Вывод результата
Результат вычислений записан в двух байтах в двоичном виде. Для того чтобы вывести его на экран в десятичном виде необходимо последовательно вывести на экран результаты целочисленного деления результата на 10n, где n – номер разряда выводимого числа. Так как результат может занимать два байта, и представлять собой число из четырёх разрядов, что требует деления на 1000, при выводе на экран применяется алгоритм деления, описанный выше.
Печать результата на экране
При успешном завершении вычислений на экран выводится число – результат вычислений. При возникновении ошибки переполнения на экран выводится «OVERFLOW». При возникновении ошибки деления на ноль на экран выводится «DIVISION BY ZERO».
Исходный код
ASEM-51 V1.3
Copyright (c) 2002 by W. W. Heinz
MCS-51 Family Macro Assembler A S E M - 5 1 V 1.3
=====================================================
Source File: calculator_final_win. s03
Object File: calculator_final_win. hex
List File: calculator_final_win. lst
Line I Addr Code Source
1: N 8000 org 8000h
2: ; основная функция
3: 8AD jmp main
4:
5: N 8003 org 8003h
6: 8reti
7:
8: N 800B org 800Bh
9: ; обработка матричной клавиатуры
10: 800BA7 call delay
11: 800Ecall mx_keyboard
12: 8reti
13:
14: N 8023 org 8023h
15: ; обработка прерываний с клавиатуры
16: 8C5 call read
17: 8reti
18:
19: 8027 mx_keyboard:
20: ; верхние клавиши
21: 8DF mov P1, #b
22: 802Ajnb P1.1, a1
23: 802DB jnb P1.0, a2
24: 8jnb P1.3, a3
25: ; средние клавиши
26: 8EF mov P1, #b
27: 8jnb P1.1, a4
28: 8D jnb P1.0, a5
29: 803Cjnb P1.3, a6
30: ; нижние клавиши
31: 803FF mov P1, #b
32: 8jnb P1.1, a7
33: 8F jnb P1.0, a8
34: 8jnb P1.3, a9
35: ; самые нижние клавиши
36: 804BBF mov P1, #b
37: 804Ejnb P1.1, a0
38: 8jnb P1.0, aclear
39: ; клавиша отжата
40: 8054 C2 07 clr 20h.7
41:
42: 8056 mx_keyb_ret:
43: 8ret
44:
45: ; запись цифр
46: 8057 a0:
47: ; если клавиша нажата и держится
48: 8FC jb 20h.7, mx_keyb_ret
49: 805Amov A, #0
50: 805CF2 call digits_write
51: 805F 80 F5 jmp mx_keyb_ret
52:
53: 8061 a1:
54: 8F2 jb 20h.7, mx_keyb_ret
55: 8mov A, #1
56: 8F2 call digits_write
57: 8EB jmp mx_keyb_ret
58:
59: 806B a2:
60: 806BE8 jb 20h.7, mx_keyb_ret
61: 806Emov A, #2
62: 8F2 call digits_write
63: 8E1 jmp mx_keyb_ret
64:
65: 8075 a3:
66: 8DE jb 20h.7, mx_keyb_ret
67: 8mov A, #3
68: 807AF2 call digits_write
69: 807D 80 D7 jmp mx_keyb_ret
70:
71: 807F a4:
72: 807FD4 jb 20h.7, mx_keyb_ret
73: 8mov A, #4
74: 8F2 call digits_write
75: 8CD jmp mx_keyb_ret
76:
77: 8089 a5:
78: 8CA jb 20h.7, mx_keyb_ret
79: 808Cmov A, #5
80: 808EF2 call digits_write
81: 8C3 jmp mx_keyb_ret
82:
83: 8093 a6:
84: 8C0 jb 20h.7, mx_keyb_ret
85: 8mov A, #6
86: 8F2 call digits_write
87: 809B 80 B9 jmp mx_keyb_ret
88:
89: 809D a7:
90: 809DB6 jb 20h.7, mx_keyb_ret
91: 80A0mov A, #7
92: 80A2F2 call digits_write
93: 80A5 80 AF jmp mx_keyb_ret
94:
95: 80A7 a8:
96: 80A7AC jb 20h.7, mx_keyb_ret
97: 80AAmov A, #8
98: 80ACF2 call digits_write
99: 80AF 80 A5 jmp mx_keyb_ret
100:
101: 80B1 a9:
102: 80B1A2 jb 20h.7, mx_keyb_ret
103: 80B4mov A, #9
104: 80B6F2 call digits_write
105: 80B9 80 9B jmp mx_keyb_ret
106:
107: ; сброс
108: 80BB aclear:
109: 80BBmov 20h, #b
110: 80BE 74 0A mov A, #0Ah
111: 80C0call out
112: 80C3jmp mx_keyb_ret
113:
114: ; чтение из последовательного порта
115: 80C5 read:
116: 80C5D jnb RI, read_ret_abort
117: 80C8 C2 98 clr RI
118: 80CA E5 99 mov A, SBUF
119: ; если операция уже вводилась
120: ; проверить, не знак ли это равенства
121: 80CCjb 20h.4, aequ0
122: ; в противном случае операция ещё не вводилась
123: ; плюс ли это?
124: 80CF B4 2B 08 cjne A, #'+', aminus0
125: ; если плюс
126: 80D2jmp aplus1
127:
128: 80D5 read_ret_abort:
129: 80D5 22 ret
130:
131: 80D6 read_ret:
132: 80D6call out
133: 80D9 22 ret
134:
135: ; вычитание
136: 80DA aminus0:
137: ; минус ли это?
138: 80DA B4 2D 09 cjne A, #'-', amultiply0
139: 80DDjmp aminus1
140:
141: ; на вычисление
142: 80E0 aequ0:
143: ; равно ли это?
144: 80E0 B4 3D F2 cjne A, #'=', read_ret_abort
145: 80E3D jmp aequ1
146:
147: ; умножение
148: 80E6 amultiply0:
149: ; звездочка ли это?
150: 80E6 B4 2A 03 cjne A, #'*', adivide0
151: 80E9F jmp amultiply1
152:
153: ; деление
154: 80EC adivide0:
155: ; косая ли это черта?
156: ; все варианты перебрали
157: ; если ни один не подходит,
158: ; значит ввели что-то не то
159: 80EC B4 2F E6 cjne A, #'/', read_ret_abort
160: 80EFE jmp adivide1
161:
162: ; запись цифры в память
163: ; в зависимости от ее порядка
164: 80F2 digits_write:
165: ; клавиша нажата и держится
166: 80F2 D2 07 setb 20h.7
167: 80F4jb 20h.0, first_digit
168: 80F7jb 20h.1, second_digit
169: 80FAC jb 20h.2, third_digit
170: 80FDjb 20h.3, fourth_digit
171: 8ret
172:
173: 8101 aplus1:
174: ; если уже введено первое число
175: 8jnb 20h.0, aplus2
176: 8jmp mx_keyb_ret
177:
178: 8106 aplus2:
179: ; записать число из цифр
180: 8call merge_digits
181: ; операция - сложение
182: ; можно вводить второе число
183: 8mov 20h, #b
184: 810C 74 2B mov A, #'+'
185: 810E 80 C6 jmp read_ret
186:
187: 8110 aminus1:
188: ; если уже введено первое число
189: 8jnb 20h.0, aminus2
190: 8jmp mx_keyb_ret
191:
192: 8115 aminus2:
193: ; записать число из цифр
194: 8call merge_digits
195: ; операция - вычитание
196: ; можно вводить второе число
197: 8mov 20h, #b
198: 811B 74 2D mov A, #'-'
199: 811D 80 B7 jmp read_ret
200:
201: 811F amultiply1:
202: ; если уже введено первое число
203: 811Fjnb 20h.0, amultiply2
204: 8jmp mx_keyb_ret
205:
206: 8124 amultiply2:
207: ; записать число из цифр
208: 8call merge_digits
209: ; операция - умножение
210: ; можно вводить второе число
211: 8mov 20h, #b
212: 812A 74 2A mov A, #'*'
213: 812C 80 A8 jmp read_ret
214:
215: 812E adivide1:
216: ; если уже введено первое число
217: 812Ejnb 20h.0, adivide2
218: 8jmp mx_keyb_ret
219:
220: 8133 adivide2:
221: ; записать число из цифр
222: 8call merge_digits
223: ; операция - деление
224: ; можно вводить второе число
225: 8mov 20h, #b
226: 8F mov A, #'/'
227: 813Bjmp read_ret
228:
229: 813D aequ1:
230: 813Djnb 20h.0, aequ2
231: 8jmp mx_keyb_ret
232:
233: 8142 aequ2:
234: 8D mov A, #'='
235: 8call out
236: ; записать число из цифр
237: 8call merge_digits
238: ; подсчитать результат
239: 814AC call evaluate
240: ; очистить
241: 814Dmov 20h, #b
242: 8mov 21h, #0
243: 8jmp read_ret_abort
244:
245: 8155 digits_ret:
246: 8add A, #30h
247: 8call out
248: 815A 22 ret
249:
250: 815B first_digit:
251: 815B F8 mov R0, A
252: 815C C2 00 clr 20h.0
253: 815E D2 01 setb 20h.1
254: 8F3 jmp digits_ret
255:
256: 8162 second_digit:
257: 8162 F9 mov R1, A
258: 8163 C2 01 clr 20h.1
259: 8165 D2 02 setb 20h.2
260: 8EC jmp digits_ret
261:
262: 8169 third_digit:
263: 8169 FA mov R2, A
264: 816A C2 02 clr 20h.2
265: 816C D2 03 setb 20h.3
266: 816E 80 E5 jmp digits_ret
267:
268: 8170 fourth_digit:
269: 8170 FB mov R3, A
270: 8171 C2 03 clr 20h.3
271: 8E0 jmp digits_ret
272:
273: ; подсчет числа по записанным цифрам
274: 8175 merge_digits:
275: 8A jb 20h.1, merge_digits1
276: 8E jb 20h.2, merge_digits2
277: 817BC jb 20h.3, merge_digits3
278: 817EE jmp merge_digits4
279:
280: 8181 write_dptr1:
281: 8jnb 20h.4, write_dptr0
282: 8B jmp merge_digits_ret
283:
284: 8187 write_dptr0:
285: 8187 AE 83 mov R6, DPH
286: 8189 AF 82 mov R7, DPL
287:
288: 818B merge_digits_ret:
289: 818B 22 ret
290:
291: ; получение результата
292: 818C evaluate:
293: ; сложение и вычитание
294: 818Cjnb 20h.6, plusminus
295: ; умножение и деление
296: 818FAC jmp multdivide
297:
298: ; число из одного знака
299: ; просто записывается в DPL
300: 8192 merge_digits1:
301: 8mov DPH, #0
302: 8mov DPL, R0
303: 8E8 jmp write_dptr1
304:
305: ; число из двух знаков
306: 8199 merge_digits2:
307: ; второй разряд * 10
308: 8199 E8 mov A, R0
309: 819A 75 F0 0A mov B, #10
310: 819D A4 mul AB
311: ; сложить с первым разрядом
312: ; и записать в DPL
313: 819E 29 add A, R1
314: 819Fmov DPH, #0
315: 81A2 F5 82 mov DPL, A
316: 81A4 80 DB jmp write_dptr1
317:
318: ; выбор, сложение или вычитание
319: 81A6 plusminus:
320: 81A6jnb 20h.5, l_plus
321: 81A9B8 jmp l_minus
322:
323: ; выбор, умножение или деление
324: 81AC multdivide:
325: 81ACF jnb 20h.5, l_multiply
326: 81AFC4 jmp l_division
327:
328: 81B2 l_plus:
329: 81B2ED call plus
330: 81B5E9 jmp evaluate_ret
331:
332: 81B8 l_minus:
333: 81B8FD call minus
334: 81BBE9 jmp evaluate_ret
335:
336: 81BE l_multiply:
337: 81BEE call multiply
338: 81C1E9 jmp evaluate_ret
339:
340: 81C4 l_division:
341: 81C4E call division
342: 81C7E9 jmp evaluate_ret
343:
344: ; число из трех знаков
345: 81CA merge_digits3:
346: ; третий разряд * 100
347: ; результат записать в 2 ячейки
348: 81CA E8 mov A, R0
349: 81CB 75 F0 64 mov B, #100
350: 81CE A4 mul AB
351: 81CF FC mov R4, A
352: 81D0 AD F0 mov R5, B
353: ; второй разряд * 10
354: 81D2 E9 mov A, R1
355: 81D3 75 F0 0A mov B, #10
356: 81D6 A4 mul AB
357: ; сложить с третьим разрядом
358: 81D7 C3 clr C
359: 81D8 3C addc A, R4
360: ; сохранить
361: 81D9 FC mov R4, A
362: ; бит переноса записать в старшую ячейку
363: 81DA ED mov A, R5
364: 81DBaddc A, #0
365: ; сохранить
366: 81DD FD mov R5, A
367: ; прибавить к младшей ячейке
368: ; первый разряд
369: 81DE EC mov A, R4
370: 81DF 3A addc A, R2
371: ; записать в DPL
372: 81E0 F5 82 mov DPL, A
373: ; бит переноса записать в старшую ячейку
374: 81E2 ED mov A, R5
375: 81E3addc A, #0
376: ; записать в DPH
377: 81E5 F5 83 mov DPH, A
378: 81E7jmp write_dptr1
379:
380: 81E9 evaluate_ret:
381: 81E9call output
382: 81EC 22 ret
383:
384: ; сложение
385: 81ED plus:
386: ; сложение младших разрядов
387: 81ED EF mov A, R7
388: 81EE C3 clr C
389: 81EFaddc A, DPL
390: 81F1 F5 82 mov DPL, A
391: ; сложение старших разрядов
392: ; с учетом бита переноса
393: 81F3 EE mov A, R6
394: 81F4addc A, #0
395: 81F6addc A, DPH
396: 81F8 F5 83 mov DPH, A
397: ; переполнение
398: 81FAmov 21h.1, C
399: 81FC 22 ret
400:
401: ; вычитание
402: 81FD minus:
403: ; вычитание младших разрядов
404: 81FD EF mov A, R7
405: 81FE C3 clr C
406: 81FFsubb A, DPL
407: 8201 F8 mov R0, A
408: ; вычитание старших разрядов
409: ; с учетом бита переноса
410: 8202 EE mov A, R6
411: 8subb A, #0
412: 8subb A, DPH
413: 8jc minus_reverse
414: 8209 F5 83 mov DPH, A
415: 820Bmov DPL, R0
416: 820D 22 ret
417:
418: ; вычитание
419: ; первое число оказалось меньше второго
420: 820E minus_reverse:
421: ; отрицательность
422: 820E D2 0A setb 21h.2
423: ; вычитание младших байт
424: 8210 E5 82 mov A, DPL
425: 8212 C3 clr C
426: 8213 9F subb A, R7
427: 8214 F5 82 mov DPL, A
428: ; вычитание старших байт
429: ; с учетом бита переноса
430: 8216 E5 83 mov A, DPH
431: 8subb A, #0
432: 821A 9E subb A, R6
433: 821B F5 83 mov DPH, A
434: 821D 22 ret
435:
436: ; умножение
437: 821E multiply:
438: ; (a+b)*(c+d)=ac+ad+bc+bd
439: ; если в старших байтах обоих чисел
440: ; есть значения, то будет переполнение
441: 821E EE mov A, R6
442: 821Fjnz mult1
443: 8221 E5 83 mov A, DPH
444: 8E jnz mult2
445: ; данные только в младших байтах
446: 8225 EF mov A, R7
447: 8F0 mov B, DPL
448: 8229 A4 mul AB
449: 822A F5 82 mov DPL, A
450: 822C 85 F0 83 mov DPH, B
451: 822F 22 ret
452:
453: ; переполнение
454: 8230 overflow:
455: 8230 D2 09 setb 21h.1
456: 8ret
457:
458: 8233 mult1:
459: 8233 E5 83 mov A, DPH
460: 8F9 jnz overflow
461: ; первое число заняло два байта
462: ; второе - один
463: ; перемножаем младшие байты и записываем
464: 8237 E5 82 mov A, DPL
465: 8239 8F F0 mov B, R7
466: 823B A4 mul AB
467: 823C F9 mov R1, A
468: 823D 85 F0 83 mov DPH, B
469: ; умножаем старший байт первого числа
470: ; на второе число
471: 8240 E5 82 mov A, DPL
472: 8242 8E F0 mov B, R6
473: 8244 A4 mul AB
474: ; прибавляем к уже полученному результату
475: 8245 C3 clr C
476: 8addc A, DPH
477: 8248 F5 83 mov DPH, A
478: ; переполнение
479: 824A 40 E4 jc overflow
480: ; проверяем B: возможно переполнение
481: 824C E5 F0 mov A, B
482: 824E 70 E0 jnz overflow
483: ; дописываем результат
484: 8mov DPL, R1
485: 8ret
486:
487: 8253 mult2:
488: ; первое число заняло один байт
489: ; второе - два
490: ; перемножаем младшие байты и записываем
491: 8253 E5 82 mov A, DPL
492: 8255 8F F0 mov B, R7
493: 8257 A4 mul AB
494: 8258 F9 mov R1, A
495: 8259 A8 F0 mov R0, B
496: ; умножаем старший байт второго числа
497: ; на первое число
498: 825B E5 83 mov A, DPH
499: 825D 8F F0 mov B, R7
500: 825F A4 mul AB
501: ; прибавляем к уже полученному результату
502: 8260 C3 clr C
503: 8addc A, R0
504: 8262 F8 mov R0, A
505: ; переполнение
506: 8CB jc overflow
507: ; проверяем B: возможно переполнение
508: 8265 E5 F0 mov A, B
509: 8C7 jnz overflow
510: ; записываем результат
511: 8mov DPL, R1
512: 826Bmov DPH, R0
513: 826D 22 ret
514:
515: ; число из четырех знаков
516: 826E merge_digits4:
517: ; четвертый разряд * 10 * 100
518: 826E E8 mov A, R0
519: 826F 75 F0 0A mov B, #10
520: 8272 A4 mul AB
521: 8F0 64 mov B, #100
522: 8276 A4 mul AB
523: ; результат записать в 2 ячейки
524: 8277 FC mov R4, A
525: 8278 AD F0 mov R5, B
526: ; третий разряд * 100
527: 827A E9 mov A, R1
528: 827B 75 F0 64 mov B, #100
529: 827E A4 mul AB
530: ; прибавить к младшему разряду
531: ; младшую ячейку четвертого разряда
532: 827F C3 clr C
533: 8280 3C addc A, R4
534: 8281 FC mov R4, A
535: ; прибавить к старшему разряду
536: ; старшую ячейку четвертого разряда
537: ; учитывая бит переноса
538: 8282 E5 F0 mov A, B
539: 8284 3D addc A, R5
540: 8285 FD mov R5, A
541: ; второй разряд * 10
542: 8286 EA mov A, R2
543: 8F0 0A mov B, #10
544: 828A A4 mul AB
545: ; прибавить к нему
546: ; младшую ячейку
547: 828B C3 clr C
548: 828C 3C addc A, R4
549: 828D FC mov R4, A
550: ; бит переноса прибавить
551: ; к старшей ячейке
552: 828E ED mov A, R5
553: 828Faddc A, #0
554: 8291 FD mov R5, A
555: ; первый разряд прибавить
556: ; к младшей ячейке
557: 8292 EB mov A, R3
558: 8293 C3 clr C
559: 8294 3C addc A, R4
560: 8295 F5 82 mov DPL, A
561: ; бит переноса прибавить
562: ; к старшей ячейке
563: 8297 ED mov A, R5
564: 8addc A, #0
565: 829A F5 83 mov DPH, A
566: 829Cjmp write_dptr1
567:
568: ; деление
569: 829E division:
570: ; проверка деления на ноль
571: 829E E5 82 mov A, DPL
572: 82A0jz divbyzero
573: 82A2 nozero:
574: ; здесь будет результат
575: 82A2mov R0, #0
576: 82A4mov R1, #0
577: ; а это для удобства заполнения результата:
578: ; сдвигать влево и прибавлять к ответу
579: ; по мере необходимости
580: ; также - регистр-счетчик
581: 82A6 7A 00 mov R2, #0
582: 82A8 7B 01 mov R3, #1
583: ; режим работы:
584: ; 0 - первая фаза, сдвиг влево
585: ; 1 - вторая фаза, сдвиг вправо и вычитание
586: 82AA C2 08 clr 21h.0
587: ; пробуем вычесть из первого числа второе
588: 82ACF jmp subtract
589: 82AF sub_l_success:
590: ; сдвигаем второе число влево...
591: 82AFD2 jmp move_left
592: 82B2 mvl_success:
593: ; ... и повторяем процедуру...
594: 82B2F jmp subtract
595: 82B5 sub_l_fail:
596: ; ... пока второе число не окажется больше первого...
597: 82B5F3 jmp move_right
598: 82B8 mvl_fail:
599: ; ... или после сдвига второе число уехало влево
600: ; меняем режим работы на вторую фазу
601: 82B8 D2 08 setb 21h.0
602: 82BAF jmp subtract
603: 82BD sub_r_success:
604: ; можно записать в результат значение...
605: 82BDB jmp add_result
606: 82C0 sub_r_fail:
607: ; ... сдвинуть вправо...
608: 82C0F3 jmp move_right
609: 82C3 mvr_r_success:
610: ; ... вычесть ...
611: 82C3F jmp subtract
612: 82C6 mvr_fail:
613: ; ... пока второе число не упрется
614: ; в R0 и R1 будет результат
615: 82C6mov DPH, R0
616: 82C8mov DPL, R1
617: 82CA 22 ret
618:
619: ; проверка деления на ноль
620: 82CB divbyzero:
621: 82CB E5 83 mov A, DPH
622: 82CD 70 D3 jnz nozero
623: ; флаг ошибки деления на ноль
624: 82CF D2 0B setb 21h.3
625: 82D1 22 ret
626:
627: ; сдвиг второго операнда влево
628: 82D2 move_left:
629: ; сдвиг второго байта
630: 82D2 E5 82 mov A, DPL
631: 82D4 C3 clr C
632: 82D5 33 rlc A
633: 82D6 F5 82 mov DPL, A
634: ; сдвиг первого байта
635: 82D8 E5 83 mov A, DPH
636: 82DA 33 rlc A
637: ; число "уехало" влево
638: 82DB 40 0B jc rollback
639: 82DD F5 83 mov DPH, A
640: ; сдвиг регистра-счетчика
641: 82DF EB mov A, R3
642: 82E0 C3 clr C
643: 82E1 33 rlc A
644: 82E2 FB mov R3, A
645: 82E3 EA mov A, R2
646: 82E4 33 rlc A
647: 82E5 FA mov R2, A
648: 82E6 80 CA jmp mvl_success
649:
650: ; откат сдвига влево
651: 82E8 rollback:
652: 82E8 D3 setb C
653: 82E9 13 rrc A
654: 82EA F5 83 mov DPH, A
655: 82EC E5 82 mov A, DPL
656: 82EE 13 rrc A
657: 82EF F5 82 mov DPL, A
658: 82F1 80 C5 jmp mvl_fail
659:
660: ; сдвиг второго операнда вправо
661: 82F3 move_right:
662: ; сдвиг первого байта
663: 82F3 E5 83 mov A, DPH
664: 82F5 C3 clr C
665: 82F6 13 rrc A
666: 82F7 F5 83 mov DPH, A
667: ; сдвиг второго байта
668: 82F9 E5 82 mov A, DPL
669: 82FB 13 rrc A
670: 82FC F5 82 mov DPL, A
671: ; сдвиг регистра счетчика
672: 82FE EA mov A, R2
673: 82FF C3 clr C
674: 8rrc A
675: 8301 FA mov R2, A
676: 8302 EB mov A, R3
677: 8rrc A
678: ; число было в крайнем правом положении
679: 8C0 jc mvr_fail
680: 8306 FB mov R3, A
681: 8A jmp mvr_success
682:
683: ; к какой фазе относится
684: ; данный сдвиг вправо
685: 830A mvr_success:
686: ; к первой
687: 830AAB jnb 21h.0, mvl_fail
688: ; ко второй
689: 830D 80 B4 jmp mvr_r_success
690:
691: ; вычитание для деления
692: 830F subtract:
693: ; вычитание второго байта
694: 830F EF mov A, R7
695: 8310 C3 clr C
696: 8subb A, DPL
697: 8313 FD mov R5, A
698: ; вычитание первого байта
699: 8314 EE mov A, R6
700: 8subb A, #0
701: 8jc sub_fail
702: 8subb A, DPH
703: 831Bjc sub_fail
704: 831D FC mov R4, A
705: 831Ejmp sub_success
706:
707: ; вычитание не получилось,
708: ; куда теперь?
709: 8321 sub_fail:
710: ; на первую фазу
711: 8jnb 21h.0, sub_l_fail
712: ; на вторую фазу
713: 8A jmp sub_r_fail
714:
715: ; вычитание получилось,
716: ; но куда сейчас?
717: 8326 sub_success:
718: ; на первую фазу
719: 8jnb 21h.0, sub_l_success
720: ; на вторую фазу
721: 8jmp sub_r_success
722:
723: ; добавление значения
724: ; к результату деления
725: 832B add_result:
726: ; первый байт
727: 832B EA mov A, R2
728: 832C 48 orl A, R0
729: 832D F8 mov R0, A
730: ; второй байт
731: 832E EB mov A, R3
732: 832F 49 orl A, R1
733: 8330 F9 mov R1, A
734: ; записать новое делимое
735: 8331 EC mov A, R4
736: 8332 FE mov R6, A
737: 8333 ED mov A, R5
738: 8334 FF mov R7, A
739: 8jmp sub_r_fail
740:
741: ; вывод
742: 8337 output:
743: ; сообщения об ошибках
744: 8jb 21h.1, output_overflow
745: 833A 20 0B 8E jb 21h.3, divbyzero
746: 833DCF jmp output_correct
747:
748: 8340 output_ret:
749: 8ret
750:
751: ; ошибка переполнения
752: 8341 output_overflow:
753: 8F mov A, #'O'
754: 8call out
755: 8mov A, #'V'
756: 8call out
757: 834Bmov A, #'E'
758: 834Dcall out
759: 8mov A, #'R'
760: 8call out
761: 8mov A, #'F'
762: 8call out
763: 835A 74 4C mov A, #'L'
764: 835Ccall out
765: 835F 74 4F mov A, #'O'
766: 8call out
767: 8mov A, #'W'
768: 8call out
769: 8A mov A, #0Ah
770: 836Bcall out
771: 836E 80 D0 jmp output_ret
772:
773: ; ошибка деления на ноль
774: 8370 output_divbyzero:
775: 8mov A, #'D'
776: 8call out
777: 8mov A, #'I'
778: 8call out
779: 837Amov A, #'V'
780: 837Ccall out
781: 837Fmov A, #'I'
782: 8call out
783: 8mov A, #'S'
784: 8call out
785: 8mov A, #'I'
786: 838Bcall out
787: 838E 74 4F mov A, #'O'
788: 8call out
789: 8E mov A, #'N'
790: 8call out
791: 8mov A, #20h
792: 839Acall out
793: 839Dmov A, #'B'
794: 839Fcall out
795: 83A2mov A, #'Y'
796: 83A4call out
797: 83A7mov A, #20h
798: 83A9call out
799: 83AC 74 5A mov A, #'Z'
800: 83AEcall out
801: 83B1mov A, #'E'
802: 83B3call out
803: 83B6mov A, #'R'
804: 83B8call out
805: 83BB 74 4F mov A, #'O'
806: 83BDcall out
807: 83C0 74 0A mov A, #0Ah
808: 83C2call out
809: 83C5jmp output_ret
810:
811: ; вывод минуса
812: 83C7 out_minus:
813: 83C7 74 2D mov A, #2Dh
814: 83C9call out
815: 83CCD2 jmp minus_done
816:
817: ; вывод результата
818: 83CF output_correct:
819: ; если число отрицательное
820: 83CF 20 0A F5 jb 21h.2, out_minus
821: 83D2 minus_done:
822: ; резервные копии результата
823: 83D2mov 30h, DPH
824: 83D5mov 31h, DPL
825: ; первая итерация
826: ; деление на 10000
827: ; 000
828: 83D8 AE 83 mov R6, DPH
829: 83DA AF 82 mov R7, DPL
830: 83DCmov DPH, #b
831: 83DFmov DPL, #b
832: 83E2 51 9E call division
833: ; результат записать в первый разряд
834: 83E4mov A, #30h
835: 83E6add A, DPL
836: 83E8 F5 32 mov 32h, A
837: ; результат умножить на 10000
838: 83EA 7E 27 mov R6, #b
839: 83EC 7F 10 mov R7, #b
840: 83EE 51 1E call multiply
841: ; ... и вычесть из решения
842: 83F0 AE 30 mov R6, 30h
843: 83F2 AF 31 mov R7, 31h
844: 83F4 31 FD call minus
845: ; вторая итерация
846: ; повторить то же самое для 1000
847: ; 000
848: 83F6mov 30h, DPH
849: 83F9mov 31h, DPL
850: 83FC AE 83 mov R6, DPH
851: 83FE AF 82 mov R7, DPL
852: 8mov DPH, #b
853: 8E8 mov DPL, #b
854: 8E call division
855: ; результат записать во второй разряд
856: 8mov A, #30h
857: 840Aadd A, DPL
858: 840C F5 33 mov 33h, A
859: ; результат умножить на 1000
860: 840E 7E 03 mov R6, #b
861: 8410 7F E8 mov R7, #b
862: 8E call multiply
863: ; ... и вычесть из решения
864: 8414 AE 30 mov R6, 30h
865: 8416 AF 31 mov R7, 31h
866: 8FD call minus
867: ; третья итерация
868: ; повторить то же самое для 100
869: ; 000
870: 841Amov 30h, DPH
871: 841Dmov 31h, DPL
872: 8420 AE 83 mov R6, DPH
873: 8422 AF 82 mov R7, DPL
874: 8mov DPH, #0
875: 8mov DPL, #b
876: 842A 51 9E call division
877: ; результат записать в третий разряд
878: 842Cmov A, #30h
879: 842Eadd A, DPL
880: 8430 F5 34 mov 34h, A
881: ; результат умножить на 100
882: 8432 7E 00 mov R6, #0
883: 8434 7F 64 mov R7, #b
884: 8E call multiply
885: ; ... и вычесть из решения
886: 8438 AE 30 mov R6, 30h
887: 843A AF 31 mov R7, 31h
888: 843C 31 FD call minus
889: ; четвертая итерация
890: ; повторить для 10
891: ; и записать в четвертый разряд
892: 843E E5 82 mov A, DPL
893: 8F0 0A mov B, #10
894: 8div AB
895: 8444 FE mov R6, A
896: 8add A, #30h
897: 8447 F5 35 mov 35h, A
898: ; пятая итерация
899: ; остаток записать в пятый разряд
900: 8449 EE mov A, R6
901: 844A 75 F0 0A mov B, #10
902: 844D A4 mul AB
903: 844E F5 F0 mov B, A
904: 8450 E5 82 mov A, DPL
905: 8452 C3 clr C
906: 8F0 subb A, B
907: 8add A, #30h
908: 8457 F5 36 mov 36h, A
909: ; вывод на экран
910: 8459 E5 32 mov A, 32h
911: 845Bcall out
912: 845E E5 33 mov A, 33h
913: 8call out
914: 8463 E5 34 mov A, 34h
915: 8call out
916: 8468 E5 35 mov A, 35h
917: 846Acall out
918: 846D E5 36 mov A, 36h
919: 846Fcall out
920: 8A mov A, #0Ah
921: 8call out
922: 8jmp output_ret
923:
924: ; готовность к работе
925: 8479 output_ready:
926: 8mov A, #'R'
927: 847Bcall out
928: 847Emov A, #'E'
929: 8call out
930: 8mov A, #'A'
931: 8call out
932: 8mov A, #'D'
933: 848Acall out
934: 848Dmov A, #'Y'
935: 848Fcall out
936: 8A mov A, #0Ah
937: 8call out
938: 8ret
939:
940: ; вывод символа
941: 8498 out:
942: 8498 C2 AC clr ES
943: 849AFB jnb TI, out
944: 849D C2 99 clr TI
945: 849F F5 99 mov SBUF, A
946: 84A1 D2 AC setb ES
947: 84A3A7 call delay
948: 84A6 22 ret
949:
950: ; задержка как мера от дребезга контактов
951: 84A7 delay:
952: 84A7 74 1F mov A, #b
953: 84A9 loop_delay:
954: 84A9 14 dec A
955: 84AA 70 FD jnz loop_delay
956: 84AC 22 ret
957:
958: 84AD main:
959: ; биты 0..3 - длина вводимого числа
960: ; 4 бит - 0 - первое число, 1 - второе
961: ; 5, 6 биты - знак операции
962: ; (00 - +,, 10 - *, 11 - /)
963: ; 7 бит - клавиша нажата и держится
964: 84ADmov 20h, #1
965: ; бит 0 - этапы операции деления
966: ; бит 1 регистрирует переполнение
967: ; бит 2 указывает на отрицательность числа
968: ; бит 3 зарезервирован для ошибки деления на ноль
969: 84B0mov 21h, #0
970: 84B3 75 B8 00 mov IP, #0
971: ; прерывания принимаются
972: ; от таймера, матричной клавиатуры
973: ; и обычной клавиатуры
974: 84B6 75 A8 92 mov IE, #b
975: ; таймер
976: 84B9mov TMOD, #b
977: 84BCmov TCON, #b
978: 84BFcall output_ready
979:
980: 84C1 80 FE loop: jmp loop
981: end
Список использованной литературы
1. , Лекции по микропроцессорным технологиям, 2010 г.
2. «Микроконтроллеры семейства MCS-51», http://digital. *****/content. htm



