Хостинг портала RFpro.ru: Московский хостер Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64 РАССЫЛКИ ПОРТАЛА RFPRO.RU Чемпионы рейтинга экспертов в этой рассылке Номер выпуска: | 1336 | Дата выхода: | 13.05.2010, 11:30 | Администратор рассылки: | Лысков Игорь Витальевич, Модератор | Подписчиков / экспертов: | 275 / 60 | Вопросов / ответов: | 2 / 2 | IRC-канал по теме: | #assembler | Вопрос № 178069: Здравствуйте, уважаемые эксперты. Требуется написать программу (с комментариями кода), которая чертит график распределения Максвелла с изменяющимися параметрами скорости в интервале от 0 до 4500 м/c, температура и масса молекулы для данного интерв... Вопрос № 178233: Доброго времени суток, уважаемые эксперты! Позвольте представить на ваше рассмотрение очередной проект(предварительный бюджет 700-800 р) В общих чертах задача поставлена так: Спроектировать и запрограммировать на ассемблере регулят... Вопрос № 178069: Здравствуйте, уважаемые эксперты. Требуется написать программу (с комментариями кода), которая чертит график распределения Максвелла с изменяющимися параметрами скорости в интервале от 0 до 4500 м/c, температура и масса молекулы для данного интервала принимается постоянной. Однако график не должен быть статичным, и температура и масса могла меняться пользователем. Платформа Dos, ассемблер TASM. Приблизительный результат можно увидеть http://chemistry.ru/course/content/models/Maxwell.html Отправлен: 27.04.2010, 18:15 Вопрос задал: Филимонов Алексей Викторович, Посетитель Всего ответов: 1 Страница вопроса » Отвечает Лысков Игорь Витальевич, Модератор : Здравствуйте, Филимонов Алексей Викторович. Ну почему же, хоть какое-то решение... Вполне нормальное решение Программа далеко неочевидная, пришлось повозиться... Используемые клавиши: Esc - выход Enter - отработка новых значений. Обратите внимание, масса должна быть задана корректно (в программе осуществляется контроль) Стрелки вниз/вверх - делают текущими для коррекции поля параметров BackSpace - вытирает последний символ
Код: ;Функция плотности вероятности распределения Максвелла ;молекул идеального газа по скоростям ;f(v)=(4/sqrt(Pi)) * (m/(2kT))^(3/2) * v^2 * exp(-(mv^2)/(2kT)) ;v - скорость частицы газа, m - ее масса, T - температура газа, ;k=1.38*10^(- 23) Дж/К - постоянная Больцмана .model tiny, C .386
VStep equ 14 ;коэффициент для преобразования ;абсциссы в скорость .data m dd 3.32e-27 ;масса молекулы (водорода, для примера) k dd 1.38e-23 ;постоянная Больцмана a dd 0 ;m/(2kT) b dd 0 ;4/sqrt(Pi) T dw 250 ;темперарура в Кельвинах fNum dw 8 ;флаг выбора, что вводится 1 - темпер, 0 - масса iLen dw 0 ;длина введенной массы
;константы c2 dd 2. c4 dd 4. c3_10_5 dd 3.e5 ;для преобразования в экранные координаты c10 dd 10. c100 dd 100.
s10 db '*10',0 ;надпись возле оси ординат s4 db '-4',0 ;показатель степени там же sTeq db 'T=',0 ;надпись для ввода температуры sMeq db 'm=',0 ;надпись для ввода массы sfBuf db 16 dup (?) ;буфер для ввода массы (вещественного числа)
.code .startup
;посчитаем b=4/sqrt(Pi) call Calc_b
;преходим в графику mov ax, 0013h ; vga 320x200x256 int 10h
mov ax, 0a000h mov es, ax ; es - сегмент видео
main_loop: ;посчитаем a=m/(2kT) call Calc_a
call line, 0, 190, 319, 190, 8 ;ось абсцисс call gor, 1000, 4000, 8 ;рисочки с надписями на оси абсцисс call line, 0, 0, 0, 190, 8 ;ось ординат call ver, 1, 6, 8 ;рисочки с надписями на оси ординат call PrintText, 10, 6, offset s10, 8 ;надпись '*10^-4' call PrintText, 34, 2, offset s4, 8 ;показатель чуть выше
call Graph, 0, 319, offset CalcFun, 0bh ;график ;выводим рамочку с массой mov ax, fNum ;инверсный флаг активности xor ax, 8 or ax, 1 call PrFloat, 319-10*8-2, 16, offset sMeq, offset m, ax, 1
;выводим рамочку с температурой Pr_temp: mov ax, fNum ;флаг активного окна (более яркий) or ax, 1 ;синий цвет, активный - голубой call PrInt, 319-10*8-2, 2, offset sTeq, T, ax, 1
wait_key: ;цикл ожидания нажатия на клавишу mov ah, 0 int 16h
cmp ah, 1 je exit ;Escape - выход cmp al, 0dh je key_Enter ;Enter - отработать новые значения cmp ah, 50h je key_Arrow ;стрелки - меняем активное окошко cmp ah, 48h je key_Arrow cmp al, 8 je key_BS ;BackSpace - вытираем послдний символ cmp al, '0' ;проверим на цифру jb cmp_menus ;меньше - проверить на минус для массы cmp al, '9' jbe cmp_digit ;цифра '0'-'9' - на проверку, что вводим cmp_menus: cmp al, '.' je cmp_massa_key ;точка - на проверку для массы cmp al, '-' je cmp_massa_key ;минус - на проверку для массы or al, 20h ;сделаем маленькой буквой cmp al, 'e' ;e - на проверку для массы je cmp_massa_key jmp wait_key ;все остальное игнорируем cmp_digit: ;цифры test fNum, 8 ;что вводим? jnz temperature_code ;=8 - температура, как целое cmp_massa_key: ;вводим массу call floatCode ;отработаем jc wait_key ;ошибка - игнорируем call PrintText, 319-8*8-2, 16, offset sfBuf, 9 ; выведем строку jmp wait_key ;и на ожидание клавиши temperature_code: ;вводим температуру push ax ;умножаем старшие разряды на 10 mov ax, 10 ;и добавляем младший mul T pop dx and dx, 0fh add ax, dx cmp ax, 1000 ;можно ввести только 3 цифры jae wait_key mov T, ax ;все ок, сохраняем jmp Pr_temp ;отрисовать
key_Arrow: ;стрелки xor fNum, 8 ;меняем активное окно mov ax, fNum ;флаг активного окна (более яркий) xor ax, 8 or ax, 1 ;синий цвет, активный - голубой ;выведем строку с массой call PrintText, 319-8*8-2, 16, offset sfBuf, ax jmp Pr_temp ;на вывод температуры
key_Enter: ;по Enter-у отрабатываем call atof, offset sfBuf, offset m ;преобразовываем во float test ax, ax ;проверим, ок? jnz wait_key ;ошибка - ничего не деаем call Graph, 0, 319, offset CalcFun,0 ;вытерем старый jmp main_loop ;и рисуем заново
key_BS: ;BackSpace test fN um, 8 ;что вводим? jnz temperature_BS call floatBS ;для массы jc wait_key ;если ошибка call Clear, 319-8*8-2, 16, 8 ;вытираем на экране call PrintText, 319-8*8-2, 16, offset sfBuf, 9 ;и выводим строку из буфера jmp wait_key ;на ожидание клавиши temperature_BS: ;для температуры cmp T, 0 ;в левой позиции je wait_key ; ничего не делаем mov ax, T ;делим на 10, удаляем младший разряд xor dx, dx mov cx, 10 div cx mov T, ax ;сохраняем jmp Pr_temp ;отрисуем
exit: ;выход mov ax, 0003h ;обратно в текстовый режим int 10h
mov ax,4c00h ;выход в ДОС int 21h
;преобразование строки во float ;параметры: ;psFloat - адрес строки ;pdFloat - адрес float atof proc psFloat:word, pdFloat:word uses si local i:word cmp iLen, 8 jne af_ret_c ;разрешаем только полностью введенное число mov si, psFloat ;считаем три символа (точку игно рируем), ; как 3-х значное число lodsb ;первый символ - число сотен and al, 0fh mov ah, 100 mul ah mov i, ax ;накапливаем lodsb cmp al, '.' ;проверим на точку jne af_ret_c lodsb ;число десятков and al, 0fh mov ah, 10 mul ah add i, ax ;накапливаем lodsb ;число единиц and ax, 0fh add i, ax ;3-х значное число fild i ;загружаем fdiv c100 ;делим на 100 lodsb ;проверяем на 'e' or al, 20h cmp al, 'e' jne af_ret_c lodsb ;проверяем на '-' cmp al, '-' jne af_ret_c lodsw ;порядок xchg al, ah and ax, 0f0fh aad ;преобразуем в двоичное число mov cx, ax ;столько раз надо разделить на 10 shr cx, 1 ;или на 100 af_div_loop: fdiv c100 ;делим cx раз на 100 loop af_div_loop shr ax, 1 ;если нечетное число. то jnc af_save_m fdiv c10 ;делим еще и на 10 af_save_m: mov si, pdFloat ;адрес float fstp dword ptr [si] ;сохраняем xor ax, ax ;признак, что все ок ret af_ret_c: mov ax, 1 ;признак ошибки ret atof endp
strlen proc pString:word ;длина строки uses di, bx mov di, pString xor bx, bx sl_loop: cmp byte ptr [di+bx], 0 ;ищем 0 je sl_ret inc bx ;считаем jmp sl_loop sl_ret: mov ax, bx ;результат ret strlen endp
;BackSpace для массы floatBS proc mov di, iLen test di, di jz im_ret_c ;нельзя для первой позиции dec di mov iLen, di ;уменьшаем длину mov sfBuf[di], 0 ;и закрываем 0 clc ;все ок ret im_ret_c: stc ;ошибка ret floatBS endp
;вводим символ для массы floatCode proc mov di, iLen ;индекс конца строки cmp di, 8 je fc_ret_c ;все 8 символов введены - ошибка cmp di, 6 jae fc_067 ;позиция цифр порядка - на ввод цифры cmp di, 5 je fc_5 ;позиция минуса порядка cmp di, 4 je fc_4 ;позиция буквы 'e' cmp di, 3 je fc_3 ; позиция второго символа после точки cmp di, 2 je fc_2 ;позиция первого символа после точки cmp di, 1 je fc_1 ;позиция точки fc_067: ;проверка на цифру cmp al, '0' jb fc_ret_c ;не цифра - ошибка cmp al, '9' ja fc_ret_c fc_save: mov sfBuf[di], al ;сохраняем inc di mov byte ptr sfBuf[di], 0 ;закрываем 0 mov iLen, di ;новая длина clc ;все ок ret fc_5: cmp al, '-' jne fc_ret_c ;ждем только '-' jmp fc_save fc_4: or al, 20h ;сделаем маленькой cmp al, 'e' jne fc_ret_c ;ждем только 'e' jmp fc_save fc_3: or al, 20h cmp al, 'e' jne fc_067 ;если не 'e', то на вставку цифры mov al, '0' ;дополним одним 0 fc_save_0: call fc_save mov al, 'e' jmp fc_save ;и вставим 'e' fc_2: or al, 20h cmp al, 'e' jne fc_067 ;если н е 'e', то на вставку цифры fc_save_00: mov al, '0' call fc_save ;дополним двумя 0 jmp fc_save_0 fc_1: cmp al, '.' je fc_save ;если точка, то вставляем or al, 20h cmp al, 'e' jne fc_ret_c ;если не 'e', то ошибка mov al, '.' call fc_save ;дополним точкой и двумя 0 jmp fc_save_00 fc_ret_c: stc ;ошибка ret floatCode endp
;вывод рамки с максимум 3-х значным целым числом ;Параметры: ;IXStart - X координата начала вывода текста ;IYStart - Y координата начала вывода текста ;pPrompt - адрес строки в начале рамки ;INum - число ;icolor1 - цвет числа ;icolor2 - цвет рамки и текста PrInt proc IXStart:word, IYStart:word, pPrompt:word, INum:word, \ icolor1:word, icolor2:word local sBuffer:byte:8, \ left:word, right:word, \ top:word, bottom:word
;нарисуем рамку, для этого посчитаем границы рамки mov ax, I XStart sub ax, 2 ;2 точки влево от начала вывода текста mov left, ax add ax, 8*5+4 ;5 символов по 8 точек + 2 влево + 2 вправо mov right, ax mov cx, IYStart sub cx, 2 ;2 точки вверх mov top, cx add cx, 8+3 ;8 точек на символ + 2 вверх + 1 вниз mov bottom, cx call line, left, top, right, top, iColor2 ;сверху call line, right, top, right, bottom, iColor2 ;справа call line, left, top, left, bottom, iColor2 ;слева inc right ;иначе почему-то ;не рисуется одна точка :( call line, left, bottom, right, bottom, iColor2 ;снизу
call PrintText, IXStart, IYStart, pPrompt, iColor2 ;выводим подсказку lea ax, sBuffer call itoa, INum, ax ;преобразуем число в текст lea ax, sBuffer mov cx, IXStart add cx, 8*2 ;обойдем подсказку call Clear, cx, IYStart, 3 ;очистим 3 знакоместа call PrintText, cx, IYStart, ax, iColor1 ;выведем 3 символа числа ret PrInt end p
;вывод рамки с 8-ми символьным вещественным числом ;Параметры: ;IXStart - X координата начала вывода текста ;IYStart - Y координата начала вывода текста ;pPrompt - адрес строки в начале рамки ;PFNum - адрес вещественного числа ;icolor1 - цвет числа ;icolor2 - цвет рамки и текста PrFloat proc IXStart:word, IYStart:word, pPrompt:word, pFNum:word, \ icolor1:word, icolor2:word local PFValue:dword, PFExp:word, \ PFw:word, \ PFleft:word, PFright:word, \ PFtop:word, PFbottom:word
;разберем число на мантиссу и десятичный порядок lea ax, PFValue ;адрес мантиссы lea cx, PFExp ;адрес порядка call XTRACTR, pFNum, offset c10, ax, cx
;нарисуем рамку, для этого посчитаем границы рамки mov ax, IXStart sub ax, 2 mov PFleft, ax add ax, 8*10+4 ;10 символов mov PFright, ax mov cx, IYStart sub cx, 2 mov PFtop, cx add cx, 8+3 mov PFbottom, cx call line, PFleft, P Ftop, PFright, PFtop, iColor2 call line, PFright, PFtop, PFright, PFbottom, iColor2 call line, PFleft, PFtop, PFleft, PFbottom, iColor2 inc PFright call line, PFleft, PFbottom, PFright, PFbottom, iColor2
;подсказка call PrintText, IXStart, IYStart, pPrompt, iColor2 ;выведем мантиссу, для этого умножим на 100 и выведем, как целое, и вставим точку fld PFValue ;загружаем мантиссу fmul c100 ;*100 fistp PFw ;в целое lea ax, sfBuf ;буфер call itoa, PFw, ax ;в строку ;вставим точку после первого знака mov ax, word ptr sfBuf+1 mov word ptr sfBuf+2, ax mov byte ptr sfBuf+1, '.' ;добавляем пордок mov byte ptr sfBuf+4, 'e' lea di, sfBuf+5 ;адрес порядка mov ax, PFExp ;порядок test ax, ax ;проверим на знак jns PrExp mov byte ptr [di], '-';минус inc di neg ax ;модуль PrExp: call itoa, ax, di ;в строку mov cx, IXStart ;позиция вывода add cx, 8*2 ;после подсказки call Clear, cx, IYStart, 8 ;очищаем 8 символов числа call PrintText, cx, IYStart, offset sfBuf, iColor1 ;вывод им call strlen, offset sfBuf ;считаем длину строки mov iLen, ax ;сохраняем ret PrFloat endp
;выводим текст ;параметры: ;xxStart - X координата начала вывода текста ;yyStart - Y координата начала вывода текста ;pStr - адрес строки ;TextColor - цвет PrintText proc xxStart:word, yyStart:word, pStr:word, TextColor:word uses bx, di, si local GenTable:dword ;прочитаем в es:bp длинный адрес таблицы генератора символов push es bp mov ax, 1130h mov bh, 3 int 10h mov ax, bp pop bp mov word ptr GenTable, ax ;сохраним mov word ptr GenTable+2, es pop es mov ax, 320 ;посчитаем адрес начала вывода mul yyStart ;строка add ax, xxStart ;колонка mov di, ax ;смещение в видеобуфере mov si, pStr ;адрес строки PT_loop: push di lodsb ;очередной символ cmp al, 0 ;конец строки je PT_ret push ds si ;нарисуем символ по таблице lds bx, GenTable ;адрес таб лицы mov ah, 0 ;байт в слово shl ax, 3 ;на символ 8 байт mov si, ax ;смещение в таблице генератора mov ax, TextColor ;цвет mov cx, 8 ;8 строк PT_line_loop: push cx mov ah, [bx+si] ;маска 8 точек в строке inc si mov cx, 8 ;8 точек в строке PT_column_loop: shl ah, 1 ;смотрим очередной бит jnc PT_column_next mov es:[di], al ;1 - выводим точку PT_column_next: inc di ;на следующую точку в строке loop PT_column_loop add di, 320-8 ;на начало в следующей строке pop cx ;число строк loop PT_line_loop ;по строкам
pop si ds pop di add di,8 ;начало для следующего символа jmp PT_loop ;на следующий символ
PT_ret: pop di ret PrintText endp
;очистка X_count символов 8х8, начиная с (X_start, Y_Start) Clear proc X_start:word, Y_Start:word, X_count:word uses di, cx, ax ;находим стартовый адрес mov ax, 320 mul Y_Start ;строка add ax, X_start ;колонка mov di, ax ;адрес
mov bx, X_Count ;число байт в строке равно shl bx, 3 ; число символов * 8 байт на символ mov dx, 320 ;приращение sub dx, bx ; для следующей строки mov al, 0 ;вытираем черным цветом mov cx, 8 ;число строк Cl_loop: push cx mov cx, bx ;в строке rep stosb add di, dx ;на следующую строку pop cx loop Cl_loop ret Clear endp
;преобразование числа NNum в строку [pSStr] itoa proc NNum:word, pSStr:word uses bx, di xor cx, cx ;счетчик цифр mov di, pSStr ;куда писать mov bx, 10 ;делим на 10 mov ax, NNum ;число i_div: xor dx, dx div bx ;в dx очередная младшая цифра push dx ;сохраним в стеке inc cx ;считаем test ax, ax ;еще есть? jnz i_div i_save: pop ax ;извлекаем, начиная со старшей or al, '0' ;делаем символ mov [di], al ;сохраняем inc di ;для следующего loop i_save mov byte p tr ss:[di], 0 ;закрываем 0 ret itoa endp
;вывод черточек с надписями на оси абсцисс, начиная с wStart до wEnd цветом clr gor proc wStart:word, wEnd:word, clr:word local sBuf:byte:8
mov bx, VStep ;коэффициент масштабирования gor_loop: mov ax, wStart xor dx, dx div bx mov di, ax ;переведем в экранные координаты
;рисуем черточку (di,188)-(di,190) call line, di, 188, di, 190, clr
;преобразуем число в строку lea ax, sBuf call itoa, wStart, ax sub di, 15 ;левее черточки на 15 lea ax, sBuf ;выводим число, как текст ниже оси абсцисс call PrintText, di, 192, ax, clr
;на следующую черточку mov ax, wStart add ax, 1000 mov wStart, ax cmp ax, wEnd ;дошли до конца? jbe gor_loop ret gor endp
;вывод черточек с надписями на оси ординат, начиная с wStart до wEnd цветом clr ver proc wStart:word, wEnd:word, clr:word local Num:word mov ax, 30 ;вычисляем строку (от черты до черты 30 линий) dec wEnd mul wEnd mov bx, ax ;номер первой линии (без смещения на 10) mov wEnd, 0 ;будем писать снизу вверх до 0 ver_loop: mov di, bx add di, 10 ;номер строки + смещение 10 ;черточка call line, 0, di, 2, di, clr mov ax, wStart inc wStart ;для следующей надписи add al, '0' mov Num, ax ;надпись '1'-'6' lea ax, Num lea di, [di-4] ;выше на половину символа ;надпись call PrintText, 3, di, ax, clr sub bx, 30 ;следующая строка cmp bx, wEnd ;дошли до верха? jge ver_loop ret ver endp
;Функция вычисления плотности вероятности распределения Максвелла ;Параметр: ;x - значение абсциссы (0-319), преобразуем в скорость умножением на 14 (0-4566) ;f(v) = b * a^(3/2) * v^2 * exp(-a*v^2) CalcFun proc x:word local v:word, \ ;скорость = x * 14 y:word ;переменная для получения значения из сопроцессора
fld a ;a mov ax, VStep ;14 mul x ;14*x mov v, ax ;v=14*x fimul v ;a*v fimul v ;a*v^2 fld st ;st(1)=st=a*v^2 fld a ;a fsqrt ;sqrt(a) fmulp ;st=a^(3/2)*v^2 fmul b ;st=b*a^(3/2)*v^2 fxch ;st(1)=b*a^(3/2)*v^2; st=a*v^2 FCHS ;st=-a*v^2=z
;далее, найдем exp(-a*v^2) fldl2e ;log(осн 2)e->st fmulp ;st(1)*log(осн 2)e->st fld st ;z*log[2]e->st(1) frndint ;округляем st до целого fsub st(1),st ;st(1)-=st fxch ;st(1)<->st f2xm1 ;st=(2 в степени st) - 1 fld1 ;1->st fadd ;st+=1 fscale ;exp = st * (2 в степени st(1)) fstp st(1) ;чтобы убрать значение из st(1)
fmulp ;st=b*a^(3/2)*v^2*exp(-a*v^2)
;промасштабируем для вывода на экран ;у нас получились значения 0 - 6*10^(-4) ;умножим на 3*10^5 и получим величины 0-180 ;отнимем от 190 и получим экранные 10-190, "перевернутые" (0 сверху) fmul c3_10_5 ;умножаем на коэффициент 3*10^5 fistp y ;сохраним в y mov ax, 190 ;ax = 190 sub ax, y ;ax = 190 - y ret CalcFun endp
;рис ует график, последовательно соединяя точки отрезками ;параметры: ;xmin - левая экранная координата графика ;xmax - правая экранная координата графика ;pFun - адрес функции, вычисляющей экранную координату по вертикали ;col - цвет линий Graph proc xmin:word, xmax:word, pFun:word, col:word Graph_loop: ;цикл рисования отрезков mov ax, pFun ;адрес функции call ax, xmin ;считаем y первой точки mov cx, ax ;сохраним в cx
mov ax, xmin ;найдем x соседней справа точки inc ax mov si, ax ;сохраним в s╕ cmp ax, xmax ;проверим, дошли и до правого края ja Graph_ret
mov ax, pFun ;адрес функции call ax, si ;ax = y второй точки
test cx, cx ;проверим, чтобы не выходить за 0 (за пределы экрана) jge Gr_ax xor cx, cx ;отрицательные y меняем на 0 Gr_ax: test ax, ax ;аналогично jge Gr_draw xor ax, ax Gr_draw: mov dx, ax ;когда оба 0, то игнорируем! or dx, cx jz Graph_next ;рисуем линию (xmin, cx)-(si,ax) цветом col call line, xmin, cx, si, ax, col Graph_next: mov xmin, si ;готовим xmin для следующ его шага jmp Graph_loop Graph_ret: ret Graph endp
;рисуем линию (x1,y1)-(x2,y2) цветом color Line proc uses di bx, x1:word, y1:word, x2:word, y2:word, color:byte local i:word, \ ;для работы со сопроцессором delta_x:word, \ ;длина проекции на ось абсцисс delta_y:word, \ ;длина проекции на ось ординат incx:word, \ ;приращение по X incy:word ;приращение по Y
;определим длину проекции на ось абсцисс и шаг по оси X mov ax, x2 sub ax, x1 ;ax=x2-x1;
;определим шаг по X (+1 если вперед, -1 если назад, 0 если не меняется) mov incx, 0 ;пусть incx=0 test ax, ax ;ax=delta_x jz set_delta_x ;не меняется jg set_x_1 ;вперед? dec incx ;назад, значит incx=-1 neg ax ;найдем ax=abs(delta_x) jmp set_delta_x ;на сохранение set_x_1: inc incx ;вперед, значит incx=1; set_delta_x: mov delta_x, ax ;delta_x = abs(x2-x1)
;определим длину проекции на ось ординат и шаг по оси Y mo v ax, y2 sub ax, y1 ;ax=y2-y1;
;определим шаг по Y (+1 если вперед, -1 если назад, 0 если не меняется) mov incy, 0 ;пусть incy=0 test ax, ax ;ax=delta_y jz set_delta_y ;не меняется jg set_y_1 ;вперед? dec incy ;назад, значит incy=-1 neg ax ;найдем ax==abs(delta_y) jmp set_delta_y ;на сохранение set_y_1: inc incy ;вперед, значит incy=1; set_delta_y: mov delta_y, ax ;delta_y=abs(y2-y1) ;определим большее из проекций как основное напрвление cmp ax, delta_x ;ax=delta_y jge from_y ;y будет основным cmp delta_x, 0 ;проверим, чтобы не было delta_x=0 (для точки), jz to_Line_ret ; иначе будет деление на 0 ;delta_x>delta_y && delta_x!=0 ;основное направление - по оси X fild delta_y fidiv delta_x ;st=k=(float)(delta_y/delta_x)
;for (int i=0;i<delta_x;i++) xor cx, cx ;cx=i jmp cmp_i_x ;на проверку i<delta_x x_loop: ;тело цикла mov i, cx ;запишем перем енную цикла в память (для сопроцессора) fld st ;st=st(1)=k fimul i ;st=k*i fimul incy ;st=incy*k*i call floor ;округлим до целого в большую сторону fistp i ;сохраним в переменной mov ax, i ;относительный номер строки на экране add ax, y1 ;добавим до ординаты начальной точки mov dx, 320 ;получим индекс начала строки экрана в сегменте экрана imul dx ; для этого умножим на длину в байтах одной стоки mov bx, ax ;сохраним bx=y=(y1+floor(incy*k*i))*320 ;посчитаем X mov ax, incx ;X меняется ровно на шаг приращения, imul cx ; умноженному на индекс точки add ax, x1 ;добавим абциссу начальной точки ax=x=x1+incx*i
add ax, bx ;сложим с индексом начала строки mov di, ax ;будем адресовать через di
mov al, color ;цвет точки mov es:[di], al ;рисуем!
inc cx ;на следующую точку cmp_i_x: cmp cx, delta_x ;дошли до конца? jl x_loop to_Line_ret: jmp Line_ret ;на выход from_y: ;вдоль оси Y fild delta_x fidiv delta_y ;st=k=(float)(delta_x/delta_y)
;for (int i=0;i<delta_y;i++) xor cx, cx ;cx=i jmp cmp_i_y ;на проверку i<delta_y y_loop: ;тело цикла mov ax, incy ;Y меняется ровно на шаг приращения, imul cx ; умноженному на индекс точки add ax, y1 ;добавим абциссу начальной точки ax=y=y1+incy*i mov dx, 320 ;получим индекс начала строки экрана в сегменте экрана imul dx ; для этого умножим на длину в байтах одной стоки mov bx, ax ;сохраним bx=y=(y1+incy*i)*320 ;посчитаем X mov i, cx ;запишем переменную цикла в память (для сопроцессора) fld st ;st=st(1)=k fimul i ;st=k*i fimul incx ;st=incx*k*i call floor ;округлим до целого в большую сторону fistp i ;сохраним в переменной mov ax, i ;относительный номер строки на экране add ax, x1 ;ax=x=x1+floor(incx*k*i)
add ax, bx ;сложим с индексом начала строки mov di, ax ;буд ем адресовать через di
mov al, color ;цвет точки mov es:[di], al ;рисуем!
inc cx ;на следующую точку cmp_i_y: cmp cx, delta_y ;дошли до конца? jl y_loop Line_ret: fistp i ;удалим из сопроцессора k ret Line endp
;округление до целого в большую сторону ;округление по умолчанию, до ближайщего, не устраивает floor proc local CtrlWordOld:word, CtrlWordNew:word fstcw CtrlWordOld ;сохраним управляющее слово fclex ;сбросим исключения mov CtrlWordNew, 0763h ;установим необходимое значение управляющего слова fldcw CtrlWordNew ;загружаем управляющее слово frndint ;округляем st до целого fclex ;сбросим исключения fldcw CtrlWordOld ;восстановим старое управляющее слово ret floor endp
Calc_a proc ;посчитаем a=m/(2kT) fld m fdiv c2 fdiv k fidiv T fstp a ret Calc_a endp
Calc_b proc ;посчитаем b=4/sqrt(Pi) fld c4 fldpi fsqrt fdivp fstp b ret Calc_b endp
;выделяем из вещественного числа [pFloat] ;мантиссу в [pValue] и порядок в [pExp] по осн ованию [pRadix] XTRACTR proc pFloat:word, pRadix:word, pValue:word, pExp:word local cw:word, cwdown:word
mov di, pFloat ;адрес float FLD dword ptr [di] ;грузим в сопроцессор val FTST ;проверим на знак FSTSW AX ;выгрузим слово состояния в ax sahf ;ah в регистр флагов setb bl ;FC = 1 -> bl=1 jz @end ;число = 0 -> на конец FABS ;|val| FLD1 ;1 v mov di, pRadix ;адрес основания (10) FLD dword ptr [di] ;r 1 v FYL2X ;l2r v FLD ST ;l2r l2r v FLD1 ;1 l2r l2r v FLD ST(3) ;v 1 l2r l2r v FYL2X ;l2v l2r l2r v FDIVR ;lrv l2r v ;меняем способ округления, нам надо округление вниз FNSTCW cw ;прочитаем cw mov AX, cw ;установим 01 для округления вниз bts AX, 10 ;10 бит = 1 btr AX, 11 ;11 бит = 0 mov cwdown, AX ;переменная для нового cw FLDCW cwdown ;загрузим FRNDINT ;округлили, получили порядок (e l2r v) mov di, pExp ;адрес слова, куда пишем порядок FIST word ptr [di] ;[lrv) l2r v FLDCW cw ;восстановим cw
FCHS ;-[lrv) l2r v FMUL ;-[lrv)*l2r v FLD ST ;-[lrv)*l2r -[lrv)*l2r v
FRNDINT ;[-[lrv)*l2r] -[lrv)*l2r v FSUB ST(1), ST ;[-[lrv)*l2r] {-[lrv)*l2r} v FXCH ;{-[lrv)*l2r} [-[lrv)*l2r] v F2XM1 ;(2^{-[lrv)*l2r} - 1) [-[lrv)*l2r] v FLD1 ;1 (2^{-[lrv)*l2r} - 1) [-[lrv)*l2r] v FADD ;2^{-[lrv)*l2r} [-[lrv)*l2r] v FSCALE ;r^(-e) [-[lrv)*l2r] v FMULP ST(2), ST ;[-[lrv)*l2r] v*r^(-e) FSTP ST ;v*r^(-e) test bl, 1 ;проверим знак числа jz @end FCHS ;для отрицательного ставим знак - @end: mov di, pValue ;адрес, куда сохраняем FSTP dword ptr [di] ;сохраняем мантиссу ret XTRACTR endp
end
----- Удачи! Ответ отправил: Лысков Игорь Витальевич, Модератор Ответ отправлен: 11.05.2010, 10:09 Номер ответа: 261330 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru Абонент Skype: igorlyskov Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"? | Отправить SMS #thank 261330 на номер 1151 (Россия) | Еще номера » | Вопрос № 178233: Доброго времени суток, уважаемые эксперты! Позвольте представить на ваше рассмотрение очередной проект(предварительный бюджет 700-800 р) В общих чертах задача поставлена так: Спроектировать и запрограммировать на ассемблере регулятор температуры для печи с четырьмя конфорками. Прошу откликнуться тех, кто готов взяться за этот проект. Заранее спасибо. Отправлен: 06.05.2010, 13:20 Вопрос задал: Botsman, Профессионал Всего ответов: 1 Страница вопроса » Отвечает Лысков Игорь Витальевич, Модератор : Здравствуйте, Botsman. Вот программа, реализующая упрощенную модель управления печью
Код: ;Программа регулятора температуры для печи с четырьмя конфорками
;Считаем, что для управления режимами плиты используется биты порта p1 (активный 0) ;11111110b - 0/1 - включить/выключить индикатор нагрева конфорки 1 ;11111101b - 0/1 - включить/выключить индикатор нагрева конфорки 2 ;11111011b - 0/1 - включить/выключить индикатор нагрева конфорки 3 ;11110111b - 0/1 - включить/выключить индикатор нагрева конфорки 4 ;11101111b - 0/1 - включить/выключить нагрев нагрев конфорки 1 ;11011111b - 0/1 - включить/выключить нагрев нагрев конфорки 2 ;10111111b - 0/1 - включить/выключить нагрев нагрев конфорки 3 ;01111111b - 0/1 - включить/выкл ючить нагрев нагрев конфорки 4 ;режимы порта будем хранить в регистре r7 ;посылая r7 в порт P1, отрабатываем режимы для всех конфорок сразу
stack equ 60h ;стек value equ 30h ;начальный адрес для переменных 30H-33h с ожидаемой ; температурой для каждой из конфорок. ;Предполагаем, что температура в пределах 0-255 work equ 40h ;переменная, необходимая для сравнения температур
key equ 0 ;начальный адрес в памяти (0-3) для считывания состояния ;каждой из четырех ручек, ;(это могут быть физически, например, четыре регистра) ;возможны четыре положения каждой из ручек, которые ;определяются битами D0-D3: ;11111110b - положение 0 - выключить ;11111101b - положение 1 - нагреть условно до 80 градусов ;11111011b - положение 2 - нагреть условно до 100 градусов ;11110111b - положение 3 - нагреть условно до 120 градусов temp equ 20h ;начальный адрес в памяти (20h-23h) для считывания ; температуры с температурных датчиков.
temp_0 equ 0 ;условные температуры для 4-х положений temp_1 equ 80 temp_2 equ 100 temp_3 equ 120 ;начало программы с адреса 0 mov sp,#stack ;инициируем вершину стека, изначально sp=#7 call init ;все выключаем main: mov p1,r7 ;отработать режимы
;читаем положение ручек управления mov dptr,#key ;начальный адрес для считывания положения ручек mov r0,#value ;начальный адрес массива переменных, куда запишем ожидаемые ; значения температуры mov r3,#0feh ;маска для бита в байте режимов (r7) mov r2,#4 ;счетчик цикла (четыре конфорки) KeyLoop: call GetKey ;отработаем для одной конфорки djnz r4,KeyLoop ;r4=r4-1; циклим, пока r4!=0
;проверяем температуры конфорок mov dptr,#temp ;начальный адрес для считывания значения термодатчиков mov r0,#value ;начальный адрес массива переменных, где ожидаемые ; значения температуры mov r3,#0feh ;ма ска для бита в байте режимов (r7) mov r2,#4 ;счетчик цикла (четыре конфорки) TempLoop: call GetTemp ;отработаем для одной конфорки djnz r4,TempLoop ;r4=r4-1; циклим, пока r4!=0
jmp main ;на повтор
;- подпрограммы ------------------------------------------ init: ;начальная инициализация mov r7,#0ffh ;режимы - все выключить
mov r0,#value ;обнулим, на всякий случай, массив температур mov r4,#4 init_loop: mov @r0,#temp_0 ;пишем по адресу в r0 значение temp_0 inc r0 ;на следующий адрес djnz r4,init_loop ;по всем ret
;считываем значение положения одной ручки GetKey: movx a,@dptr ;читаем память с состоянием ручки jb acc.0,GK_1 ;если бит D0=1, то проверяем дальше ;положение 0 - выключить mov @r0,#temp_0 ;запишем значение температуры 0 (на всякий случай) ;по большому счету, это значение не используется, ;положение выключить отрабатывается по-особому, ;но и не помешает...
;для положения 0 гасим индикатор и выключаем обогреватель... mov a,r3 ;a = маске для включения индикатора (нап ример, 0feh) swap a ;маска бита в старшей тетраде для обогревателя (0efh) anl a,r3 ;маска включения для индикатора и обогревателя (0eeh) cpl a ;маска для выключения (11h)! orl a,r7 ;выключаем режимы mov r7,a ;сохраняем jmp GK_ret ;на выход GK_1: jb acc.1,GK_2 ;проверяем бит D1 положения 1, если D1=1, то проверяем дальше mov @r0,#temp_1 ;значение ожидаемой температуры положения 1 jmp GK_IndOn ;и на общую часть отработки GK_2: jb acc.2,GK_3 ;проверяем бит D2 положения 2, если D2=1, то проверяем дальше mov @r0,#temp_2 ;значение ожидаемой температуры положения 2 jmp GK_IndOn GK_3: jb acc.3,GK_ret ;проверяем бит D3 положения 3, если D3=1, то на выход ; (если ничего не встретилось, значит ручка в ; промежуточном состоянии, например, крутится) mov @r0,#temp_3 ;значение ожидаемой температуры положения 3 ;общая часть отработки GK_IndOn: ;включаем индикацию нагрева mov a,r7 ;старое с остояние anl a,r3 ;накладываем маску по "и" mov r7,a ;сохраняем
GK_ret: ;коррекция маски и адресов для следующей конфорки mov a,r3 ;сдвинем маску setb c ;чтобы "вдвинуть" единицу rlc a ;сдвигаем влево на 1 бит, С=1 попадает в младший mov r3,a ;сохраняем inc dptr ;адрес состояния ручек inc r0 ;адрес для хранения значения ожидаемой температуры ret
;проверяем показания термодатчиков и управляем обогревателями GetTemp: ;проверим, надо ли управлять обогревателем mov a,r3 ;маска интересуемой конфорки orl a,r7 ;"или" с состоянием вкл/выкл индикатора xrl a,r3 ;xor даст 0, только если оба бита нуля (остальные = 1) ;т.е. нужная конфорка и она должна греть! jz GT_Temp ; на управление
GT_off: ;выключаем обогреватель mov a,r3 ;маска конфорки swap a ;на место управления обогревателем (меняем местами тетрады) cpl a ;0 -> 1 orl a,r7 ;выключаем mov r7,a ;сохраняем jmp GK_ret GT_Temp: ;управляем movx a,@dptr ;читаем показание термодатчика в aккумулятор mov work,@r0 ;читаем ожидаемое значение температуры cjne a,work,GT_cmp ;сравниваем, != идем на метку jmp GK_ret ;равно - ничего не делаем GT_cmp: ;проверим, меньше или больше jnc GT_off ;если показания термодатчика больше, то выключаем GT_on: ;если меньше, то включаем mov a,r3 ;маска конфорки swap a ;на место управления обогревателем (меняем местами тетрады) anl a,r7 ;включаем mov r7,a ;сохраняем jmp GK_ret ;на коррекцию маски и адресов для следующей конфорки
end
----- Удачи! Ответ отправил: Лысков Игорь Витальевич, Модератор Ответ отправлен: 12.05.2010, 13:25 Номер ответа: 261350 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru Абонент Skype: igorlyskov
Оценка ответа: 5 Комментарий к оценке: Спасибо! Подробности - письмом ;) Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"? | Отправить SMS #thank 261350 на номер 1151 (Россия) | Еще номера » | Оценить выпуск » Нам очень важно Ваше мнение об этом выпуске рассылки! Скажите "спасибо" эксперту, который помог Вам! Отправьте СМС-сообщение с тестом #thank НОМЕР_ОТВЕТА на короткий номер 1151 (Россия) Номер ответа и конкретный текст СМС указан внизу каждого ответа. Полный список номеров » * Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи. (полный список тарифов) ** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются. *** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании. |
Комментариев нет:
Отправить комментарий