Целочисленные константы
Целочисленные константы могут быть записаны как двоичные, восьмеричные, десятичные или шестнадцатеричные числа в зависимости от того, какая система счисления удобнее для представления константы. Компилятор распознает основание системы счисления по одной из букв B, Q’ O’ D или Н, следующей за числом (суффикс).
Буква B используется для обозначения двоичных чисел. Примеры записи двоичных констант:
1001b, 1000$1100B.
Эти константы удобно использовать при работе непосредственно с выводами портов или с отдельными битами внутренних регистров специального назначения.
Буквы 'O' или 'Q' используется для обозначения восьмеричных чисел (рекомендуется буква Q).
Для обозначения десятичных чисел используется буква D. Если буква за числом отсутствует, то считается, что это десятичная константа.
Шестнадцатеричные цифры определяются по букве H. Первым символом шестнадцатеричной константы обязательно должна быть цифра, это отличает ее от идентификаторов. Например, шестнадцатеричное представление числа 163 должно быть записано как 0A3H, а не А3Н, что будет принято компилятором за идентификатор.
Если константа содержит цифру, недопустимую в данной системе счисления, то данная константа считается ошибочной.
Максимальное значение целочисленной константы с размерностью word:
1111$1111$1111$1111В = 177777Q = 65535D = 0FFFFH
Примеры правильных целочисленных констант:
12AH, 2, 33Q, 1010B, 55D, 0BF3H, 65535, 0FC05H
Примеры синтаксически недопустимых целочисленных констант:
12AF - шестнадцатеричная константа не имеет буквы Н в конце, поэтому по умолчанию для нее принимается десятичная система счисления, но тогда в ней присутствуют недопустимые символы.
12AD - последний символ D может быть интерпретирован как основание системы счисления, но тогда символ А не десятичная цифра. Если же это шестнадцатеричная константа, то тогда в ней отсутствует указатель системы счисления буква Н.
11А2В - А и 2 недопустимые цифры для двоичного числа. Если необходимо записать шестнадцатеричную константу, то надо указать суффикс Н.
2ADGH - символ G недопустим при записи шестнадцатеричных чисел.
Исполняемые операторы
В языке программирования PLM-51 используются арифметические операции, результат которых зависит от :
+ суммирование - вычитание * умножение / деление mod вычисление остатка от целочисленного деления В языке программирования PLМ-51 также определена одноместная операция '-'. Для нее требуется один операнд, которому она предшествует.При использовании в операции различных типов операндов (byte или word) происходит автоматическое преобразование типов к одному виду (word). Если в выражении необходимо одновременно использовать тип bit, то нужно использовать функции преобразования типов boolean, expand или propagate.
В условном операторе и операторах цикла используются операции отношения:
< меньше > больше <= меньше или равно >= больше или равно = равно <> не равноЕсли указанное отношение между операндами верно, то результат битового типа равен 1, иначе - 0. Например, если d=7, то:
(d > 5) результат будет 1 (истина)(d = 4) результат будет 0 (ложь)
Над переменными можно осуществлять логические операции:
not побитовая инверсия операнда and логическое "и" or логическое "или" xor "исключающее или" (суммирование по модулю два)предназначен для программирования контроллеров
Язык высокого уровня PLM- 51 предназначен для программирования контроллеров серии MCS-51. Он удовлетворяет требованиям разработки программного обеспечения микроконтроллеров для систем различного назначения.
Компилятор plm51.exe - это программное средство, которое исходный текст, написанный на языке программирования PL/M-51 в перемещаемые объектные модули. Эти модули затем могут объединяться с другими модулями, написанными на языкax программирования PLM-51 или ASM-51. Компилятор выводит на экран дисплея или в файлы листингов сообщения об ошибках и вспомогательную информацию, которая может быть использована при отладке и разработке программ.
Компилятор plm51.exe может быть установлен на компьютерах серии IBM или совместимых с ними в операционной системе DOS 3.Х и выше и использоваться для генерации команд микроконтроллеров семейства MCS-51.
Необходимо отметить, что язык программирования PLM-51 предназначен для написания управляющих программ, поэтому не поддерживает знаковую арифметику и вычисления с плавающей запятой. Это является одновременно и преимуществом и недостатком этого языка программирования. Из-за указанной особенности загрузочные модули, созданные на этом языке программирования получаются практически такими же компактными, как и написанные на языке программирования ассемблер, но если в процессе реализуемого алгоритма управления каким либо объектом требуется достаточно сложные вычисления, то приходится использовать отдельно написанные библиотеки математической поддержки (или писать их самим).
Пожалуй в настоящее время, если требуются достаточно сложные математические вычисления, то стоит использовать язык программирования С-51. К настоящему времени появились трансляторы с этого языка программирования, создающие загрузочный модуль, лишь немногим уступающие компактностью загрузочному модулю, создаваемому языком программирования PLM-51 (естественно при правильном объявлении переменных и соответствующем стиле программирования).
с текстом программы для улучшения
Поясняющие могут чередоваться с текстом программы для улучшения читаемости программы и ее документирования. Комментарии в языке программирования PL/M-51 являются последовательностью символов, которая слева ограничивается символами /*, справа ограничивается символами */. Эти ограничители указывают транслятору, что следует игнорировать любой текст между ними. Комментарий может содержать любой печатный символ кода ASCII, а также включать пробелы, возврат каретки, перевод строки и табуляцию. Комментарий не может быть вставлен внутрь содержимого строковой константы. Комментарий может встречаться везде, за исключением вставки его в лексическую единицу.
Пример комментария: /* начало сегмента данных */
[ ] [ ] [ ]
Лексические единицы, разделители и использование пробелов
Наименьшей единицей операторов PL/M-51 является лексическая единица. Каждая из лексических единиц относится к одному из классов:
идентификаторы; ключевые слова; простые ограничители (все , кроме $ и _, являются простыми ограничителями); составные ограничители (они образуются посредством определенных комбинаций двух спецсимволов, а именно: <>, <=, >=, /*, */); числовые константы; текстовые строковые константы;В большинстве случаев вполне очевидно, где заканчивается одна лексическая единица и начинается следующая. Например, в операторе присваивания:
X=AP*(FT-3)/A;
X, AP, FT, A - являются идентификаторами переменных;
3 - числовой константой;
все прочие символы - простыми ограничителями.
Ключевые слова, идентификаторы и числовые константы должны обязательно отделяться друг от друга. Если между двумя идентификаторами, числовыми константами или ключевыми словами не может быть указан простой или составной ограничитель, то в качестве разделителя между ними должен вставляться символ пробела. Вместо одного символа пробел может использоваться непрерывная последовательность символов пробела.
Многомодульные программы
Язык программирования PLM-51 позволяет писать .
Оттранслированный программный модуль сохраняется в виде отдельного файла в объектном формате, где кроме машинных команд сохраняется информация о именах переменных, адресах команд, требующих модификации при объединении модулей в единую программу и отладочная информация.
Раздельная трансляция программы возможна при использовании двух программ: транслятора исходного текста программы plm-51 и редактора связей rl-51.
На первый взгляд раздельная трансляция не должна вызывать каких либо проблем. Однако это не так. При компиляции исходного текста программы если транслятор обнаружит переменную или подпрограмму, которые не были заранее объявлены, то будет сформировано сообщение об ошибке и объектный модуль будет стёрт с диска компьютера.
Для того, чтобы транслятор вместо формирования сообщения об ошибке записал в объектный модуль информацию, необходимую для редактора связей, нужно осуществить объявление внешних переменных подпрограмм и меток. Для объявления внешних переменных после обычного объявления добавляется слово EXTERNAL. При таком объявлении при трансляции исходного текста программы для переменной память данных для переменных не распределяется, а создаются соответствующие записи для редактора связей, позволяющие осуществить соответствующие вызовы подпрограмм и переходы между модулями, а также обращение к переменным другого модуля. Пример объявления внешних переменных на языке программирования PLM-51:
declare RejRab byte external, UrovGr byte external, NomKan word external, Sost bit external, Soob bit external;В этом объявлении перечисляются переменные, точное значение которых редактор связей должен получить из другого модуля и модифицировать все , в которых эти переменные используются.
Все используемые подпрограммы тоже должны быть предварительно объявлены. При использовании подпрограмм из других модулей они должны быть объявлены как внешние. При этом должны быть полностью объявлены все параметры подпрограмм.
Пример объявления внешних подпрограмм на языке программирования PLM-51:
TestOZU: procedure byte external; end TestOZU;
Rd558: procedure (AdrRAM,NachAdr,Nbyte) byte external; var (AdrRAM,NachAdr,Nbyte )byte; end Rd558;
Wr558: procedure (AdrRAM,NachAdr,Nbyte) byte external; var (AdrRAM,NachAdr,Nbyte )byte; end Wr558;
Для того, чтобы редактор связей мог связать вызов подпрограммы из одного модуля с самой подпрограммой в другом модуле, информация об этой подпрограмме должна быть помещена в объектный модуль. Для этого подпрограмма должна быть оттранслирована с атрибутом PUBLIC. Пример определения подпрограммы, доступной для других модулей, в исходном тексте модуля:
WrNadp: procedure(i,StrPtr) public; declare StrPtr address, char based StrPtr byte constant, i byte;
do while char<>0; BufInd(i)=char; StrPtr=StrPtr+1; i=i+1; end; end WrNadp;
IndNom: procedure public; declare Adres byte;
if BufInd(2)=0 then Adres=0; else Adres=8;
if RejNab=NabTlf1 then call WrNadp(Adres,.('T1',0)); if RejNab=NabTlf2 then call WrNadp(Adres,.('T2',0)); if RejNab=NabRadA then call WrNadp(Adres,.NadpRa);
if Adres=0 then call WrInd; else call InitPolnInd(2); end IndNom;
Переменные, к которым можно обращаться из других модулей, тоже должны быть объявлены с атрибутом PUBLIC.
Программа rl-51 объединяет несколько объектных файлов (модулей) в один. Для объединения нескольких модулей в исполняемую программу имена всех модулей передаются в редактор связей в качестве параметров при запуске этой программы. Пример вызова редактора связей из командной строки DOS для объединения трёх модулей:
rl51.exe progr.obj, modul1.obj, modul2.obj
В результате работы редактора связей в этом примере будет создан исполняемый модуль с именем progr.
Необходимость предварительного объявления внешних переменных и подпрограмм приводит к тому, что исходный текст программы загромождается этими объявлениями и найти собственно программу становится сложно. Кроме того при таких объявлениях возможно возникновение ошибок. Поэтому лучше вынести объявления подпрограмм и переменных в отдельные файлы, которые затем могут быть подключены в исходный текст программы директивой INCLUDE.
Наименьшая вероятность ошибиться при описании переменных и подпрограмм у программиста, который писал исходный текст модуля, к подпрограммам и переменным которого нужно обращаться из других модулей. Поэтому правила хорошего тона предполагают, что этот программист будет поставлять не только объектный модуль, но и файл описания своих переменных с атрибутом EXTERNAL. Такие файлы называются файлами заголовками и обычно записываются с расширением *.h. Пример исходного текста модуля приведён ниже:
/*Исходный текст модуля comm.plm*/ $CODE $NOLIST
Kommand: do; $INCLUDE (C:\COMP\PLM51\BIN\Rg51FA.Dcl) $INCLUDE (stdio.h) /*Подключение других файлов заголовков*/ $INCLUDE (dcl.h) $LIST
declare NomPult byte external, Bufer(7) byte external, RejRab byte public, NomKan word public,
PrmSoob: procedure using 2; declare i byte;
for i=0 to KolBytes; do while not RI;end; BufInd(i)=SBuf; RI=0; end;
Soob=true; end PrmSoob;
PriemKom: procedure interrupt 4 using 2; KodKom=(SBuf and 0f0h)/16; KolBytes=SBuf and 0fh; RI=0; If KodKom=KomSoob then call PrmSoob; If KodKom=KomSost then call PrmSost; end PriemKom; /*------- Конец модуля ---------*/
Исходный текст файла-заголовка этого модуля:
/*Начало файла заголовка comm.h*/ declare RejRab byte external, NomKan word external,
PriemKom:procedure external;end PriemKom; /*------- Конец файла заголовка---------*/
Теперь для того, чтобы воспользоваться приведённым выше модулем достаточно записать строку:
$INCLUDE (comm.h)
Естественно, так как процесс трансляции разбит на два этапа, то ошибки могут возникать не только на этапе трансляции модулей, но и при связывании модулей в исполняемую программу. Наиболее распространённые ошибки - это забыть включить имя объектного модуля в строку вызова редактора связей, забыть объявить переменную или подпрограмму как PUBLIC или использовать одни и те же адреса для переменных или констант в различных модулях. Сообщения об этих ошибках выводятся в файл с расширением *.m51.
Полный путь написания программ на языке программирования plm51 показан на рисунке 1 файла .
[] []
могут быть объявлены пять
В языке программирования PLM- 51 могут быть объявлены пять типов объектов: переменные, константы, литералы, метки и подпрограммы. В одном блоке для каждого имени допустимо только одно объявление. Переменные, константы, литералы и подпрограммы должны быть объявлены раньше, чем они будут использованы в исполняемом операторе.
Метка может быть объявлена двумя способами:
если она стоит перед выполняемым оператором и заканчивается с двоеточием (:) определена в операторе DECLARE. Подпрограмма объявляется оператором PROCEDURE и определяется между операторами PROCEDURE и END.
Переменные, константы и литералы объявляются оператором DECLARE. При этом они могут объявляться как в разных операторах DECLARE, так и в одном. Если оператор DECLARE содержит более чем одно объявление, то они разделяются запятыми. При объявлении переменной обязательно указывается тип объявляемой переменной. Пример использования оператора DECLARE:
declare Chr byte; declare Count word; declare Chr byte, Count word; Переменная может быть скаляром, массивом или структурой.
Cкаляр является объектом, значение которого не известно на этапе трансляции, и может изменяться в процессе выполнения программы. К нему обращаются при помощи идентификатора переменной.
Скаляр обязательно имеет тип. В языке программирования PLM-51 это может быть восьмибитовая беззнаковая переменная - byte, шестнадцатибитовая беззнаковая переменная - word или однобитовая переменная - bit.
Массив - это набор скаляров одинакового типа, имеющих один идентификатор, и различающихся индексами.
Например:
А(0), A(1), A(2), A(3), и т.д.
Структура позволяет объединять под одним именем переменные разного типа. Ее элементы различаются друг от друга идентификаторами поля. Например, индикатор Employees.Name обращается к полю Name внутри структуры Employees. Массивы и структуры могут быть как переменной, так и константой.
Так как микроконтроллеры семейства MCS-51 имеют несколько адресных пространств, то транслятору необходимо указывать, в какой из областей памяти необходимо размещать переменные.
Это осуществляется при помощи уточняющих слов, следующих за определением типа переменной.
MAIN - переменная размещается во с IDATA - переменная размещается во с REGISTER - переменная размещается в области AUXILIARY - переменная размещается во CONSTANT - константа размещается в Если уточняющее слово отсутствует, то по умолчанию переменные размещаются во внутренней памяти данных. В приведенном выше примере переменные были размещены во внутренней памяти данных. Приведём пример объявления переменной в области регистров специальных функций:
declare SBUF byte at (99h) register; /*рег. данных последовательного порта */ В этом примере была объявлена переменная, совпадающая с регистром данных последовательного порта. Поэтому при записи байта в эту переменную, записанное число будет передано через .
Суффикс CONSTANT описывает переменные в адресном пространстве памяти программ, где должно находиться ПЗУ. Содержимое такой переменной в отличие от других не изменяется в процессе выполнения всей программы. Идентификатор такой переменной никогда не должен находиться в левой части оператора присваивания. Инициализация данных производится добавлением значения константы к ключевому слову CONSTANT. Следующий оператор:
declare Porog byte constant (48);
объявляет байт Porog в памяти программ и присваивает ему значение 48. Оператор:
declare (Counter, Limit, Incr) word constant (1024, 0, -2)
объявляет скаляры Counter (счетчик англ), Limit (граница англ) и Incr (увеличение англ) типа WORD, указывает, что они находятся в ПЗУ, и устанавливает значение константы Counter равным 1024, значение константы Limit - 0, значение константы Incr равным (-2).
Достаточно мощное средство программирования предоставляет макроподстановка LITERALLY. Строка, следующая за ключевым словом LITERALLY подставляется на этапе трансляции.
Следующий пример иллюстрирует использование ключевого слова LITERALLY:
declare True literally '1', False literally '0'; declare Rough bit; declare (x, y, Delta, Final) word; ...
rough = True; do while Rough; x = smooth (x, y, Delta);/* smooth это подпрограмма, объявленная в другом месте .*/ if (x - Final) < Delta then Rough = False; end; ... В этом примере при помощи ключевого слова LITERALLY определяются булевы значения True и False для работы с операциями отношения. Это делает программу более удобной для чтения.
Ещё один вариант использования ключевого слова LITERALLY это объявление констант, неизменных во время одной компиляции, но которые могут принимать другое значение при последующих компиляциях исходного текста программы.
Рассмотрим следующий пример:
declare Buffer$Size literally '32' declare Print$Buffer (Buffer$Size) word; ... print$buffer (buffer$size - 10) = 'g'; Последующие изменения Buffer$Size могут быть сделаны в одном месте в первом операторе declare. Компилятор распространит изменение по всей программе во время компиляции. Таким образом, программист сократит утомительный и приводящий к ошибкам процесс поиска в программе тех мест, где строка '32' используется как размер буфера, и внесение нового значения размера буфера.
Язык программирования PLM очень похож на широко распространённый язык программирования PASCAL, так как оба этих языка произошли от общего родоначальника - языка программирования ALGOL-68. При помощи макроподстановок LITERALLY эти языки программирования можно сделать ещё более похожими. Это очень полезное свойство для людей, привыкших программировать на PASCAL.
[] [] []
и переменная, поэтому любое обращение
объявляется точно также как и переменная, поэтому любое обращение к подпрограмме должно осуществляться внутри области действия объявления подпрограммы. Кроме того, обращение к подпрограмме не может встречаться внутри самой подпрограммы, т.е. до оператора END объявления этой подпрограммы.
Объявление подпрограммы состоит из 3-х частей: зарезервированного слова PROCEDURE, последовательности операторов, составляющих тело подпрограммы, и зарезервированного слова END:
<имя>:procedure [(<список параметров>)] [<адресное пространство>] [<атрибуты>]; <operator-1>; <operator-2>; ... <operator-N>; end [<имя>]; Например:
ProverkaDveri: Procedure; if VneshnDverZaperta and VnutrDverZaperta then Call VkluchitPitanie; else Call Trevoga; end ProverkaDveri; где VkluchitPitanie и Trevoga это подпрограммы а VneshnDverZaperta и VnutrDverZaperta глобальные битовые переменные, объявленные раньше описываемой подпрограммы.
Имя подпрограммы в операторе PROCEDURE выглядит точно также, как и определение метки, однако имя подпрограммы не является меткой. Область действия подпрограммы определяется местоположением ее объявления в тексте программы точно так же, как область действия переменной определяется местоположением оператора DECLARE. Объявление подпрограммы может содержать в себе операторы объявления DECLARE, и эти операторы должны предшествовать первому выполняемому оператору в теле подпрограммы.
Как и в блоке DO, идентификатор, следующий за словом END, не оказывает никакого действия на программу, а только повышает наглядность программы и облегчает ее отладку. Если оператор END содержит идентификатор, то он обязательно должен быть тем же самым, что и идентификатор имени подпрограммы.
Оператор безусловного перехода GOTO
Оператор GOTO изменяет порядок выполнения программы при помощи передачи управления на оператор, метка которого указана в операторе GOTO. Ключевое слово GOTO может также записываться со вставленным пробелом, т.е. в виде GO TO. Оператор GOTO записывается в следующем виде:
GoTo < метка >;
Использование операторов GOTO является неизбежным при некоторых ситуациях, однако в большинстве случаев там, где должна быть предусмотрена передача управления, более предпочтительным является использование итеративного оператора DO, DO WHILE, DO CASE, IF или вызова процедуры. Неограниченное использование операторов GOTO в программе приводит к тому, что программу становится трудно понимать, модифицировать и сопровождать. Реальная практика использования языка PL/M-51 для программирования как системных, так и прикладных задач, показывает, что в большинстве случаев программные модули могут не содержать оператор GOTO без ухудшения их эффективности.
Оператор цикла do
Оператор цикла DO записывается в следующей форме:
do <переменная цикла> = <начальное выражение>to<конечное выражение>; <operator-1; <operator-2>; ... <operator-n>; end;где переменная цикла должна быть простой скалярной переменной и иметь тип BYTE или WORD. Она не может быть элементом массива или быть базированной переменной. Начальное выражение и конечное выражение могут быть любыми разрешенными выражениями языка PL/M-51. Они тоже должны иметь тип byte или word. Оператор цикла работает следующим образом:
Вычисляется начальное выражение и его значение присваивается переменной цикла. Это делается только один раз до первого прохождения через блок. Вычисляется конечное выражение и его значение сравнивается со значением переменной цикла. Если значение переменной цикла больше, чем значение конечного выражения, то шаги 3 и 4 данного алгоритма пропускаются и управление передается оператору, следующему за оператором END. В блоке выполняются операторы. При достижении оператора END вновь определяется значение переменной цикла. Значение переменной цикла увеличивается на 1. Если при этом не произойдет переполнения переменной, то происходит снова выполнение шага 2. Иначе цикл завершается.Начальное значение вычисляется один раз. Конечное значение вычисляется каждый раз при повторении блока. Отрицательное значение шага недопустимо.
Пример: do j = 0 to 9 by 2; Vector(j) = 0; end;В более общей форме оператора цикла DO разрешается использовать значение шага цикла, отличающееся от 1. Эта форма выглядит следующим образом:
do <переменная цикла> = <начальное выражение> to <конечное выражение> by <выражение шага>; <operator-1>; <operator-2>; ... <operator-n>; end;В данном случае переменная цикла, которая задается в операторе DO, увеличивается каждый раз при достижении оператора END на значение шага, равное значению выражения шага, а не на 1. Пример использования такой формы оператора DO:
SOS=1; do i=1 to 2*X by 2; SOS= SOS*ARY(i); end;Значение выражения шага может иметь тип BYTE или WORD. Выражение шага цикла вычисляется каждый раз сразу же после выполнения всех операторов в операторе цикла. Аналогично структурному оператору, оператор цикла может рассматриваться как одиночный оператор языка PL/M-51. В отличие от структурного оператора, оператор цикла не может содержать в себе объявлений. Однако он может содержать вложенный , в котором можно поместить объявления переменных.
Оператор цикла с проверкой условия до тела цикла do while
Оператор DO WHILE содержит условную операцию (такую же, как в части IF оператора IF), и вызывает исполнение операторов в этом блоке до тех пор, пока условие верно. В следующем примере оператор DO WHILE используется для пошагового прохождения по элементам массива Table до тех пор, пока очередной элемент не превысит значение скалярной переменной с именем Level (уровень англ.):
i = 0; do while table(i) <= Level; i = i + 1; end;В этом примере Table – это предварительно объявленный массив. Переменные Level и i тоже должны быть предварительно объявлены.
Переменной i первоначально присваивается значение 0, затем она используется как индекс для массива Table. Так как i увеличивается при каждом выполнении блока DO WHILE, то каждый раз, когда выполняется исполняемый оператор внутри блока DO WHILE, с переменной Level сравнивается следующий элемент массива Table. Когда найден элемент, превышающий значение переменной Level, то условие в операторе DO WHILE больше неверно, выполнение блока не повторяется и управление передается следующему за зарезервированным словом END оператору. С этого момента переменная i является индексом первого элемента массива Table, который превышает значение переменной Level.
Оператор присваивания
Оператор присваивания записывается в виде:
=выражение;
Выражение вычисляется, и полученное значение присваивается переменной.
Пример оператора присваивания: A=B+2;
Выражение в языке программирования PL/M-51 состоит из операндов, которые комбинируются при помощи различных или операций, а также .
Например:
А + В А + В - С A * T + F/D A * (B + C) - (D - E)/F A XOR B,Операндом в выражении может быть переменная, подпрограмма-функция, числовая константа или указатель.
В выражениях в качестве операндов могут использоваться подвыражения. Подвыражение - это обычное выражение, заключенное в скобки. Подвыражения могут использоваться для группировки частей выражения, точно так же, как и в обычной алгебраической записи. Использование подвыражений позволяет сократить количество операторов в программе, а значит и объем исходного текста программы, но затрудняет отладку этой программы.
Язык программирования PL/M-51 обеспечивает автоматическое преобразование между типами BYTE и WORD, но не может автоматически преобразовывать битовые переменные в числовые.
Числовые значения могут быть преобразованы к битовому типу при помощи встроенной функции BOOLEAN, которая возвращает битовое значение, равное биту в младшем разряде исходного числа. Битовая переменная может быть преобразована в числовую при помощи встроенных функций EXPAND и PROPAGATE. Обе процедуры преобразуют 0 (ложь) в число 00h. Функция EXPAND преобразует 1 (истина) в число 01h, а PROPAGATE преобразует 1 в число 0ffh (255). Например, встроенная функция propagate преобразует битовое значение в байт:
I = J + Propagate(Magic_Bit);Оператор возвращения из подпрограммы RETURN
Выполнение подпрограммы может завершаться выполнением оператора RETURN в теле подпрограммы. Подпрограмма-функция обязательно должна содержать оператор RETURN с выражением в качестве операнда. Пример использования оператора RETURN:
RETURN 2+2;Оператор выбора do case
Оператор DO CASE, использует значение данного выражения для выбора исполняемого оператора. Следует отметить, что язык программирования PLM-51 ориентирован на микроконтроллеры MCS-51. Поэтому для реализации данного оператора используется команда процессора . Это означает, что команда выполняется за два машинных цикла. В следующем примере Tst_1 в операторе DO CASE может иметь любое значение от 0 до 3.
do case Tst_1; red = 0; blue = 0; green = 0; gray = 0; end;Если значение выражения равно 0, то выполняется только первый оператор присваивания, и 0 будет присвоен переменной red (красный англ). Если значение выражения равно 1, то будет выполнен только второй оператор присваивания и переменной blue (голубой англ) будет присвоен 0. Значения выражения 2 и 3 вызовет присваивание 0 переменным green (зеленый англ) и gray (серый англ) соответственно.
Максимальное число выбираемых операторов может быть 84. В операторе должны присутствовать все варианты выбора! Если какой либо оператор не нужен, то используется , состоящий только из символа ';'. Если же по одному из вариантов требуется выполнение нескольких операторов, то можно воспользоваться
Оператор вызова подпрограммы CALL
Оператор CALL используется для того, чтобы вызвать - процедуру (т.е. подпрограмму, которая не возвращает значения). Пример использования оператора CALL:
Call DecodCmd;используется два типа операторов:
В языке программирования PL/M- 51 используется два типа операторов: операторы объявления и выполняемые операторы. Все операторы PL/M-51 заканчиваются точкой с запятой.
Операторы объявления
Объявление является невыполняемым оператором, который объявляет некоторый объект или набор объектов, связывает с ним один или несколько идентификаторов и, если это необходимо, распределяет память.
В объявлении могут быть объявлены пять типов объектов: переменные, константы, литералы, метки и подпрограммы. В текущем блоке для каждого имени допустимо только одно объявление.
Переменные, константы, литералы и подпрограммы должны быть объявлены раньше, чем они будут использоваться в выполняемом операторе. Метка полностью объявлена, если она стоит перед выполняемым оператором и заканчивается с двоеточием (:) или определена в операторе DECLARE. Подпрограмма объявляется оператором PROCEDURE и заключается между операторами PROCEDURE и END. Переменные, константы и литералы должны объявляться оператором DECLARE.
DECLARE Width byte;
Этот оператор вводит идентификатор (переменную) Width (ширина англ) и резервирует 1 байт (8 бит) памяти. В языке программирования PL/M-51 нет необходимости знать конкретный адрес этой переменной, достаточно обратиться к ней по имени Width.
Группа операторов, предназначенных для выполнения какой-либо функции, может быть задана именем, объявляющим их как подпрограмму.
Address_Upper: PROCEDURE (Beta) byte;
Отладка программ
После того, как программные модули были успешно оттранслированы, размещены по конкретным адресам и связаны между собой, для можно воспользоваться любым из методов, показанных на рисунке 1:
внутрисхемным эмулятором встроенным программным отладчиком внешним программным отладчиком отлаживаемым устройством с записанным в память программ двоичным кодом программыВнутрисхемный эмулятор с отображением переменных языка программирования на дисплее компьютера оказывает значительную помощь при отладке программ непосредственно на разрабатываемой аппаратуре. Этот метод отладки предоставляет наиболее удобную среду, когда можно непосредственно в отлаживаемом устройстве останавливать программу, контролировать выполнение программы непосредственно по исходному тексту программы, состояние внешних портов и внутренних переменных, как входящих в состав микросхемы, так и объявленных при написании исходного текста программы. Необходимое для отладки программ оборудование показано на рисунке 2.
Рисунок 2. Пример системы отладки программного обеспечения для микроконтроллеров.
При с использованием внутрисхемного эмулятора необходимо включать в объектные модули символьную информацию. Для этого используются директивы компилятора. В компиляторе языка программирования PLM-51 возможны следующие действия:
включение информации о типе переменных для проверки типов при связывании модулей. Эта же информация используется внутрисхемным эмулятором. Исключение информации о переменных пользователя может использоваться для создания прототипов или для уменьшения размера объектного модуля; включение или исключение таблиц символьной информации; конфигурация вызовов подпрограмм для обеспечения связывания с модулями, написанными на языке программирования ASM-51; определение желаемого содержания и формата выходного листинга программы. Распечатка промежуточных кодов на языке ассемблер после компилирования программ, написанных на языке программирования PLM-51. Включение или исключение листингов отдельных блоков исходного текста.[] [] []
Формальные должны быть небазированными переменными,
Формальные должны быть небазированными переменными, объявленными внутри подпрограммы. Их идентификаторы задаются в списке параметров в операторе PROCEDURE. Идентификаторы в списке разделяются запятыми, а сам список заключается в скобки. В списке параметров не допускаются применение массивов и структур. Если в подпрограмме нет формальных параметров, то список формальных параметров (включая скобки) в операторе PROCEDURE опускается. Каждый формальный параметр обязательно должен быть объявлен в теле подпрограммы оператором DECLARE, предшествующем первому исполняемому оператору.
При вызове подпрограммы с формальными параметрами в операторе CALL или обращении к функции должны содержаться фактические параметры. Каждый фактический параметр является выражением, значение которого присваивается соответствующему формальному параметру подпрограммы до того, как подпрограмма начнет выполняться. Например, следующая подпрограмма-процедура имеет 4 параметра, называемые Ukazat, N, Min, Max.
ProvDiapaz: Procedure(Ukazat, N, Min, Max); Declare Ukazat word; Declare (N, Min, Max, Perem Based Ukazat(1), I) byte; do I = 1 to N; if (Perem(I) < Min) or (Perem(I) > Max) then Call UstOshib; /*UstOshib это заранее объявленная подпрограмма */ end; end ProvDiapaz; ... Call ProvDiapaz(.Value, 20, low, up); Эта подпрограмма просматривает N байтовых переменных. Через параметр Ukazat передается адрес первой из этих переменных. Если какая-нибудь из этих переменных меньше параметра Min или больше параметра Max, то вызывается объявленная ранее в этой же программе процедура UstOshib.
Переменные I и Perem не являются параметрами подпрограммы. Это обычные локальные переменные.
Отметим, что массив Perem объявлен с размерностью в один элемент. Так как это базированный массив, то важен только адрес переменной, задаваемый переменной Ukazat. Индекс в массиве может быть любым. При объявлении переменной можно указать в качестве размерности массива любое число большее 0. Размерность указывается для того, чтобы переменная Perem воспринималась как массив.
Вызов подпрограммы в конце примера передаёт приказ проверить находятся ли элементы массива Value(20) в диапазоне чисел от low до up. Адрес массива передан оператором .Value количество элементов массива числом 20. Использование базированной переменной, адрес которой передается в качестве параметра, позволяет процедуре иметь свой собственный неизменяемый идентификатор (Perem) для разных переменных, передаваемых при вызове процедуры.
Подпрограммы-функции
Пример подпрограммы из предыдущего параграфа - это . Для нее в операторе PROCEDURE не задается тип, и такая процедура не возвращает никакого значения. Подпрограмма-процедура вызывается по ее имени оператором CALL. Тем не менее иногда удобно присваивать вычисленное значение сразу переменной. Примером является вычисление математических функций таких как синус или косинус. Запись математической операции была бы удобнее в следующем виде:
Y=sin(x);Именно такую форму записи позволяет использовать подпрограмма-функция. В языке программирования PLM-51 подпрограмма-функция может иметь тип: bit, byte или word который указывается в операторе Procedure. Такая подпрограмма возвращает значение объявленного типа, которое может быть использовано в выражении или присвоено переменной.
Когда на этапе выполнения программы происходит обработка выражения, то запись имени функции осуществляет вызов подпрограммы-функции. Само имя функции заменяется значением, возвращаемым этой подпрограммой. Затем вычисляется оставшаяся часть выражения, и выполнение программы продолжается в нормальной последовательности.
Подобно подпрограмме-процедуре, подпрограмма-функция может иметь параметры. Тело подпрограммы-функции должно обязательно содержать оператор . Заметим, что подпрограмма-функция подобно подпрограмме-процедуре может изменять содержимое глобальных переменных.
Рассмотрим пример использования подпрограммы- функции для обнаружения нажатия на кнопку. Если к портам P0 и P1 подключена , то при нажатии на кнопку на входах P0 на одном из выводов порта появится логический 0. Подпрограмма может обнаружить это состояние и в основной программе оператор обнаружения нажатия на кнопку будет совпадать с записью алгоритма.
SostKnIzm: Procedure bit; Declare tmp bit; bit=0; if (P0 <> 0ffh) then bit=1; return bit end SostKnIzm; /* Основная программа */ ... if SostKnIzm then Call DecodSostKn;[] [] []
Подпрограммы обработки прерываний
Атрибут INTERRUPT позволяет объявить подпрограмму-процедуру обработки сигналов прерываний, поступающих от внешних устройств. Подпрограмма процедура с этим атрибутом вызывается при получении микроконтроллером соответствующего сигнала прерывания. Подпрограмма обработки прерываний не может быть подпрограммой функцией и не может иметь переменные-параметры. Формат атрибута:
Interrupt N;где N-любое десятичное число от 0 до 255.
Число N определяет номер обрабатываемого прерывания. При этом номер 0 соответствует внешнему прерыванию от ножки INT0, номер 1 соответствует прерыванию от таймера 0, номер 2 соответствует внешнему прерыванию от ножки INT1 и так далее. Пример подпрограммы-обработчика прерывания от таймера 0 приведён на рисунке 1.
IntTim0: procedure interrupt 2; TH0=25; TL0=32; TF=0; end;Применение
Язык программирования PL/M-51 и его библиотеки являются частью интегрированного набора средств разработки программного обеспечения для микроконтроллеров семейства MCS-51. Язык программирования PLМ51 поддерживает модульное написание программ. Процесс разработки программ на языке программирования PLM-51 показан на рисунке 1.
Рисунок 1. Процесс написания программы на языке программирования PLM-51.
При разработке программного обеспечения выполняются следующие этапы:
постановка задачи (полное определение решаемой проблемы); разработка принципиальной схемы и выбор необходимого программного обеспечения; разработка системного программного обеспечения. Этот важный шаг состоит из нескольких этапов, включающих: описание последовательности выполняемых каждым блоком задач, выбор языка программирования и используемых алгоритмов; написание текста программы и подготовка к трансляции при помощи любого текстового редактора; компиляция программы; исправление синтаксических ошибок, выявленных компилятором, в текстовом редакторе с последующей перетрансляцией; создание и сохранение библиотек часто используемых объектных модулей при помощи программы lib51.ехе; связывание полученных перемещаемых объектных модулей в абсолютный модуль и размещение переменных в памяти микроконтроллера при помощи редактора связей rl51.exe; создание программы, записываемой в ПЗУ микроконтроллера (загружаемый модуль) в hex формате, при помощи программы oh.exe; проверка полученной программы при помощи символьного отладчика или других программных или аппаратных средств.Файл, в котором хранится программа, написанная на языке PLМ51 (исходный текст программы), называется исходным модулем. Для исходного текста программы принято использовать расширения файла: plm или p51. Исходный текст программы можно написать, используя любой текстовый редактор.
Получить можно, указав имя исходного модуля программы в качестве программы-транслятора в DOS строке или строке командного файла:
plm51.exe modul.plm
В этом примере в результате трансляции исходного текста программы, содержащегося в файле modul.plm будет получен объектный модуль, который будет записан в файл с именем modul.obj. Как показано на рисунке 1, объектный модуль не может быть загружен в память программ микроконтроллера. В память микроконтроллера загружается исполняемый модуль.
Получить программы можно, указав все имена объектных модулей программы в качестве программы редактора связей в DOS строке или строке командного файла:
rl51.exe main.obj, modul1.obj, modul2.obj
Имя исполняемого модуля программы по умолчанию совпадает с именем первого объектного файла в списке параметров строки запуска редактора связей. Исполняемый модуль программы записывается в файл без расширения. При выполнении приведённой выше в качестве примера командной строки будет получен исполняемый модуль, который будет записан в файл с именем main.
Большинство программаторов, предназначенных для записи информации в память программ микроконтроллеров, не может работать с объектным форматом исполняемого модуля программы, поэтому для загрузки машинного кода в процессор необходимо преобразовать объектный формат исполняемого модуля в общепринятый для программаторов гексадецимальный формат. При преобразовании форматов вся отладочная информация теряется. Машинный код процессора в гексадецимальном формате называется загрузочным модулем.
Загрузочный модуль программы можно получить при помощи программы-преобразователя программы oh.exe, передав ей в качестве имя файла исполняемого модуля программы, например:
oh.exe main
В результате выполнения этой командной строки будет получен загрузочный модуль программы, который будет записан в файл с именем main.obj.
Приоритеты операций
В таблице 1 приведены приоритеты операторов языка программирования PL/M-51 от высшего приоритета к низшему. Порядок вычисления выражения следующий: сначала выполняются операторы в круглых скобках, в них от старшего приоритета к младшему, а среди равнозначных операторов – слева направо.
Таблица 1
Оператор | Класс | Описание |
(, ) | Скобки | Управляют порядком вычислений выражения внутри скобок, вычисляются до действий над операторами вне скобок |
+, . , - | Унарная операция | Одиночный оператор плюс, оператор адреса, одиночный оператор минус |
*, /, MOD, =, - , PLUS, MINUS | Арифметическая операция | Умножение, деление, модуль (остаток) от деления, сложение, вычитание |
<, <=, <>, =, >=, > | Операция отношения | Меньше, меньше или равно, не равно, равно, больше или равно, больше |
NOT AND OR, XOR | Логическая операция | Логическое отрицание Логическое 'И' Логическое 'ИЛИ', логическое исключающее 'ИЛИ' |
Пустой оператор
Пустой оператор не содержит ничего, кроме пробелов и комментариев. Это выполняемый оператор без какого-либо воздействия на программу. У пустого оператора может быть метка. Пустой оператор удобно использовать как часть конструкции . Пустой оператор завершается точкой с запятой ‘;’.
[] [] []
В исходном тексте программы, написанной
В исходном тексте программы, написанной на языке программирования PLM-51 можно использовать буквы латинского алфавита верхнего и нижнего регистров, а также арабские цифры:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d i f g h i j k l m n o p q r s t
0 1 2 3 4 5 6 7 8 9
В языке программирования PLM-51 используются также специальные символы:
= . / ( ) + ' < > : ; $ _
Кроме того, язык программирования PL/M-51 использует символы пробела, табуляции, возврата каретки, перевода строки.
Компилятор PLM-51 выдает сообщение об ошибке, если в тексте исходной программы встречается символ, отличающийся от символов, перечисленных выше. (То есть строки и символьные константы на русском языке запрещены!) Компилятор воспринимает последовательность непрерывных пробелов как один пробел.
PLM-51 не делает различий между строчными и заглавными буквами, кроме символьных строк. Например, имена xyz и XYZ одинаковы, а строки 'PLM' и 'plm' различны.
Идентификаторы в языке программирования PLM-51 используются для того, чтобы дать имя переменной, процедуре, символической константе или метке оператора. Длина идентификатора не превышает 31 символ. Первый символ обязательно должен быть буквой, последующие символы могут быть буквами, цифрами, знаками _ или $. Знак $ внутри идентификатора всегда игнорируется транслятором и может использоваться для улучшения читаемости идентификатора. Идентификатор, содержащий знак $, является полным эквивалентом идентификатора, из которого этот знак удален.
Примеры правильных идентификаторов:
A XYR_56 DFG$$RTY$CFG RT$EUI RTEUI Последние два примера эквивалентны.
Идентификаторы должны отличаться от зарезервированных (ключевых) слов.
Строчные константы
Строчная константа записывается при помощи символов кода ASCII заключенных в апострофы. Для того, чтобы включить в строку апостроф записывается два апострофа. Например, строка '''Q' состоит из двух символов - апострофа и буквы Q. В строке допускается использование пробелов. Транслятор представляет в памяти строки символов в коде ASCII-7, по одному восьмиразрядному байту на каждый семиразрядный код, с нулевым старшим разрядом. Строка, состоящая из двух символов, транслируется в двухбайтовое значение. Например: строка 'А' эквивалентна числу 41Н, а строка 'AG' эквивалентна числу 4147Н. Строки символов, имеющие длину более двух символов, не могут использоваться в качестве арифметических значений, поскольку арифметические значения ограничиваются 16 двоичными разрядами. Тем не менее, более длинная строка символов может использоваться для хранения текстовых сообщений.
Необходимо однако отметить, что язык программирования PLM-51 не поддерживает русских букв и воспринимает эти символы как ошибки. Если требуется написать какую либо команду на русском языке, то приходится использовать для этого цифровые константы.
в программе является, частью, по
PL/M-51 является блочно-структурированным языком, каждый оператор в программе является, частью, по крайней мере, одного блока.
Каждая программа на PL/M-51 состоит из одного или более модулей, записанных в отдельных файлах и компилируемых отдельно. Каждый модуль может состоять из одного или более блоков. В языке программирования PL/M-51 имеется два типа блоков: блоки DO и блоки подпрограмм.
Модуль должен начинаться оператором DO с меткой перед ним, и заканчиваться оператором END. Между этими двумя операторами помещаются операторы, составляющие программу. Эти операторы объявляют переменные и выполняют необходимые действия. Модуль может содержать несколько блоков.
Блок - это соответствующим образом записанная группа операторов, начинающихся оператором DO и заканчивающаяся оператором END.
начинается с объявления подпрограммы и заканчивается оператором END. Переменные, объявленные в подпрограмме и исполняемые операторы, находящиеся между операторами начала и конца подпрограммы, используются только при вызове подпрограммы.
Любая программа, написанная на языке программирования PLM-51, начинается с оператора do, при этом имя программы записывается перед этим оператором и оформляется как метка. Перед первым исполняемым оператором программы обязательно должны быть объявлены все переменные и константы, которые будут использоваться в программе. Программа, написанная на языке программирования PLM-51, заканчивается оператором end. Пример программы, написанной на языке программирования PLM-51 приведён ниже:
Primer:do; declare a byte; a=2+2; end; Эта программа выполняет простейшие действия и содержит только один исполняемый оператор. Так как микроконтроллер не содержит встроенных средств отображения информации, то в языке программирования нет встроенных средств отображения полученного результата. Результат приведённой в примере программы можно посмотреть только во внутренней памяти микроконтроллера. То есть проверить работоспособность этой программы можно только на отладчике.
Для того, чтобы получить более полное представление о структуре программ, написанных на языке программирования PLM-51, приведём пример программы с использованием подпрограмм.
PrimerSIN:do; /*---------- Объявление переменных -------------------------*/ declare tabsin(180) byte const (0, /*sin(0)*/ 0.01745*32767, /*sin(1)*/ 0.03490*32767); /*sin(2)*/ declare a byte at(80h) register,/*переменная значения синуса*/ i byte;/*переменная аргумента в градусах*/ /*---------- Объявление подпрограмм -----------------------*/ sin:procedure(x) byte; declare x byte; return(tabsin(x)); end sin; /*--------- Начало основной программы ----------------------*/ do i=0 to 180; a=sin(i); /*вычислить очередное значение синуса*/ end; end; В этом примере используется подпрограмма вычисления синуса с использованием табличного способа. Как видно из исходного текста программы все объявления были сделаны до первого исполняемого оператора. Переменная a в этом примере совпадает с адресом порта P0, поэтому синус можно наблюдать на выходе этого порта.
[] [] []
Структурный оператор do;end;
Существует три основных способа использования структурного оператора:
Структурный оператор может рассматриваться в качестве отдельного оператора языка PL/M-51 и использоваться в программе везде, где может встречаться отдельный исполняемый оператор. Это используется в блоках DO CASE и операторах IF; Структурный оператор ограничивает область действия локальных переменных. Вся программа написанная на языке программирования PL/M-51 сама может рассматриваться как структурный оператор do;end, удовлетворяющим дополнительным требованиям.Каждый оператор внутри структурного оператора может являться любым оператором языка PL/M-51, в том числе и объявлением, при условии, что все объявления внутри структурного оператора должны быть выполнены до первого исполняемого оператора.
Структурный оператор начинается с ключевого слова DO и записывается в следующем виде:
do; <operator-1>; <operator-2>; ... <operator-n>; end; Пример: IF Wes<Min then /*Условная операция*/ do; /*Структурный оператор*/ incr=incr*2; /*Содержит два*/ Schetch=Schetch+1; /*оператора*/ end;Структурные операторы могут вкладываться друг в друга. При этом максимальное число уровней вложенности не может превышать 16.
Пример: do; <operator-1>; <operator-2>; do; <operator-A>; <operator-B> <operator-C>; end; <operator-3>; <operator-4>; end;Условный оператор
Оператор IF обеспечивает условное выполнение операторов. Он записывается в следующей форме:
IF <выражение> THEN <operator-1>; [ELSE <operator-2>;]ключевое слово THEN и исполняемый оператор, следующий за ним, записываются всегда, а ключевое слово ELSE со следующим за ним исполняемым оператором представляют собой необязательную часть условного оператора. Если результат вычисления выражения равен 1 (истина), то выполняется operator-1. Если результат вычисления выражения равен 0 (ложь), то выполняется operator-2. Пример:
IF Wes<Min then /*Условная операция*/ Schetch=Schetch+1; /*Плечо 1*/ else Schetch=0; /*Плечо 2*/В качестве выражения могут быть использованы любые битовые переменные в том числе ножки портов а также подпрограммы-функции, возвращающие битовое значение. Использование битовых переменных и подпрограмм позволяет увеличить читаемость исходного текста программы.
IF PrinjatByte then Call DecodCmd;В приведённом примере использована подпрограмма-функция, осуществляющая приём байта из . В названиях подпрограмм отображены действия, выполняемые этими подпрограммами.
Вложенные блоки и области действия переменных
Любой объект, который объявляется в программе на языке PL/M-51, имеет область действия. Область действия существует для:
переменных подпрограмм метокОбласть действия объекта представляет собой часть программы, в которой объявляется идентификатор объекта за вычетом текста, содержащегося в любом вложенном в него блоке, в котором объявляется тот же самый идентификатор. К объектам запрещено обращение до того, как они будут объявлены. Это ограничение не касается меток.
Такое определение области действия позволяет не следить при написании программы за использованием идентификаторов, которые уже были использованы в программе в других модулях.
Некоторые блоки могут содержать вложенные блоки, как показано в следующих примерах. Использование внутренних блоков позволяет объявлять локальные переменные. Это позволяет использовать одни и те же ячейки памяти для различных переменных и тем самым экономить ресурсы памяти данных.
Пример 1:
Пример 2:
Переменные существуют только в пределах блока. Если внутри блока были присвоены локальным переменным какие-то значения, то не следует ожидать, что вернувшись снова в этот блок переменные сохранят эти значения. При использовании локальных переменных им назначаются одни и те же ячейки памяти.
Это правило не распространяется на вызов подпрограмм. При вызове подпрограммы переменная, объявленная в блоке становится недоступной, но при возвращении в этот блок она сохраняет свое значение.
[] [] []