Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

691_Mikushin_A.V._Programmirovanie_mikroprotsessorov_

.pdf
Скачиваний:
48
Добавлен:
12.11.2022
Размер:
1.96 Mб
Скачать

Символьные константы имеют тип int и при преобразовании типов дополняются знаком. Символьные константы используются обычно при управлении микроконтроллерным устройством от клавиатуры. Пример использования символьной константы на языке программирования C-51 приведён ниже:

if(NajKn=='p') VklUstr();

В этом примере если в переменной NajKn содержится код, соответствующий букве "p", то будет выполнена подпрограмма VklUstr.

Строковые константы. Если символьные константы используются обычно при вводе информации с клавиатуры, то при отображении информационных сообщений обычно используются целые строки символов. В строке допускается использование пробелов.

Строковая константа (литерал или литеральная строка) – это последовательность символов (включая строковые и прописные буквы русского и латинского алфавита, а также цифры) заключенные в кавычки ("). Например: "Школа

N 35", "город Тамбов", "YZPT КОД".

Отметим, что все управляющие символы, кавычка ("), обратная дробная черта (\) и символ новой строки в литеральной строке и в символьной константе представляются соответствующими управляющими последовательностями. Каждая управляющая последовательность представляет собой один символ. Например, при печати литеральной строки "Школа \n N 35" его часть "Школа" будет напечатана на одной строке, а вторая часть "N 35" на следующей строке.

Символы литеральной строки обычно хранятся в памяти программ, но могут храниться и в памяти данных. В конец каждой литеральной строки компилятором добавляется нулевой символ, который можно записать как: "\0". Именно этот символ и является признаком конца строки.

Литеральная строка рассматривается как массив символов (char[ ]). Отметим важную особенность: число элементов массива равно числу символов в строке плюс 1, так как нулевой символ (символ конца строки) также является элементом массива. Все литеральные строки рассматриваются компилятором как различные объекты.

Одна литеральная строка может выводиться на дисплей как несколько строк. Такие строки разделяются при помощи обратной дробной черты и символа возврата каретки \n. На одной строке исходного текста программы можно записать только одну литеральную строку. Если необходимо продолжить написание одной и той же литеральной строки на следующей строке исходного текста программы, то в конце строки исходного текста можно поставить обратную строку. Например, исходный текст:

"строка неопределенной \ длины"

полностью идентичен литеральной строке:

"строка неопределенной длины".

21

Однако более удобно для объединения литеральных строк использовать символ (символы) пробела. Если в программе встречаются два или более литерала, разделенные только пробелами или символами табуляции, то они будут рассматриваться как одна литеральная строка. Этот принцип можно использовать для формирования литералов, занимающих более одной строки.

1.4. Выражения в операторах языка программирования C-51

Выражением называется комбинация знаков операций и операндов, результатом которой является определенное значение. Знаки операций определяют действия, которые должны быть выполнены над операндами. Каждый операнд в выражении в свою очередь может быть выражением. Значение выражения зависит от расположения знаков операций и круглых скобок в выражении, а также от приоритета выполнения операций. Примеры выражений:

А+В

A*(B+C)-(D-E)/F

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

Операндом в выражении может быть переменная, числовая константа, подпрограмма-функция или указатель. Любой операнд, который имеет константное значение, называется константным выражением. Каждый операнд имеет тип.

Если в качестве операнда используется константа, то ему соответствует значение и тип представляющей его константы. Целая константа может быть типа int, long, unsigned int, unsigned long, в зависимости от ее значения и от формы записи. Символьная константа имеет тип int. Константа с плавающей точкой всегда имеет тип float.

При вычислении выражений тип каждого операнда может быть преобразован к другому типу. Преобразования типов могут быть неявными, при выполнении операций и вызовов функций, или явными, при выполнении операций приведения типов. Из-за того, что неявные преобразования типов могут различаться для трансляторов разных фирм, то при написании программы лучше использовать явное преобразование типов переменных. Примеры явных преобразований типов операндов:

a=(int)b+(int)c;

//Переменные a и b могут быть восьмиразрядными. Преобразование типов

 

//нужно чтобы избежать переполнения

s=sin((float)a/15)); //Если не преобразовать тип переменной a, то деление будет целочисленным //и результат деления будет равен нулю.

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

22

как и в обычной алгебраической записи. Использование подвыражений позволяет сократить количество операторов в программе, а значит, и объем исходного текста программы (но не объём исполняемой программы), но затрудняет отладку этой программы.

В языке программирования C-51 используются арифметические операции, результат которых зависит от типа операндов:

1.+ суммирование

2.– вычитание

3.* умножение

4. / деление

5. % вычисление остатка от целочисленного деления

Примеры выражений, использующие арифметические операции:

А+В А+В-С A*T+F/D

A*(B+C)-(D-E)/F

В языке программирования C-51 также определено несколько одноместных арифметических операций:

1.'–' изменение знака операнда на противоположное значение

2.'+' знак плюс не влияет на значение операнда

3.'++' увеличение значения операнда на единицу

4.'--' уменьшение значения операнда на единицу

Для одноместной операции требуется один операнд, которому она предшествует. Например:

P3 = -5; //Присвоить порту P3 значение числа -5

a = -b; //Присвоить переменной a отрицательное значение переменной b с=++a + 2; //Увеличить значение переменной a на 1 и прибавить 2

с=a++ + 2; /*Прибавить к переменной a 2, присвоить это значение переменной c и только после этого увеличить значение переменной a на 1.*/

Над операндами можно осуществлять логические операции:

1.'&&' логическое “и”

2.'&' побитовое логическое “и”

3.'||' логическое “или”

4.'|' побитовое логическое “или”

5.'^' “исключающее или” (суммирование по модулю два)

Здесь следует объяснить различие между логическими и побитовыми логическими операциями. Дело в том, что в стандартном языке ANSI C не существует битовых переменных. Для хранения битовых значений истина ‘1’ и ложь

23

‘0’ используются стандартные целые типы переменных. В простейшем случае это байт. При этом все значения переменной, отличающиеся от 0, считаются 1. Например, пусть в переменной a хранится число 5, а в переменной b – число 6. Тогда:

a|b=7 //00000101 or 00000110 = 00000111

a||b=1 //(00000101)->1 (00000110)->1; (1 or 1= 1), Результат равен 00000001 a&b=4 //00000101 and 00000110 = 00000100

a&&b=1 //(00000101)->1 (00000110)->1; (1 and 1= 1), Результат равен 00000001 a^b=3 //00000101 xor 00000110 = 00000011

В языке программирования C-51 также определено несколько одноместных логических операций:

1.'!' инверсия операнда

2.'~' побитовая инверсия операнда

Например, пусть в переменной a хранится число 5. Тогда:

a=~a; //~00000101 = 11111010 = 250 a=~a; //~11111010 = 00000101 = 5 a=!a; //(00000101)->1; ~1 = 0 a=!a; // ~0 = 1

В условном операторе и операторах цикла используются операции отно-

шения:

1.< меньше

2.> больше

3.<= меньше или равно

4.>= больше или равно

5.== равно

6.!= не равно

Если указанное отношение между операндами верно, то результат равен 1, иначе 0. Например, если d = 7, то:

(d > 5) результат будет 1 (истина) (d = 4) результат будет 0 (ложь)

Над переменными-указателями возможно проведение адресных операций.

1.'*' операция косвенной адресации

2.'&' вычисление адреса переменной

Операция косвенной адресации ‘*’ осуществляет доступ к переменной при помощи указателя. Результатом операции является значение переменной, на которую указывает операнд. Типом результата является тип переменной, адресуемой указателем. При работе с указателями необходимо быть предельно

24

осторожными, так как, если указатель содержит недопустимый адрес, то результат операции чтения или записи будет непредсказуем и может привести к выходу проектируемого устройства из строя.

Операция вычисления адреса переменной ‘&’ дает адрес ячейки памяти своего операнда. Операндом может быть любой идентификатор. Имя функции или массива также может быть операндом операции вычисления адреса переменной, хотя в этом случае знак операции вычисления адреса переменной является лишним, так как имена массивов и функций являются и так являются адресами. Операция вычисления адреса переменной не может применяться к элементам структуры, являющимися полями битов, и к объектам с классом памяти register.

Пример использования адресных операций при работе с указателем:

int t, f=0, *adress;

adress = &t /*переменной adress, объявленной как указатель, присваивается адрес переменной t */

*adress =f; /*переменной находящейся по адресу, содержащемуся в переменной adress, присваивается значение переменной f, т.е. 0, что эквивалентно t=f; т.е. t=0;*/

Может возникнуть вопрос: а зачем тогда нужны указатели, если можно прекрасно обойтись обычным присваиванием переменной? Использование указателей очень удобно при написании подпрограмм. Ведь одни и те же действия подпрограмма должна выполнять над различными участками памяти! Конкретный адрес переменной будет передан в подпрограмму при её вызове. Рассмотрим пример вывода информации через последовательный порт:

void PutNadp(char code *c)//Объявлен указатель c на символ в памяти программ

{do{while(!TI);

//Подождать готовности последовательного порта

TI=0;

 

SBUF=*c++;

//Передать очередной символ

}while(*c!=0);

//Если передан последний символ строки

}

//то выйти из подпрограммы

...

 

PutNadp("привет!");

//Вывод одной строки

...

 

PutNadp("Вася!");

//Вывод второй строки

Приоритеты выполнения операций.

В языке С-51 операции с высшими приоритетами вычисляются первыми. Наивысшим приоритетом является приоритет равный 1. Приоритеты и порядок операций приведены в табл. 6. Порядок вычисления выражения следующий: сначала выполняются операторы в круглых скобках, в них от старшего приоритета к младшему, а среди равнозначных операторов – слева направо.

25

 

 

 

Таблица 6

Приоритет

Знак операции

Типы операции

Порядок

выполнения

 

 

 

2

() [] . ->

Выражение

Слева направо

1

- ~ ! * & ++ -- sizeof

Унарные

Справа налево

 

операции

 

 

 

приведения типов

 

 

3

* / %

Мультипликативные

Слева направо

4

+ -

Аддитивные

 

5

<< >>

Сдвиг

 

6

< > <= >=

Отношение

 

7

== !=

Отношение (равенство)

 

8

&

Поразрядное И

 

9

^

Поразрядное исключаю-

 

 

 

щее ИЛИ

 

10

|

Поразрядное ИЛИ

 

11

&&

Логическое И

 

12

||

Логическое ИЛИ

 

13

? :

Условная

 

14

= *= /= %= += –=

Простое и составное

Справа налево

 

&= |= >>= <<= ^=

присваивание

 

15

,

Последовательное

Слева направо

 

 

вычисление

 

1.5.Операторы языка программирования C-51

Вязыке программирования C-51 используется два типа операторов: операторы объявления и выполняемые операторы. Все операторы C-51 заканчиваются точкой с запятой.

Операторы объявления.

Объявление является неисполняемым оператором, который объявляет некоторый объект или набор объектов, связывает с ним один или несколько идентификаторов и, если это необходимо, распределяет память микроконтроллера.

В объявлении могут быть объявлены три типа объектов: переменные, метки и функции. В программе для каждого имени допустимо только одно объявление. Метка полностью объявлена, если она стоит перед выполняемым оператором и заканчивается с двоеточием ‘:’. Например:

vfg: svGorit(); //Вызов подпрограммы с именем svGorit

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

26

char Rejim; //Переменная, хранящая номер режима размером в один байт

int Schet; //Переменная, использующаяся как счётчик размером в два байта

В языке программирования C-51 нет необходимости знать конкретный адрес переменной, достаточно обратиться к ней по имени Rejim или Schet.

Функция объявляется точно так же как и переменные. То есть перед именем подпрограммы-функции записывается тип переменной, которую возвращает подпрограмма после своего завершения. Так как в подпрограмму в свою очередь тоже могут передаваться переменные, которые называются параметрами подпрограммы, то эти переменные записываются в скобках после имени подпрограммы-функции. Перед каждой переменной обязательно указывается ее тип. Например:

char PrinjatByte(void); //Подпрограмма, предназначенная для приёма одного байта.

Так как подпрограмме приёма обычно не требуется никаких дополнительных переменных, то вместо переменной-параметра подпрограммы указано слово void, обозначающее, что у подпрограммы-функции нет параметров.

Исполняемые операторы.

Оператор присваивания:

Условный оператор.

Структурный оператор.

Оператор цикла for

Оператор цикла с проверкой условия до тела цикла

Оператор цикла с проверкой условия после тела цикла

Оператор continue

Оператор выбора

Оператор безусловного перехода

Оператор выражение

Оператор возвращения из подпрограммы

Пустой оператор

При вычислении операторов используются выражения, в состав которых входят одноместные, двухместные и трёхместные операции.

Оператор присваивания.

Оператор присваивания записывается в виде:

Переменная=выражение;

Выражение вычисляется, и полученное значение присваивается переменной. Например:

P0=2; //Установить начальные потенциалы на ножках второго порта микроконтроллера

a=cos(b*5); //Этот оператор присваивания осуществляет вызов подпрограммыфункции.

27

Достаточно часто требуется изменять значение какой-либо переменной. То есть и источником и приёмником данных служит одна и та же переменная. В этом случае можно воспользоваться составным оператором присваивания. Использование составного оператора сокращает исходный текст программы. Например:

sum+=3;

//Оператор эквивалентен оператору sum=sum+3;

Umensh-=5;

//Оператор эквивалентен оператору Umensh=Umensh-5;

a*=10;

//Оператор эквивалентен оператору a=a*5;

mask&=0x10;/* Оператор эквивалентен оператору mask=mask&5;

Обычно используется для записи нулей в определённые биты пере-

менной */

Условный оператор.

Оператор if обеспечивает условное выполнение операторов. Он записывается в следующей форме:

if(<выражение>) <operator-1>;

[else <operator-2>;]

При этом ключевое слово else со следующим за ним исполняемым оператором представляют собой необязательную часть условного оператора. Если результат вычисления выражения равен 1 (истина), то выполняется operator-1. Если результат вычисления выражения равен 0 (ложь), то выполняется operator-2. Если выражение ложно и отсутствует оператор-2, то выполняется оператор, следующий за условным. Пример записи условного оператора:

if(Wes<Min)

/*Условная операция*/

Schetch=Schetch+1;

/*Плечо 1*/

else

 

Schetch=0;

/*Плечо 2*/

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

if(P1.5)fnKn5Naj(); /* В этом примере предполагается, что к пятой ножке порта P1 подключена кнопка с надписью "5"*/

if(Kn5Naj)fnKn5Naj(); /* Этот пример эквивалентен предыдущему, но ножке P1.5 поставлена в соответствие переменная Kn5Naj*/

if(PrinjatByte())DecodCmd(); /* Предполагается, что функция PrinjatByte возвращает значение '1', если байт принят*/

28

В приведённом примере использована подпрограмма-функция, осуществляющая приём байта из последовательного порта. В названиях подпрограмм отображены действия, выполняемые этими подпрограммами.

Структурный оператор {}.

Существует два основных способа использования структурного оператора:

1.Структурный оператор может рассматриваться в качестве отдельного оператора языка С-51 и использоваться в программе везде, где может встречаться отдельный исполняемый оператор. Это используется в опе-

раторах for, while, do while, switch of и if;

2.Структурный оператор ограничивает область действия локальных переменных.

Каждый оператор внутри структурного оператора может являться любым оператором языка C-51, в том числе и объявлением, при условии, что все объявления внутри структурного оператора должны быть выполнены до первого исполняемого оператора.

Структурный оператор начинается с открывающей скобки ‘{‘ и записывается в следующем виде:

{<operator-1>; //Здесь могут быть объявления переменных

<operator-2>;

...

<operator-n>;

}

Заметим, что в конце составного оператора точка с запятой не ставится. Пример использования структурного оператора:

if(Wes<Min)

/*Условная операция*/

{incr=incr*2;

/*Структурный оператор*/

Schetch=Schetch+1; /*Содержит два оператора*/

}

Структурные операторы могут вкладываться друг в друга:

{<operator-1>; <operator-2>; {<operator-A>; <operator-B> <operator-C>;

}

<operator-3>; <operator-4>;

}

Пример использования объявлений внутри вложенного структурного оператора:

29

int main () {int q,b; float t,d;

...

if(...) {int e,g;

float f,q;

...

}

...

return (0);

}

Переменные e, g, f, q будут уничтожены после выполнения составного оператора. Отметим, что переменная q является локальной в составном операторе, т.е. она никоим образом не связана с переменной q объявленной в начале функции main с типом int. Отметим также, что выражение стоящее после return может быть заключено в круглые скобки, хотя наличие последних необязательно.

Оператор цикла for.

Оператор for – это наиболее общий способ организации цикла. Оператор цикла for записывается в следующей форме:

for ( выражение 1 ; выражение 2 ; выражение 3 ) тело цикла;

Выражение 1 обычно используется для установления начального значения переменных, управляющих циклом. Выражение 2 – это выражение, определяющее условие, при котором тело цикла будет выполняться. Выражение 3 определяет изменение переменных, управляющих циклом после каждого выполнения тела цикла. В качестве тела цикла может служить любой исполняемый оператор языка C-51, в том числе и составной оператор. Внутри составного оператора может быть заключено любое количество исполняемых операторов.

Схема выполнения оператора for:

1.Вычисляется выражение 1.

2.Вычисляется выражение 2.

3.Если значения выражения 2 отлично от нуля (истина), выполняется тело цикла, вычисляется выражение 3 и осуществляется переход к пункту 2, если выражение 2 равно нулю (ложь), то управление передается на оператор, следующий за оператором for.

Обратите внимание, что проверка условия всегда выполняется в начале цикла. Это значит, что тело цикла может ни разу не выполниться, если условие выполнения сразу будет ложным.

Пример использования оператора for:

for(i=1;i<10;i++) //от i равного 1 до 10 с шагом 1 выполнить b=i*i;

В этом примере вычисляются квадраты чисел от 1 до 9.

30