Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методическое руководство по PIC- Набор регистро....doc
Скачиваний:
14
Добавлен:
02.05.2019
Размер:
149.5 Кб
Скачать

Incfsz f,d

Когда Вы приобретете некоторый опыт работы с ассемблером PIC, Вы будете использовать эти команды очень часто. При d=1 команда DECFSZ уменьшает на единицу, а INCFZ увеличивает на единицу заданный регистр и пропускает·следующую·команду, если регистр 'стал равным нулю. При d=0 результат записывается в регистр W и следующая команда, пропускается, если рабочий регистр W стал равным нулю. Эти команды используются для формирования временных задержек, счетчиков, циклов и т.д. Вот типичный пример использования цикла:

START

MOVLW 0FFh ;Загрузить 0FFh в регистр W

MOVWF SCRATCH ;Загрузить регистр W в SCRATCH

LOOP

DECFSZ SCRATCH, l ;Уменьшить SCRATCH на 1

GOTO LOOP ;и переходить обратно, пока не станет =0

MOVF DIGIT,0 ;Загрузить регистр DIGIT в W

MOVWF DATAPORT ;Вывести на светодиоды

DECF DIGIT, l ;Уменьшить DIGIT на 1

GOTO START ;Перейти на начало

В результате светодиоды будут мигать с различной частотой. Светодиод младшего разряда будет мигать чаще всего, а светодиод старшего разряда реже всего. При тактовой частоте 4 МГц частота миганий светодиода старшего разряда будет примерно 8 Гц а каждый следующий будет мигать вдвое чаще. Теперь разберемся, как это у нас получилось. Команда DECFSZ здесь работает в цикле задержки, состоящем из двух команд - DECFSZ и GOTO LOOP. Поскольку мы предварительно загрузили в регистр SCRAТСН значение 0FFh, этот цикл выполнится 255 раз, пока SCRAТСН не станет равным нулю. При тактовой частоте 4 МГц это дает задержку 1 мксек/команду * 2 команды * 255 = 510 мксек. В регистр DIGIT мы предварительно ничего не записывали, поэтому там могло находиться любое значение, которое и выводится на светодиоды на первом проходе. Затем регистр DIGIТ уменьшается на 1 и цикл повторяется сначала. В результате регистр DIGIT перебирает все значения за 256 циклов, т.е. за примерно за 130 мсек.

Тот же код можно использовать и с командой INCFSZ, заменив загружаемое в регистр SCRAТСН значение с FFh на 0h. Светодиоды будут мигать точно так же и если заменить команду DECF на команду INCF.

SWAPF f,d

Эта команда меняет местами полубайты в любом регистре. Как и для других команд, при d=0 результат записывается в рабочий регистр W а при d=1 остается в регистре. Вот простой пример использования этой команды:

MOVLW B'00001111' ;Загрузить 00001111 в регистр W

MOVWF DATAPORT ;Загрузить регистр W в DATAPORT

SWAPF DATAPORT, l ;Поменять полубайты

Светодиоды покажут 11110000.

RRF f,d

RLF f,d

В ассемблере РIС имеется две команды сдвига - сдвиг вправо через бит CARRY любого регистра RRF и сдвиг влево через бит CARRY любого регистра RRF. Как и для других команд, при d=O результат сдвига записывается в регистр W, а при d=1 остается в регистре. Инструкции сдвига используются для выполнения операций умножения и деления, для последовательной передачи данных и для других целей. Во всех случаях бит, сдвигаемый из 8-битного регистра, записывается в бит CARRY в регистре STATUS, а бит CARRY записывается в другой конец регистра, в зависимости от направления сдвига. При сдвиге влево RLF CARRY записывается в младший бит регистра, а при сдвиге вправо RRF CARRY записывается в старший бит регистра.

BCF STATUS,0 ;Очистить бит 0 (CARRY) в регистр STATUS

MOVLW 0FFh ;Загрузить 0FFh в регистр W

MOVWF DATAPORT ;Загрузить регистр W в DATAPORT

RRF DATAPORT, l ;Сдвинуть вправо

Светодиоды должны показать 01111111, поскольку CARRY загрузился в старший бит W. Теперь сдвинем впево:

BCF STATUS,0 ;Очистить бит 0 (CARRY) в регистр STATUS

MOVLW 0FFh ;Загрузить 0FFh в регистр W

MOVWF DATAPORT ;Загрузить регистр W в DATAPORT

RRF DATAPORT, l ;Сдвинуть влево

Светодиоды должны показать 11111110.

BCF f,d

BSF f,d

Команды очистки бита BCF и установки бита BSF используются для работы с отдельными битами в регистрах. Параметр b означает номер бита, с которым производится операция, и может принимать значения от 0 до 7. Попробуем включить светодиод, используя команду BCF:

MOVLW 0FFh ;Загрузить 0FFh в регистр W

MOVWF DATAPORT ;Загрузить регистр W в DATAPORT

BCF DATAPORT,7 ;Очистить бит 7 в порте В

GOTO

в результате погаснет светодиод, соответствующий биту 7. Вспомните, мы делали аналогичные вещи при помощи использования маски и команды ANDWF. Разница в том, что команды ANDWF и IORWF требуют предварительного формирования маски и хранения ее в каком-либо регистре, но в то же время способны одновременно установить или очистить несколько бит. Команды же BCF и BSF оперируют только с одним битом. Кроме того, команды BCF и BSF не изменяют регистр состояния STA TUS, поэтому они часто используются в тех случаях, когда не требуется последующая проверка регистра состояния.

BTFSC f,d BTFSS f,d

Команды условных переходов BTFSC и BTFSS проверяют состояние заданного бита в любом регистре и в зависимости от результата пропускают или нет следующую команду. Команда BTFSC пропускает команду, если заданный бит сброшен, а команда BTFSS - если установлен. Вот простой пример:

MOVLW 0FFh ;Загрузить 0FFh в регистр W

MOVWF DATAPORT ;Загрузить регистр W в DATAPORT

MOVLW B'00000001' ;Загрузить 00000001 в регистр W

MOVWF CNTRLPORT ;Загрузить регистр W в CNTRLPORT

LOOP

BTFSS CNTPLPOPT,0 ;Проверить бит 0 в CNTRLPORT

GOTO LOOP ;Ждать пока бит 0 не установится

BCF DATAPORT, 7 ;Выключить светодиод

GOTO $ ;3ациклиться навсегда

В этом примере проверяется разряд 0 порта А (вывод 17 микросхемы) и, если этот вывод установлен в высокий уровень выключается светодиод.

Ранее мы упоминали о возможности проверки битов состояния в регистре STATUS. Это также делается при помощи команд BTFSS и BTFSC:

;Проверка бита САRRУ

BTFSS STATUS,C ;если С установлен, пропустить GOTO

GOTO WHERE_EVER ;

Аналогично проверяется бит ZERO:

;Проверка бита ZERO

BTFSS STATUS, Z ; если Z установлен, пропустить GOTO

GOTO WHERE_EVER ;

Можно с уверенностью сказать, что Вы будете использовать эти примеры очень часто.

CALL k

RETURN

Эти две команды предназначены для работы с подпрограммами. Команда CALL используется для перехода на подпрограмму по адресу, задаваемому в команде, а команда RETURN - для возврата из подпрограммы. Обе команды выполняются за 2 цикпа. Адрес, на котором находилась команда CALL запоминается в специально организованных регистрах, называемых стеком. Эти регистры недоступны для обращений и используются только при вызовах подпрограмм и возвратах. Глубина стека, т.е. число специальных регистров - 8. Поэтому из основной программы можно сделать не более 8 вложенных вызовов подпрограмм. ·После возврата из подпрограммы выполнение продолжается со следующей после CALL команды. Регистр·W и регистр STATUS при вызове подпрограммы не сохраняются, поэтому, если необходимо, их можно сохранить в отдельных ячейках памяти. Вот простой пример использования подпрограммы:

START

BSF DATAPORT,7 ;Включить светодиод

CALL PAUSE ;Вызвать подпрограмму

BCF DATAPORT, 7 ;Выключить светодиод

CALL PAUSE ;Вызвать подпрограмму

GOTO START ;Перейти на начало

;

PAUSE

MOVLW 0FFh ;Загрузить 0FFh в регистр W

MOVWF SСRAТСН ;Загрузить регистр W в SCRATCH

MOVLW 0FFh ;Загрузить 0FFh в регистр W

MOVWF DIGIT ;Загрузить регистр W в DIGIT

LOOP

DЕСFSZ SCRATCH, l ;Уменьшить SCRATCH на 1

GOTO LOOP ;И переходить обратно, пока не станет =0

DECFSZ DIGIT, l ;Уменьшить DIGIT на 1

GOTO LOOP ;И переходить на метку LOOP, пока не станет =0

RETURN ;Вернуться из подпрограммы

в результате светодиод будет мигать с частотой около 1 Гц. PAUSE - подпрограмма формирования паузы.

RETLW k

RETFIE

Существуют еще две команды, предназначенные для возврата из подпрограмм. Команда RETLW возвращает в рабочем регистре W константу, заданную в этой команде, а команда RETFIE разрешает прерывания.

CALL SHOWSYМ Вызвать подпрограмму

MOVWF DATAPORT ;Вывести элемент таблицы в порт В

GOTO $ ;3ациклиться навсегда

SHOWSYМ

RETLW 081h ;Записать 081h в W и вернуться из подпрограммы

Светодиоды должны отобразить 10111011.

СПЕЦИАЛЬНЫЕ КОМАНДЫ

Нам осталось упомянуть о двух специальных командах -CLRWDT и SLEEP. Команда CLRWDT предназначена для сброса сторожевого таймера, назначение которого мы уже обсуждали. Эта команда должна присутствовать в таких участках программы, чтобы время выполнения программы между двумя соседними командами CLRWDT не превышало времени срабатывания сторожевого таймера. Команда SLEEP предназначена для перевода процессора в режим пониженного энергопотребления. После выполнения этой команды тактовый генератор процессора выключается и обратно в рабочий режим процессор можно перевести либо по входу сброса, либо по срабатыванию сторожевого таймера, либо по прерыванию.

Пример программы

Начнем с описания базового кода, который будет использован в наших примерах. Когда Вы начинаете писать код для Вашего проекта, секция заголовка (весь код до строки с выражением ORG О) должна учитывать особенности Вашего применения. В секции заголовка определяются логические имена для всех используемых в проекте ресурсов - портов, битовых и байтовых переменных и регистров. Наш заголовок также устанавливает порты ввода/вывода, так что все разряды портов А и В будут установлены как выходы после выполнения следующих команд:

;Инициализация порта А

BCF STATUS,RP

CLRF CNTRLPORT

MOVLW INIТА

BSF STATUS,RP

MOVWF TRISA

;Инициализация порта B

BCF STATUS,RP

CLRF DATAPORT

MOVLW INIТB

BSF STATUS,RP

MOVWF TRISB

;Выбор банка О

,Очистить регистр CNTRLPORT

;Загрузить В'ОООООООО' в регистр W

;Выбор банка 1

;Все разряды порта А установить как выходы

;Выбор банка О

,Очистить регистр DATAPORT

;Загрузить В'ОООООООО' в регистр W

;Выбор банка 1

;Все разряды порта B установить как выходы

Когда включается питание, РIС16F84 устанавливает все разряды портов А и В на ввод и начинает выполнять программу с адреса 000h.

Ниже представлен базовый код.

; Пример базового кода для демонстрационной программы

;

;

; Секция заголовка

;

; Описание операционных регистров

TMRO EQU 01h

PC EQU 02h

STATUS EQU 03h

FSR EQU 04h

; регистры ввода/вывода

CNTRLPORT EQU 05h

DATAPORT EQU 06h

; ячейки ОЗУ

SCRATCH EQU 0Ch

DIGIT EQU 0Dh

; регистры ввода/вывода

C EQU 0h

DC EQU 1h

Z EQU 2h

PD EQU 3h

TO EQU 4h

RP EQU 6h

; управляющие регистры

TRISA EQU 85h

TRISB EQU 86h

; слова инициализации для ввода/вывода

INITA EQU B’00000000’

INITB EQU B’00000000’

;

; рабочая секция

;

; начало исполняемого кода

ORG 0

GOTO BEGIN

;

ORG 100h

BEGIN

BCF STATUS,RP

CLRF CNTRLPORT

MOVLW INIТА

BSF STATUS,RP

MOVWF TRISA

;Инициализация порта B

BCF STATUS,RP

CLRF DATAPORT

MOVLW INIТB

BSF STATUS,RP

MOVWF TRISB

;

BCF STATUS,RP

;

; сюда вставьте код примера

;

;

END

;Выбор банка О

,Очистить регистр CNTRLPORT

;Загрузить В'ОООООООО' в регистр W

;Выбор банка 1

;Все разряды порта А установить как выходы

;Выбор банка О

,Очистить регистр DATAPORT

;Загрузить В'ОООООООО' в регистр W

;Выбор банка 1

;Все разряды порта B установить как выходы

;Выбор банка О

Разберем подробно каждую строку кода. Во-первых, все строки, начинающиеся со знака ";" воспринимаются ассемблером как комментарии. Перейдем к выражению TMRO. Мы задали ассемблеру, что каждый раз, когда встретится слово TMRO, необходимо подставить значение 01h (01 шестнадцатеричное). Слово "EQU" означает равенство. Таким образом, мы присвоили TMRO значение 1h. Как видно из рисунка 4, регистр TMRO действительно имеет адрес 1h. Вы можете использовать 01h каждый раз, когда вы хотите адресовать регистр TMRO, но это будет значительно сложнее отлаживать, поскольку Вы должны будете все время помнить, что 01h означает RTCC. У Вас могут существовать и данные, равные 01h. Использование символьных имен устраняет двусмысленность и позволяет облегчить чтение исходного текста. Вы также можете видеть выражения для определения регистров РС, STATUS и FSR. Имя РС соответствует регистру с адресом 02h, имя STATUS соответствует регистру с адресом 0Зh, имя FSR -регистру с адресом 04h и так далее. Мы также задали имена для портов ввода/вывода, CNTRLPORT (05h) и

DАTAPORT (О6h). Ячейки ОЗУ также могут иметь имена. Мы выбрали имена "SCRAТСН" для ячейки с адресам OCh и "DIGIT" для ячейки с адресом ODh.

Если Вы прочитаете до конца этот текст, то увидите, что мы нигде не используем РС непосредственно, хотя это имя и определено. В этом нет ошибки - можно определять имена и потом не использовать их, хотя, конечно, нельзя использовать имя, если оно не было предварительно определено. Не очень тревожтесь за это - работа ассемблера как раз и заключается в проверке текста на соблюдение всех правил, и Вы получите сообщения об ошибках, если что-то не будет соответствовать.

Вы можете не только именовать регистры, но и отдельные биты внутри регистров. Обратите внимание на секцию, задающую регистр STАTUS. Символу С присвоено значение Oh, поскольку С или CARRY, это нулевой бит слова состояния STATUS. Каждый раз, когда мы должны будем проверить бит CARRY (бит 0), мы будем пользоваться предварительно определенным символом "С". Каждый раз, когда мы захотим обратиться к биту 2, или биту ZERO, мы будем использовать символ Z вместо 02h. Вы можете определить полную структуру битов регистра, даже если Вы затем не все из них будете использовать. Теперь нам стало ясно, как описываются регистры, и мы можем перейти к исполняемому коду. Перед тем, как начать исполняемый код, мы должны задать выражение ORG О. Это указатель для ассемблера, что код, следующий за этим выражением, начинается с нулевого адреса ЭППЗУ. Выражение "ORG" используется для размещения сегментов кода по различным адресам в пределах размеров ЭППЗУ. Еще одно выражение ORG находится перед меткой BEGIN, имеющей адрес 100h, как задано выражением ORG 100h. Исполняемый код должен заканчиваться директивой END, означающей, что за этой директивой отсутствуют исполняемые команды.

При включении питания PIC16F84 переходит на адрес 000h. Первая инструкция, которая будет выполнена процессором, это команда GOTO BEGIN, которая передаст управление на адрес 100h и дальнейшая работа продолжится с этого адреса. BEGIN - это выбираемое пользователем имя метки (метки всегда должны начинаться с первой позиции строки), которое ассемблер использует в качестве адресной ссылки. В процессе работы ассемблер определяет расположение метки BEGIN и запоминает, что если это имя будет встречено еще раз, вместо него будет подставлен адрес метки. Команды CALL и GOTO используют метки для ссылок в исходном тексте. Теперь посмотрим на следующие команды, выполняемые процессором. Команда MOVLW INITA загружает в рабочий регистр W значение, присвоенное имени INITA. Это значение задано в заголовке и равно B'00000000', то есть 00h. Символы B' означают, что данные заданы в двоичном формате. Можно было бы написать в этом же месте 0 (десятичный) или 0h (шестнадцатеричный) и получить тот же самый результат. Двоичное представление удобнее использовать в тех случаях, когда предполагается операция с битами в регистре.

Следующая команда MOVWF TRISA загружает значение из рабочего регистра W в регистр управления конфигурацией порта А TRISA. Задание 0 в разряде этого регистра определяет, что соответствующий разряд порта А является выходом. B нашем случае все разряды порта А устанавливаются выходами. Обратите внимание, что порт А имеет только 5 разрядов, и старшие 3 бита значения, записываемого в регистр TRISA, также имеющего 5 разрядов, не используются. Если бы мы захотели, например, установить младший разряд порта А как вход, мы бы задали в секции описания регистров значение INITA равным В'00000001'. Если по ходу работы программы нам потребуется переопределять назначение отдельных разрядов портов, например, при двунаправленной передаче, то удобнее всего задать все необходимые слова конфигурации в секции описания, как мы сделали для INITA и INITB.

Следующие две команды MOVLW INITB и MOVWF TRISB определяют конфигурацию порта B. Мы могли бы сэкономить и не писать команду MOVLW INITB, поскольку в нашем случае INIT8 также равно 0h. Однако мы не стали этого делать, поскольку это может привести к трудно обнаружимым ошибкам, если впоследствии нам потребуется изменить назначение какого-либо одного разряда. Вместо того, чтобы изменить только один разряд в одном порту, изменятся два разряда с одинаковым номером в двух портах. Поэтому пока программа не закончена, такую экономию делать не желательно, хотя в конце, на этапе оптимизации кода, такие повторы можно удалять.

Команды BCF STATUS,RP u BSF STA TUS,RP нужны для переключенuя между банками памяти. Дело в том, что вся память данных микроконтроллера разбита на два банка. Банку О соответствуют адреса 00h .. 7F, банку 1 -8F .. FF. Выбор банка определяется состоянием бита 5 в регистре STATUS. Когда этот бит установлен в 1, выбран банк 1, иначе - банк 0.