Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

RFpro.ru: Ассемблер? Это просто! Учимся программировать


Хостинг портала RFpro.ru:
Московский хостер
Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64

РАССЫЛКИ ПОРТАЛА RFPRO.RU

Лучшие эксперты данной рассылки

Boriss
Статус: Академик
Рейтинг: 2648
∙ повысить рейтинг »
Абаянцев Юрий Леонидович aka Ayl
Статус: Профессионал
Рейтинг: 2372
∙ повысить рейтинг »
vladisslav
Статус: 8-й класс
Рейтинг: 1335
∙ повысить рейтинг »

/ КОМПЬЮТЕРЫ И СОФТ / Программирование / Assembler (Ассемблер)

Номер выпуска:1431
Дата выхода:30.03.2011, 15:30
Администратор рассылки:Лысков Игорь Витальевич (Старший модератор)
Подписчиков / экспертов:216 / 67
Вопросов / ответов:1 / 1

Вопрос № 182543: Здравствуйте, уважаемые эксперты! Прошу Вас помочь с решением следуюшей задачи: - написать программу в среде MPLab для микроконтроллера PIC16F84. Общая задача такова: в программу на компьютере вводятся 2 числа и операция между ними (наприме...



Вопрос № 182543:

Здравствуйте, уважаемые эксперты! Прошу Вас помочь с решением следуюшей задачи:
- написать программу в среде MPLab для микроконтроллера PIC16F84.
Общая задача такова: в программу на компьютере вводятся 2 числа и операция между ними (например, 2+3), далее это отправляется на COM порт, к которому подключен микроконтроллер. Он принимает данные, выполняет требуемую операцию с этими числами, выводит результат на индикатор-семисегментик, а также отправляет этот результат обратно в COM порт, передавая его компьютеру. То есть это, своего рода, программа "калькулятор" ...

Просьба к Вам, уважаемые эксперты, помочь с решением той части задачи, которую выполняет микроконтроллер, то есть написать программу для микроконтроллера. Надеюсь на Вашу помощь!

p.s.: Только арифметические операции "+", "-", "*","/".

Отправлен: 17.03.2011, 13:47
Вопрос задал: Dmitry (Посетитель)
Всего ответов: 1
Страница вопроса »


Отвечает Лысков Игорь Витальевич (Старший модератор) :
Здравствуйте, Dmitry!
Вот и программа, которая принимает три байта (два знаковых числа и код операции) по RS-232С,
считает, выдает на индикатор результат и передает результат обратно
Сделан минимальный контроль: код операции (1-4) и на деление на 0
Для вывода на монитор я воспользовался ранее написанной программой...
Пробуйте

Код:
;Программа калькулятора
;Программа принимает от компьютера по каналу RS-232C три байта:
;первый операнд, второй операнд, код операции
;1 = +, 2 = -, 3 = *, 4 = /
;После чего считает, выводит на индикатор и передает обратно байт результ ата
;Проверяется код операции, деление на 0
;
;Параметры RS-232C:
;скорость 9600 бод, 1 стоп-бит, без контроля четности
;выдержки времени рассчитаны для цикла 1 мкс
;------------------------------------------------------
;Установка типа процессора
LIST P=16F84
;------------------------------------------------------
;Регистры специального назначения
STATUS EQU 03h ;регистр статуса
PORTB EQU 06h ;порт В
PCL EQU 02h ;регистр программного счетчика
;------------------------------------------------------
;Биты регистра STATUS
RP0 EQU 5h ;бит выбора страницы
Z EQU 2h ;номер бита Z в статусе
C EQU 0h ;номер бита С в статусе
;------------------------------------------------------
;Управляющие регистры портов ввода-вывода
TRISB EQU 6h
;------------------------------------------------------
;ОЗУ
;рабочие регистры для приема/передачи
WORK1 EQU 0Eh
WORK 2 EQU 0Fh
WORK3 EQU 10h
;аргументы калькулятора
ARG1 EQU 11h
ARG2 EQU 12h
;рабочие регистры для вывода на дисплей
CNT_1 EQU 13h ;счетчики
CNT_2 EQU 14h
CNT_3 EQU 15h
CNT_4 EQU 16h
W1 EQU 17h ;временные регистры для расчетов
W2 EQU 18h
W3 EQU 19h
;------------------------------------------------------
;биты регистра PORTB
DAT EQU 4h ;бит данных (порт В)
SYN EQU 5h ;бит синхронизации (порт В)
RS232TX EQU 6h ;передатчик RS-232C
RS232RX EQU 7h ;приемник RS-232C
;
;------------------------------------------------------
; Программа
;------------------------------------------------------
ORG 0h ;начало кода
GOTO START
ORG 4h ;программа обработки прерываний
RETFIE ;отсутствует
;
START
BSF STATUS,RP0 ;настройка порта PORTB
MOVLW B'10001111' ;установка RB4-RB6 на вывод
MOVWF TRISB
BCF STATUS,RP0
< br />;установка битов в 1
BSF PORTB,DAT ;бит данных индикации
BSF PORTB,SYN ;бит синхро индикации
BSF PORTB,RS232TX ;передатчик RS-232С

;основной цикл программы
LOOP1 ;принимаем первый аргумент
BTFSC PORTB,RS232RX ;ожидание старт-бита
GOTO LOOP1 ; принимаемых данных
CALL RX232 ;прием байта в WORK1 и в аккумулятор
MOVWF ARG1 ;сохраним в ARG1

LOOP2 ;принимаем второй аргумент
BTFSC PORTB,RS232RX ;ожидание старт-бита
GOTO LOOP2 ; принимаемых данных
CALL RX232 ;прием байта в WORK1 и в аккумулятор
MOVWF ARG2 ;сохраним в ARG2

LOOP3 ;принимаем код операции
BTFSC PORTB,RS232RX ;ожидание старт-бита
GOTO LOOP3 ; принимаемых данных
CALL RX232 ;прием байта в WORK1 и в аккумулятор

;определимся с операцией
;результат всех операций будет в ARG1
DECFSZ WORK1,1 ;1 = +
GOTO CMPSUB ;проверим на -
CALL PLUS ;отработаем +< br /> GOTO OUTPUT ;на вывод результата
CMPSUB
DECFSZ WORK1,1 ;2 = -
GOTO CMPMUL ;проверим на *
CALL MENUS ;отра ботаем -
GOTO OUTPUT ;на вывод результата
CMPMUL
DECFSZ WORK1,1 ;3 = *
GOTO CMPDIV ;проверим на /
CALL MULT ;отработаем *
GOTO OUTPUT ;на вывод результата
CMPDIV
DECFSZ WORK1,1 ;4 = /
GOTO PRERR ;все остальное на вывод ошибки Err1
CALL DIVIDE ;отработаем /
GOTO TRANS ;на передачу (вывод на экран внутри DIVIDE)
PRERR ;вывод сообщения об ошибке
MOVLW D'1' ;1 - номер ошибки
CALL ERR ;Err1
CLRW ;вернем 0
GOTO TRANS ;на передачу
OUTPUT
CALL DISPLAY ;вывод знакового числа из ARG1 на дисплей
TRANS
CALL TX232 ;передача байта из ARG1
GOTO LOOP1 ;на повтор
;
PLUS ;ARG1 = ARG1 + ARG2
MOVFW ARG2
ADDWF ARG1,1
RETURN
;
MENUS ;ARG1 = ARG1 - ARG1
MOVFW ARG2
SUBWF ARG1,1
RETURN
;
MULT ;ARG1 = ARG1 * ARG2
MOVFW ARG1 ;проверим на равенство нулю операндов
ANDWF ARG2,0 ;если хоть один = 0, то и произведение = 0
BTFSC STATUS,Z ;проверяем бит нуля, если Z = 0, то ответ 0
GOTO MULTNEXT ;на умножение
CLRF ARG1 ;результат 0
RETURN
MULTNEXT ;умножаем, складывая ARG1 ARG2 раз
MOVFW ARG1 ;W = ARG1
CLRF ARG1 ;ARG1 - здесь будем накапливать сумму
MULTLOOP
ADDWF ARG1,1 ;ARG1 = ARG1 + W
DECFSZ ARG2,1 ;ARG2 раз
GOTO MULTLOOP
RETURN
;
DIVIDE ;ARG1 = ARG1 / ARG2
MOVFW ARG2 ;проверим на равенство нулю делителя
ANDWF ARG2,0 ;если = 0, то ошибка Err2
BTFSC STATUS,Z ;проверяем бит нуля, если Z = 0, то ошибка 2!
GOTO DIVNEXT ;на деление
MOVLW '2'
CALL ERR ;сообщение об ошибке
CLRF ARG1 ;возвращаем 0
RETURN
DIVNEXT ;для деления воспользуемся подпрограммой DIVISION
MOVFW ARG1 ;для чего запишем делимое
MOVWF W1 ;в W1
MOVFW ARG2 ;а делитель - в W
CALL DIVISION ;результат: W1 - частное, W - остаток
MOVFW W1 ;сохраним частное
MOVWF ARG1 ;в ARG1
CALL DISPLAY ;на дисплей
RETURN
;
DISPLAY ;вывод знакового числа ARG1 на дисплей
MOVLW d'3' ;3 цифры
MOVWF CNT_1 ;CNT_1 - счетчик цифр
MOVF ARG1,0 ;W = ARG1
BTFSS ARG1,7 ;проверяем старший бит - бит знака
GOTO POSITIVE ;ARG1.7 = 0 - >0
COMF ARG1,0 ;найдем модуль числа
ADDLW D'1' ; W = (not ARG1) + 1
POSITIVE:
MOVWF W1 ;W1 = W = ARG1

;цикл вывода десятичных знаков
M01 MOVLW d'10' ;будем делить W1 на 10 и получать в W остаток
CALL DIVISION ; от деления - очередной младший разряд
CALL CODE_SEG ;конвертируем число в сегментный код
CALL OUT_SEG ;зажигаем нужные сегменты
DECFSZ CNT_1,1 ;CNT_1 = CNT_1 - 1, если 0, то на RETURN
GOTO M01 ;иначе повторяем
;выведем знак числа
MOVLW D'10' ;пусто - для положительны х
BTFSS ARG1,7 ;проверяем старший бит - бит знака
GOTO DISPSIGN ;>0 идем на вывод
MOVLW D'11' ;- для отрицательных
DISPSIGN
CALL CODE_SEG ;конвертируем число в сегментный код
CALL OUT_SEG ;зажигаем нужные сегменты
RETURN ;выход

;вывод цифры (отработка сегментов, заданных в регистре W)
OUT_SEG
MOVWF W2 ;W2 = W
MOVLW d'8'
MOVWF CNT_2 ;CNT_2 = 8 - число бит

;цикл по битам
M03 BCF PORTB,DAT ;установка в 0 RB4 (чтобы горело)
BTFSC W2,0 ;если 0 бит в регистре W2 = 0, то пропускаем
BSF PORTB,DAT ;команду, если нет, то установка RB4 в 1 (чтобы потухло)

; синхронизация PORTB
BCF PORTB,SYN
BSF PORTB,SYN

RRF W2,1 ;сдвиг вправо на 1 бит
DECFSZ CNT_2,1 ;по всем 8 битам
GOTO M03 ;повтор
RETURN

;деление W1 на W
;находим путем последовательного вычитания
;делителя из делимого
;р езультат: W1 - частное, W - остаток
DIVISION
MOVWF W2 ;сохраним W в W2, т.к. след команда его портит
MOVF W1,0 ;W = W1< br /> MOVWF W3 ;W3 = W = W1 - делимое
MOVF W2,0 ;восстановим W = W2 - делитель
CLRF W1 ;W1 = 0 - частное, как количество вычитаний делителя

;цикл вычитания делителя из делимого
;вычитание заменяется сложением с кодом в дополнительном коде
;т.е. 5-2 = 5+0feh = 3 и С=1
; 1-2 = 1+0feh = 0ffh и C=0
;т.о., C=1 означает, что отнимается, а С=0 - нет

M04 SUBWF W3,1 ;W3 = W3 - W
BTFSC STATUS,C ;проверяем бит переноса, если C = 0, то на выход
GOTO M05 ;на инкремент частного
ADDWF W3,0 ;добавим лишний раз отнятый делитель, результат в W
RETURN ;имеем в W1 частное, а W - остаток

M05 INCF W1,1 ;считаем отнятые делители
GOTO M04 ;продолжаем

;кодировка кода на иникатор
;на входе W = 0-9
;10 - знак пусто (для положительных)
;11 - знак минус (для отрицательных)
;12 - символ 'E' (для сообщения Err)
;13 - символ 'r' (для сообщения Err)< br />;на выходе код
CODE_SEG
ADDWF PCL,1 ;переход на адрес следующей команы + содержимое W
RETLW b'00000011' ;0
RETLW b'10011111' ;1
RETLW b'00100101' ;2
RETLW b'00001101' ;3
RETLW b'10011001' ;4
RETLW b'01001001' ;5
RETLW b'01000001' ;6
RETLW b'00011111' ;7
RETLW b'00000001' ;8
RETLW b'00001001' ;9
RETLW b'11111111' ;ничего не горит (для +)
RETLW b'11111101' ;-
RETLW b'01100001' ;E
RETLW b'11110101' ;r

ERR ;вывод сообщения об ошибке
;в W число - код ошибки
CALL CODE_SEG ;конвертируем число в сегментный код
CALL OUT_SEG ;зажигаем нужные сегменты
MOVLW D'13' ;r
CALL CODE_SEG ;конвертируем число в сегментный код
CALL OUT_SEG ;зажигаем нужные сегменты
MOVLW D'13' ;r
CALL CODE_SEG ;конвертир уем число в сегментный код
CALL OUT_SEG ;зажигаем нужные сегменты
MOVLW D'12' ;E
CALL CODE_SEG ;конвертируем число в сегментный код
CALL OUT_SEG ;зажигаем нужные сегменты
RETURN

;----------------------------------------------------
;Подпрограммы приема-передачи
;----------------------------------------------------
;Подпрограмма приема байта в регистр WORK1 и W по RS-232C
RX232
CLRF WORK1 ;очистка приемника байта
;
MOVLW D'49' ;пауза 148 мкс для выхода
MOVWF WORK3 ;примерно на середину интервалов
R00
DECFSZ WORK3,1 ;принимаемых битов
GOTO R00
;
MOVLW 8h ;счетчик принимаемых битов
MOVWF WORK2
R01
RRF WORK1,1 ;сдвиг приемника байта
BTFSS PORTB,RS232RX ;принятый бит равен 1 ?
GOTO R02 ;нет!
BSF WORK1,7 ;да! установить очередной бит в 1
GOTO R03 ;приемника байта
R02
NOP ;задержка, выравни вающая время приема 0 и 1
BCF WORK1,7 ;принятый бит = 0
;
R03
MOVLW D'31' ;пауза 95 мкс, дополняющая время
MOVWF WORK3 ;приема бита до 104 мкс
R04
DECFSZ WORK3,1
GOTO R04
NOP
;
DECFSZ WORK2,1 ;по всем битам
GOTO R01
;
MOVFW WORK1 ;W = WORK1
RETURN

;подпрограмма передачи байта из регистра ARG1 по RS-232C.
TX232
BCF PORTB,RS232TX ;передача старт-бита
MOVLW D'33' ;пауза 100 мкс, дополняющая время
MOVWF WORK2 ;передачи старт-бита до 104 мкс
W00
DECFSZ WORK2,1
GOTO W00
;
MOVLW 8h ;будем передавать 8 бит
MOVWF WORK2
W01
BTFSS ARG1,0 ;очередной бит = 1 ?
GOTO W02 ;-нет!
BSF PORTB,RS232TX ;-да!
GOTO W03
W02

BCF PORTB,RS232TX ;бит = 0
NOP ;задержка, выравнивающая время передачиа 0 и 1
W03
RRF ARG1,1 ;сдвиг передаваемого байта для передачи сл едующего бита
;
MOVLW D'31' ;пауза 95 мкс, дополняющая время
MOVWF WORK3 ;приема бита до 104 мкс
W04
DECFSZ WORK3,1
GOTO W04
NOP
;
DECFSZ WORK2,1 ;по всем битам
GOTO W01
;
BSF PORTB,RS232TX ;передача стоп-бита
MOVLW D'34' ;пауза, дополняющая время
MOVWF WORK3 ;передачи стоп-бита до 104 мкс
W05
DECFSZ WORK3,1
GOTO W05
RETURN

END

-----
Люби своего ближнего, как самого себя

Ответ отправил: Лысков Игорь Витальевич (Старший модератор)
Ответ отправлен: 24.03.2011, 16:26
Номер ответа: 266382
Украина, Кировоград
Тел.: +380957525051
ICQ # 234137952
Mail.ru-агент: igorlyskov@mail.ru

Вам помог ответ? Пожалуйста, поблагодарите эксперта за это!
Как сказать этому эксперту "спасибо"?
  • Отправить SMS #thank 266382 на номер 1151 (Россия) | Еще номера »
  • Отправить WebMoney:


  • Оценить выпуск »
    Нам очень важно Ваше мнение об этом выпуске рассылки!

    Задать вопрос экспертам этой рассылки »

    Скажите "спасибо" эксперту, который помог Вам!

    Отправьте СМС-сообщение с тестом #thank НОМЕР_ОТВЕТА
    на короткий номер 1151 (Россия)

    Номер ответа и конкретный текст СМС указан внизу каждого ответа.

    Полный список номеров »

    * Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи. (полный список тарифов)
    ** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
    *** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.



    В избранное