Вопрос № 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 - остаток
;кодировка кода на иникатор ;на входе 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
* Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи.
(полный список тарифов)
** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
*** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.