Дата последнего обновления файла 23.08.2005

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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', если байт принят

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

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

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

  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>;
}

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

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.

Некоторые варианты использования оператора for повышают его гибкость за счет возможности использования нескольких переменных, управляющих циклом.

Пример:

int main()
 {int top,bot;
  char string[100],temp;
  for(top=0,bot=100;top<bot;top++,bot--)
   {temp=string[top];
    string[bot]=temp;
   }
  return 0;
 }

В этом примере, реализующем запись строки символов в обратном порядке, для управления циклом используются две переменные top и bot. Отметим, что на месте выражение 1 и выражение 3 здесь используются несколько выражений, записанных через запятую, и выполняемых последовательно.

Так как согласно синтаксису языка Си оператор может быть пустым, тело оператора for также может быть пустым. Такая форма оператора может быть использована для организации поиска.

Пример:

for(i=0;t[i]<10;i++);

В данном примере переменная цикла i принимает значение номера первого элемента массива t, значение которого больше 10.

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

for(;;)        //Постоянно
  {Knop=P2;      //опрашивать порт P2
   ObrabSobyt(); //и обрабатывать нажатие кнопок
  }

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

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

Оператор цикла while называется циклом с предусловием и имеет следующий формат:

while (выражение) тело цикла;

Оператор while содержит условную операцию (такую же, как в операторе if), и вызывает исполнение операторов в этом блоке до тех пор, пока условие верно. Проверка условия производится до выполнения тела цикла, поэтому оператор тела цикла может быть не выполнен ни разу. В качестве выражения допускается использовать любое выражение языка Си, а в качестве тела любой оператор, в том числе пустой или составной. Схема выполнения оператора while следующая:

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

Оператор while может быть полезен для ожидания срабатывания какого-либо устройства микроконтроллера, например таймера:

  ...
  while(!TF0);  //Программа ожидает переполнения таймера T0
  TF0=0;
  TL0=time;     //Настроить таймер T0
  TН0=time>>8;  //на очередной интервал времени
  ...

В следующем примере оператор while используется для пошагового прохождения по элементам массива Table до тех пор, пока очередной элемент не превысит значение скалярной переменной с именем Level (уровень англ.):

  i = 0;
  while(table(i)<=Level)i++;

В приведённом примере Table - это предварительно объявленный массив. Переменные Level и i тоже должны быть предварительно объявлены.

Переменной i первоначально присваивается значение 0, затем она используется как индекс для массива Table. Так как i увеличивается при каждом проходе цикла while, то  каждый раз, когда выполняется оператор внутри блока while, с переменной Level сравнивается следующий элемент массива Table. Когда найден элемент, превышающий значение переменной Level, то условие в операторе while больше неверно, выполнение блока не повторяется и управление передается следующему за циклом while оператору. С этого момента переменная i является индексом первого элемента массива Table, который превышает значение переменной Level.

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

Оператор цикла while называется циклом с постусловием и имеет следующий формат:

do тело цикла while (выражение);

Оператор do while содержит условную операцию (такую же, как в операторе if), и вызывает исполнение операторов в этом блоке до тех пор, пока условие верно. Проверка условия производится после выполнения тела цикла, поэтому оператор тела цикла будет выполнен хотя бы один раз. В качестве выражения допускается использовать любое выражение языка Си, а в качестве тела любой оператор, в том числе пустой или составной. Схема выполнения оператора do while следующая:

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

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

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

i=10
do тело цикла; while(--i<0);

Однако, конкретно в реализации компилятора C-51, намного эффективнее следующая конструкция:

for(i=10;i>0;i--) тело цикла;

Операторы while и do while могут быть вложенными.

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

       int i,j,k;
       ...
       i=0;j=0;k=0;
       do{i++;j--;
          while (a[k]<i)k++;
         }
       while(i<30&&j<-30); 

Оператор break

Оператор break обеспечивает прекращение выполнения самого внутреннего из объединяющих его операторов switch, do, for,while. После выполнения оператора break управление передается оператору, следующему за прерванным оператором цикла или выбора.

Оператор continue

Оператор continue, как и оператор break, используется только внутри операторов цикла, но в отличие от него выполнение цикла не прерывается, а начинается следующая итерация цикла. Формат записи оператора:

continue;

Пример:

int main()
{int a,b;
 for(a=1,b=0;a<100;b+=a,a++)
  {if(b%2)continue;
   ... /* обработка четных сумм */
  }
 return 0;
}

Когда сумма чисел от 1 до а становится нечетной, оператор continue передает управление на очередную итерацию цикла for, не выполняя операторы обработки четных сумм.

Оператор continue, как и оператор break, прерывает самый внутренний из объемлющих его циклов.

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

Оператор switch предназначен для организации выбора из множества различных вариантов. Формат оператора следующий:

switch ( выражение )
 {[объявление]
      ...
  [ case  константное-выражение1]: [ список-операторов1]
  [ case  константное-выражение2]: [ список-операторов2]
      ...
      ...
  [ default: [ список операторов ]]
 }

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

Значение этого выражения является ключевым для выбора из нескольких вариантов. Тело оператора smitch состоит из нескольких операторов, помеченных ключевым словом case с последующим константным выражением.

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

Все константные выражения в операторе switch должны быть уникальны. Кроме операторов, помеченных ключевым словом case, может быть, но обязательно один, фрагмент помеченный ключевым словом default.

Список операторов может быть пустым, либо содержать один или более операторов. Причем в операторе switch не требуется заключать последовательность операторов в фигурные скобки.

Отметим также, что в операторе switch можно использовать свои локальные переменные, объявления которых находятся перед первым ключевым словом case, однако в объявлениях не должна использоваться инициализация.

Схема выполнения оператора switch следующая:

  • вычисляется выражение в круглых скобках;
  • вычисленные значения последовательно сравниваются с константными выражениями, следующими за ключевыми словами case;
  • если одно из константных выражений совпадает со значением выражения, то управление передается на оператор, помеченный соответствующим ключевым словом case;
  • если ни одно из константных выражений не равно выражению, то управление передается на оператор, помеченный ключевым словом default, а в случае его отсутствия управление передается на следующий после switch оператор.

Отметим интересную особенность использования оператора switch: конструкция со словом default может быть не последней в теле оператора switch. Ключевые слова case и default в теле оператора switch существенны только при начальной проверке, когда определяется начальная точка выполнения тела оператора switch. Все операторы, между начальным оператором и концом тела, выполняются вне зависимости от ключевых слов, если только какой-то из операторов не передаст управления из тела оператора switch. Таким образом, программист должен сам позаботится о выходе из case, если это необходимо. Чаще всего для этого используется оператор break.

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

Если значение выражения равно 0, то выполняется только первый оператор присваивания, и 0 будет присвоен переменной red (красный англ). Если значение выражения равно 1, то будет выполнен только второй оператор присваивания и переменной blue (голубой англ) будет присвоен 0. Значения выражения 2 и 3 вызовет присваивание 0 переменным green (зеленый англ) и gray (серый англ) соответственно.

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

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

Оператор goto изменяет порядок выполнения программы при помощи передачи управления на оператор, метка которого указана в операторе goto. Оператор goto записывается в следующем виде:

       goto имя-метки;
                  ...
       имя-метки: оператор;

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

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

Использование операторов goto является неизбежным при некоторых ситуациях, однако в большинстве случаев там, где должна быть предусмотрена передача управления, более предпочтительным является использование итеративного оператора while, do while, DO CASE, if или вызова процедуры. Неограниченное использование операторов goto в программе приводит к тому, что программу становится трудно понимать, модифицировать и сопровождать. Реальная практика использования языка C-51 показывает, что в большинстве случаев программные модули могут не содержать оператор goto без ухудшения их эффективности.

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

Любое выражение, которое заканчивается точкой с запятой, является оператором.

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

Примеры записи операторов-выражений:

++ i;         //Этот оператор представляет выражение, 
              //которое увеличивает значение переменной i на единицу.
a(x,y);       //Этот оператор представляет выражение, 
              //состоящее из вызова подпрограммы-процедуры.

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

Оператор return завершает выполнение функции, в которой он задан, и возвращает управление в вызывающую функцию, в точку, непосредственно следующую за вызовом. Формат оператора:

return [выражение] ;

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

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

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

Пример:

int sum(int a,int b)
{return(a+b);
}

Функция sum имеет два формальных параметра a и b типа int, и возвращает значение типа int, о чем говорит описатель, стоящий перед именем функции. Возвращаемое оператором return значение равно сумме фактических параметров.

Пример:

void prov (int a, double b)
{float c;
 if(a<3)
     return;
   else if(b>10)
     return;
   else
     {c=a+b;
      if((2*c-b)==11)return;
     }
}

В этом примере оператор return используется для выхода из функции в случае выполнения одного из проверяемых условий.

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

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

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

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

Пример:

     int main ( )
     {
          ...
           { if (...) goto a;    /* переход на скобку */
               { ...
               }
      a:;  }
           return 0;
       }

Литература:

  1. Микушин А.В. Занимательно о микроконтроллерах. СПб, БХВ-Петербург, 2006.
  2. Микушин А.В., Сажнев А.М., Сединин В.И. Цифровые устройства и микропроцессоры. СПб, БХВ-Петербург, 2010.
  3. Keil uVision3 V3.51 для платформы MCS51

Вместе со статьей "Операторы языка программирования C-51" читают:

Языки программирования для микроконтроллеров
http://digteh.ru/Progr/progr.php

Указатели в C-51
http://digteh.ru/MCS51/C51/pntr_c51.php

Использование функций в языке программирования С-51
http://digteh.ru/MCS51/C51/func.php

Многомодульные программы
http://digteh.ru/MCS51/C51/manymod.php


* Для тех читателей что вышли на эту страницу по поиску прошу обратить внимание, что здесь рассматривается не стандартный язык программирования С, а язык, адаптированный к микроконтроллерам серии MCS-51. Имеются отличия!

Автор Микушин А. В. All rights reserved. 2001 ... 2017

Предыдущие версии сайта:
http://neic.nsk.su/~mavr
http://digital.sibsutis.ru/

Поиск по сайту сервисом Яндекс

Поиск по сайту сервисом ГУГЛ

пЕИРХМЦ@Mail.ru


Яндекс.Метрика
Rambler's Top100