“Шапка” программы начинается с подключения специального файла с расширением INC, в виде строчки #include
Далее идет строчка с указанием типа микроконтроллера в виде директивы LIST p=16F628A. После нее строчка __CONFIG 3F01h ( __CONFIG – директива установки битов конфигурации), здесь двухбайтным шестнадцатеричным числом 3F01h (значение слова конфигурации) настраиваются биты конфигурации микроконтроллера (выбор кварцевого генератора, сторожевой таймер, защита памяти программ и др.). Для лучшей наглядности при настройке битов можно прописать значение слова конфигурации в двоичной форме __CONFIG b’11111100000001′.
Теперь необходимо присвоить названия адресам регистров ОЗУ, которые будут использоваться в программе. Делается это для удобного написания программы. Присвоение название осуществляется директивой equ (определение константы), например, var equ 0020h. Записи var в этом случае будет соответствовать число 0020h, которое является адресом регистра ОЗУ в памяти данных, кстати, в файле P16F628A.INC названия регистрам специального назначения присвоены таким же образом.
Я также использую директиву #define (определение текстовой последовательности для замены), чтобы присвоить названия линиям порта микроконтроллера. Например, строка #define led PORTВ,0 означает что, запись led будет заменяться на PORTB,0. Составляя текст программы не надо везде писать PORTB,0, а пишем просто led.
Все вышесказанное относится к “шапке” программы, после которой следует сам текст программы. Директивой org (определение начального адреса) задают начальный адрес в памяти программ, после которого будет располагаться код программы. Строка org 0000h означает что, код программы расположиться, начиная с 0-го адреса памяти программ. Подпрограмма обработчика прерываний должна располагаться, начиная с адреса 0004h, поэтому в начале подпрограммы необходимо написать строку org 0004h, при этом до этой строки надо написать org 0000h и команду перехода GOTO на основную программу, иначе исполнение основной программы начнется с подпрограммы обработчика прерываний. Если прерывания не задействованы, можно не пользоваться директивой org, программа автоматически расположиться с нулевого адреса памяти программ. Вообще с помощью этой директивы можно расположить требуемый участок кода в любую область памяти программ.
Директива end в конце программы указывает на окончание программы, конец всех команд.
Таким образом, шапка программы выглядит примерно следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include <P16F628A.INC> ;подключение файла P16F628A.INC LIST p=16F628A ;указание типа процессора __CONFIG 3F18h ;установка битов конфигурации Sec equ 0020h ;присвоение названий регистрам ОЗУ Sec0 equ 0021h Sec1 equ 0022h var equ 0023h T1L equ 0024h T1H equ 0025h shet equ 0026h W_temp equ 0079h STATUS_temp equ 007Ah #define led PORTA,7 ;присвоение названий линиям порта #define knp1 PORTB,0 #define knp2 PORTB,1 #define signal PORTB,2 org 0000h ;начать выполнение программы с адреса 0000h goto Start ;переход на метку Start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Подпрограмма обработки прерываний org 0004h ;начать выполнение подпрограммы с адреса 0004h ................. ;тело подпрограммы ................. ................. retfie ;выход из подпрограммы прерывания ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Основная программа Start ................. ;тело основной программы ................. ................. end ;конец всей программы |
Как видно здесь нет ничего сложного, далее остается только написать текст программы.
Вместо
Sec equ 0020h ;присвоение названий регистрам ОЗУ
Sec0 equ 0021h
Sec1 equ 0022h
var equ 0023h
T1L equ 0024h
T1H equ 0025h
shet equ 0026h
W_temp equ 0079h
STATUS_temp equ 007Ah
Я пишу всегда вот так.
Значительно удобнее.
Ассемблер сам все расставит как нужно.
;***** Распределение памяти
cblock 0x20 ;начало памяти данных
Sec
Sec0
Sec1
var
T1L
T1H
shet
W_temp
STATUS_temp
ENDC
Немного дополню
Для контроля количества переменных полезно заканчивать объявление блока таким комментарием:
ENDC ;—– завершаем объявление переменных Bank0
; Итого 42 переменных из 48 возможных
При добавлении/удалении просто правим цифру и нет необходимости их считать.
Спасибо. С #define, equ и cblock все понятно. Напишите, пожалуйста как заменить серию команд одним макросом. Гугл не дал толкового объяснения.
;=========================
; МАКРОСЫ
;=========================
bank0 macro
bcf STATUS, RP0
endm
bank1 macro
bsf STATUS, RP0
endm
Это макросы переключения банков
Просто пишешь потом
bank0 или
bank1
И все.
Или можно просто использовать встроенные в ассемблер макрокоманды
Например:
banksel CURVA – переключение на банк, в котором находится регистр CURVA
Привет
Привет 233
Спасибо, Александр.
Лично я не жаблюсь на комменты и внешние файлы, гораздо удобнее разбить большую программу на 20-30-40 мелких файлов и редактировать в многооконном редакторе, чем уныло листать вверх-вниз.
Вот, например, шапка текущей разработки:
; Управление усилителем с аудиопроцессором PT2348
; с ЖКИ индикатором 1602
; микроконтроллер PIC16F76
; Чипы на I2C: DS3231, AT24C16, PT2348
; Чипы на UART: ESP8266
; 16 МГц
;==============================================
; Объявляем подключаемые файлы
;==============================================
list p=16F76 ; Определяем тип микроконтроллера
#include ; Подключаем файл, определяющий параметры и набор РОН
;==============================================
; Объявляем конфигурацию
;==============================================
; установка битов конфигурации
;_BODEN_OFF & – разрешён сброс по снижению напряжения питания
;_CP_OFF & – Биты защиты памяти программ отключены, прочитать записанную программу можно
;_PWRTE_ON & – разрешена задержка запуска по включению питания
;_WDT_ON & – сторожевой таймер включен
;_HS_OSC – HS генератор
__CONFIG _BODEN_OFF & _CP_OFF & _PWRTE_ON & _WDT_ON & _HS_OSC
;==============================================
; Объявляем константы
;==============================================
#include ; Подключаем файл с распиновкой
#include ; Подключаем файл с константами
;==============================================
; Объявляем макросы
;==============================================
;==============================================
; Объявляем переменные
;==============================================
#include ; Подключаем файл с переменными
;==============================================
Почему-то в листинге сожрало всё, что заключено в угловые скобки 🙂
дополнять не буду, так как в данном случае для понимания это несущественно
Следует избегать записей, как у автора статьи, типа “__CONFIG 3F18h ;установка битов конфигурации”
Это именно плохой тон, так как такая запись является абсолютно нечитаемой и бесполезной при переносе на другой МК, обычно ею пользуются те, кто всё делает на одном-двух МК типа не к ночи помянутого PIC16F628A.
Впрочем, ещё раз посмотрел листинг и увидел именно PIC16F628A. И почему я не удивлён?
Добрый день. Пожалуйста, объясните где в программе должен располагается текст макроса, т.е. откуда программа его берет. По возможности, покажите на каком-то реальном примере.
Объясните где в программе должен располагается макрос, т.е. откуда основная программа его берет