Циклы в языке С (Си) для микроконтроллеров AVR


В данной статье будут рассмотрены циклы в языке программирования Си для микроконтроллеров AVR. Будут рассмотрены циклы типа "для" (for) и циклы типа "пока" (while), будет показано как осуществить принудительное прерывание цикла и организовать бесконечный цикл. Рассмотрены вопросы вложенных циклов и формирования длительных временных задержек.

Структура цикла с предусловием

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

В языке С есть две разновидности циклов: циклы со счетчиком (типа "для" или for) и цикл с условием (типа "пока" или while). В других языках программирования, например Pascal, циклы с условием разделялись на циклы с предусловием (типа while) и циклы с пост условием (типа repeat until), но в современных языках программирования циклы с пост условием постепенно отмирают.

Циклы типа "для" (for)

Циклы типа "для" (for) применяются в ситуациях, в которых заранее известно количество повторений цикла. Поэтому в составе подобного цикла всегда есть так называемый "счетчик повторений" или "переменная цикла". Пример использования цикла for в языке представлен на следующем рисунке.

В данном примере тело цикла повторится столько раз, сколько значений "пробежит" переменная цикла i от своего начального значения, задаваемого операцией присваивания i = a, до конечного значения, задаваемого условием i < b. Изменение переменной i определяется условием присваивания вида i = i + c. Но чаще всего в циклах типа for в языке С переменная цикла изменяется за одно повторение цикла на +1 или -1, поэтому используется запись вида i++ (инкремент переменной цикла) или i-- (декремент переменной цикла). В рассмотренном примере при i = b цикл завершается и выполняется оператор, следующий за закрывающей скобкой цикла.

Рассмотрим пример цикла for, приведенный на следующем рисунке.

В этом примере на первом шаге цикла переменная i будет равна 1, перед вторым шагом произойдет ее увеличение на 1 в результате инкремента (i++) и она станет равной 2. На третьем шаге значение переменной цикла i будет равно 3. И так до тех пор, пока на пятом шаге цикла она не станет равной 5. В результате следующей операции инкрементирования (i++) переменная цикла получит значение 6, но условие i <= 5 уже не будет истинным, поэтому цикл завершится. Таким образом, тело цикла будет выполнено 5 раз.

Язык С допускает инициализацию переменной цикла в его оглавлении как показано на следующем рисунке.

Но начинающим лучше производить инициализацию переменной цикла в начале функции вместе с остальными инициализируемыми переменными – более подробно читайте об этом в статье про переменные в языке С.

Усовершенствуем программу управления миганием светодиода, рассмотренную в статье про программирование портов микроконтроллеров AVR, с помощью цикла типа "для" (for). Заставим светодиод мигать 10 раз.

Пример подобной программы представлен на следующем рисунке.

Программа для мигания светодиодом 10 раз

Циклы типа "пока" (while)

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

while (условие)
{
// тело_цикла
}

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

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

Пример:

int y;

y = 50;

while (y > 0)
{
y = y - 1;
}

В этом примере тело цикла будет повторено (выполнится) 50 раз, до тех пор пока переменная y будет больше нуля. На каждом шаге цикла значение переменной y будет уменьшаться на 1. И когда оно станет равным 0, цикл завершится.

Оператор break

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

В большинстве случаев он используется следующим образом:

if (условие1) break;

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

Бесконечные циклы

Бесконечный цикл в языке программирования С можно осуществить как с помощью цикла "для" (for), так и с помощью цикла "пока" (while). Синтаксис подобных циклов выглядит следующим образом.

for(;;)
{
// тело_цикла
}

или

while (1)
{
// тело_цикла
}

Чаще применяется способ с циклом типа while – он более нагляден. Выйти из подобных циклов можно единственным образом – применив рассмотренный в предыдущем разделе оператор break.

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

Вложенные циклы

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

Пример вложенного цикла в языке С

Рассмотрим пример двух вложенных друг в друга циклов "для". Тело вложенного цикла в общей сложности будет повторено 200 раз.

В этом примере тело вложенного цикла будет выполнено 200 раз.

Формирование задержки

Аппаратные средства микроконтроллеров AVR не могут формировать длительные задержки – но это, собственно говоря, не очень и нужно потому что сколь угодно длительную задержку можно организовать с помощью циклов (лишь бы имелась возможность формирования хотя бы небольшой задержки). Пример организации задержки длительностью 10 минут с помощью цикла и функции _delay_ms() представлен на следующем рисунке:

Пример организации длительной задержки для микроконтроллеров AVR



Комментарии

Циклы в языке С (Си) для микроконтроллеров AVR — 17 комментариев

    • Ну тогда все нормально. Переключился на написание статей про другие микроконтроллеры/платы, про AVR стал уже чуть чуть забывать, к сожалению

    • Ну попробовать можно, только вот не будет ли такой урок слишком короткий для отдельной статьи

      • Быть может тогда добавить тему "Конечные автоматы для AVR" как развитие темы " Switch".
        К сожалению ,тему конечных автоматов очень трудно найти в уроках для AVR.
        Хотя это очень интересно.
        Спасибо.

        • Надо подумать. А вы случайно не знаете какую-нибудь англоязычную статью где эта тема хорошо освещена? Тогда я бы просто перевел эту статью и эта тема стала бы доступна в сети и на русском языке

          • у меня есть несколько ссылок по этой теме и хороший урок.
            Но я не уверен можно ли публично выставлять чужие уроки.
            Я не нашел здесь email или что похожее на обратную связь.

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

            • https://www.youtube.com/watch?v=2UN2H3mSpLE&list=PL-bJ-cyZJjjDetZrdA7uiYrVvdJSIBZVR&index=56

              jaxcoder.com/Post/Index?guid=3d7c2e49-c587-465b-a1df-861d3fcad914

              popayaem.ru/konechnye-avtomaty-kak-programmirovat-bez-zaparok.html

              digitrode.ru/articles/90-konechnyy-avtomat-na-c.html

              kit-e.ru/micro/switch-1/

              github.com/search?q=Finite+State+Machine

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

  1. А можно в место delay(1000) сделать ту же задержку ну допустим оператором for?

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

    • можно
      #define F_CPU 4000000UL // указываем частоту в герцах
      #define time 30 //объявляем константу time(например 30)
      void pause (unsigned long a)//функция паузы с аргументом а

      {
      unsigned long counter ;//переменная counter
      for(counter=a; counter>0; counter--)
      asm ("nop");//для того, чтобы избежать оптимизации этой ф-ции
      }

      пример использования
      int main(void) {

      ......

      while(1)

      {
      ....
      pause (10000L*time);//пауза рассчитывается в зависимости от частоты F_CPU
      //в данном случае аргумент а=10000L = 10000*(1/4000000)= 2,5( мсек)
      // и еще умножаем на выбранную константу (например 30) получаем 30*2,5=75(мсек)
      ....
      }
      }

      • Ну в принципе идея конечно рабочая, только я вот лично сам никогда не сталкивался с использованием функции asm("nop") и поэтому не знаю за какое время (за сколько тактов) она выполняется

  2. Спасибо, все подробно объяснили. Тема (на мой взгляд) относительно несложная для понимания, поэтому, наверное, и вопросов не возникает 🙂

  3. Что то циклы не вызвали особого интереса у пользователей нашего сайта, пока ни одного комментария ))

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *