Цикл for arduino. Цикл for в Arduino: Урок по использованию и оптимизации кода

Что такое цикл for в Arduino. Как правильно использовать цикл for для оптимизации кода. Какие преимущества дает применение цикла for в Arduino проектах. Как избежать типичных ошибок при работе с циклом for.

Что такое цикл for и зачем он нужен в Arduino

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

Основные преимущества использования цикла for в Arduino:

  • Компактность кода — позволяет заменить повторяющиеся строки одним циклом
  • Гибкость — можно легко изменять количество повторений
  • Оптимизация памяти — занимает меньше места в памяти, чем повторение кода
  • Удобство при работе с массивами и пинами Arduino

Синтаксис цикла for в Arduino

Базовый синтаксис цикла for выглядит следующим образом:

for (инициализация; условие; инкремент) {
  // код, который нужно повторять
}

Где:


  • Инициализация — выполняется один раз в начале цикла
  • Условие — проверяется перед каждой итерацией
  • Инкремент — выполняется в конце каждой итерации

Например, простой цикл для мигания светодиодом 5 раз:

for (int i = 0; i < 5; i++) {
  digitalWrite(LED_PIN, HIGH);
  delay(500);
  digitalWrite(LED_PIN, LOW); 
  delay(500);
}

Оптимизация кода с помощью цикла for

Одно из главных применений цикла for в Arduino - это оптимизация кода при работе с несколькими пинами. Как это работает?

Рассмотрим пример установки нескольких пинов в режим OUTPUT без использования цикла:

pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);

А теперь оптимизируем этот код с помощью цикла for:

for (int pin = 2; pin <= 6; pin++) {
  pinMode(pin, OUTPUT);
}

Как видим, код стал значительно компактнее и его легче модифицировать при необходимости.

Работа с массивами через цикл for

Цикл for отлично подходит для обработки массивов в Arduino проектах. Это особенно полезно при работе с несколькими светодиодами, кнопками или датчиками.

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


int ledPins[] = {2, 3, 4, 5, 6};

void setup() {
  for (int i = 0; i < 5; i++) {
    pinMode(ledPins[i], OUTPUT);
  }
}

void loop() {
  for (int i = 0; i < 5; i++) {
    digitalWrite(ledPins[i], HIGH);
    delay(100);
    digitalWrite(ledPins[i], LOW);
  }
}

Этот код последовательно включает и выключает 5 светодиодов, подключенных к пинам 2-6.

Вложенные циклы for в Arduino

Иногда в Arduino проектах возникает необходимость использовать вложенные циклы for. Это может быть полезно, например, при работе с матрицами светодиодов.

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

int rows[] = {2, 3, 4};
int cols[] = {5, 6, 7};

void setup() {
  for (int i = 0; i < 3; i++) {
    pinMode(rows[i], OUTPUT);
    pinMode(cols[i], OUTPUT);
  }
}

void loop() {
  for (int r = 0; r < 3; r++) {
    for (int c = 0; c < 3; c++) {
      digitalWrite(rows[r], HIGH);
      digitalWrite(cols[c], LOW);
      delay(100);
      digitalWrite(rows[r], LOW);
      digitalWrite(cols[c], HIGH);
    }
  }
}

Этот код последовательно включает светодиоды в матрице 3x3, создавая эффект бегущего огня.


Типичные ошибки при использовании цикла for

При работе с циклом for в Arduino проектах начинающие разработчики часто допускают некоторые ошибки. Рассмотрим самые распространенные из них:

1. Бесконечный цикл

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

Пример неправильного кода:

for (int i = 0; i < 5; i--) {
  // Этот цикл никогда не завершится
}

Как исправить: Убедитесь, что инкремент в цикле for изменяет переменную в нужном направлении.

2. Выход за границы массива

Еще одна распространенная ошибка - попытка обратиться к элементу массива за его границами.

Пример неправильного кода:

int arr[] = {1, 2, 3, 4, 5};
for (int i = 0; i <= 5; i++) {
  Serial.println(arr[i]); // Ошибка при i = 5
}

Как исправить: Используйте строгое неравенство (<) вместо нестрогого (≤) при работе с индексами массива.

3. Неправильное использование фигурных скобок

Некорректное использование фигурных скобок может привести к неожиданному поведению программы.

Пример неправильного кода:

for (int i = 0; i < 5; i++);
{
  digitalWrite(LED_PIN, HIGH);
  delay(500);
  digitalWrite(LED_PIN, LOW);
  delay(500);
}

Как исправить: Уберите точку с запятой после условия цикла for.


Альтернативы циклу for в Arduino

Хотя цикл for очень удобен, в некоторых ситуациях могут быть более подходящие альтернативы. Рассмотрим два основных варианта:

Цикл while

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

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

int sensorValue = 0;

while (sensorValue < 100) {
  sensorValue = analogRead(A0);
  delay(100);
}

Этот код будет считывать значения с аналогового входа A0, пока оно не превысит 100.

Цикл do-while

Цикл do-while похож на while, но гарантирует, что тело цикла выполнится хотя бы один раз.

Пример использования do-while:

int buttonState;

do {
  buttonState = digitalRead(BUTTON_PIN);
  digitalWrite(LED_PIN, HIGH);
  delay(100);
  digitalWrite(LED_PIN, LOW);
  delay(100);
} while (buttonState == LOW);

Этот код будет мигать светодиодом, пока не будет нажата кнопка, при этом светодиод мигнет как минимум один раз.

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

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


Цикл for с несколькими переменными

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

for (int i = 0, j = 10; i < 5 && j > 0; i++, j--) {
  // Код цикла
}

Этот цикл будет выполняться 5 раз, увеличивая i и уменьшая j одновременно.

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

Иногда требуется создать намеренно бесконечный цикл:

for (;;) {
  // Код, который будет выполняться бесконечно
  // Здесь должно быть условие выхода, например, break
}

Этот цикл будет выполняться бесконечно, пока не будет выполнено условие выхода (например, с помощью оператора break).

Заключение

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


Многозадачность в микроконтроллерах Arduino, Wemos, ECP8266

6 августа 2020 г.

Текст видео

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

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

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

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

В переменных startMillis и endMillis будет храниться значения этой временной метки в начале цикла и в конце. Кажется что для того чтобы посчитать время выполнения нужно из endMillis вычесть startMillis, но это не всегда так. Дело в том, что самое большое беззнаковое целочисленное число которое можно сохранить в нашем микроконтроллере занимает 4 байта. Давайте проверим, какое максимальное значение можно сохранить в переменную типа unsigned long, и что будет при его переполнении.

Объявим константу макс ю л и сохраним в нее максимальное значение unsigned long. Префикс 0x означает, что дальше за ним будет значение байт в шестнадцатеричной кодировке.

Без префикса десятичная система исчисления

В – двоичная система исчисления

0 – восьмеричная система исчисления

(07 в десятичной системе счисления это 7, а 016 это 14) O_O будьте внимательны

0x – шестнадцатеричная система исчисления

Восемь F следом это значение этих байт. По два символа на каждый байт. Т.е. в двоичной кодировке все 4 байта окажутся заполненные единицами. UL в конце означает что эти байты объявлены как тип данных unsigned long.

Если вывести это значение в консоль, то оно выведется в привычной для нас десятичной форме. Таким образом, мы выяснили, что максимальное значение unsigned long это то число, которое вы видите на экране.

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

Получилось 999. Очевидно, что когда значение переполнилось, то оно вначале стало нулем, а потом к нему добавилось еще 999.

Получается, что наш счетчик времени через 4 миллиарда миллисекунд переполнится и начнет считать сначала. Это произойдет примерно через 49 дней. Я не хочу, чтобы это устройство начало сбоить через 49 дней. Поэтому чтобы убедиться, что эта программа адекватно отреагирует на переполнение счетчика миллисекунд, я предлагаю приблизить эту дату и посмотреть, что будет, когда она настанет. Для этого я написал специальную функцию, которая возвращает временную метку в миллисекундах, которая переполнится через 30 секунд. Везде где нужно получить время в миллисекундах я буду использовать эту функцию. Таким образом, если в программе не будет ошибки через 30 секунд, то и через 49 дней ее не будет то же.

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

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

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

Что же, все работает как надо. Погрешность всего несколько миллисекунд. Это вполне приемлемо.

На этом модификация основного цикла программы завершена.

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

Получение точного времени из интернета в целом работает так. В интернете есть специальные сервера которые ведут очень точный счет времени. К ним можно отправить короткий бинарный запрос длинной в 48 байт на UDP сокет с портом 8888. В ответ они пришлют другие 48 байт с точным временем. Задержки при передаче данных при этом учитываются. Этот протокол называется NTP, т.е. Network Time Protocol. Я не буду сейчас рассматривать его более подробно. Код для получения точного времени из интернета я взял из примеров этой библиотеки.

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

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

Метод timeString() возвращает время в понятном для человека формате. Методы hour(), minute(), second(), day(), month() это как раз и есть то, новое что появилось в нашей программе после подключения библиотеки TimeLib.

Аналогичным образом модифицируем код для получения информации с метеодатчиков. При этом запрос на получение информации я буду отправлять один раз в пять минут, а ответ буду проверять в каждом цикле. 5 минут это 300 секунд, но я выберу значение 301.

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

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

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

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

Ссылки на исходный код, я оставлю в описании под видео.

Пины PIN ардуино. Режим pinmode output в цикле

Функция имеет значение
pinMode(<номер пина>, <тип>) и не возвращает никаких значений.

Как мы уже определили значение Input установлено по умолчанию, поэтому мы его обсуждать не будем, а остановимся на Output.

Рад приветствовать на своём канале моих подписчиков и просто заглянувших посмотреть что же здесь такого. Надеюсь, что вы тоже подпишитесь на канал. Приятного просмотра.
В режиме OUTPUT Arduino выдаёт на внешнее устройство максимально возможный ток и по сути ваша плата становится  источником тока. Максимальный ток, который можно снять с выхода ардуино – 40 мА. Для работы обычного, не мощного светодиод, например, 5мм одноцветного светодиод надо 20 мА, и это практически единственное устройство которое можно питать напрямую от Ардуино. Всё остальное надо подключать через внешний транзистор или реле.

На этом закончим теорию и перейдём к практике.
Сначала создадим обычный скетч который мы пишем всегда. В нём установим 12 выводов Ардуино в режим Output. Как видите – на это потребовалось достаточно много времени и заняло почти 30 строчек кода. Подумаем, как можно сделать короче.

Так как в этом примере все выводы идут по порядку, то можно сделать обычный цикл, и в нём присвоить всем выводам значение OUTPUT.
Создаём две переменные, начало и конец и присваиваем им значения первого и последнего вывода пина Ардуино, а дальше просто в цикле перебираем по очереди все пины и присваиваем им значения Output. Это отлично работает, но есть одно но. А вдруг вам не нужны все пины в состоянии выхода, вдруг какие-то надо оставить в состоянии Input, тогда этот пример не подойдёт.
Призовём себе на помощь массив и пропишем в него только те пины которые нам надо установить в состояние Output. Массив может быть любой размерности и пины в нём не обязательно указывть по порядку. Можно указать в любой последовательности. А теперь всё так же в массиве присвоим им значение Output.
Ну и напоследок напишем тот же пример, но с прямым обращения к регистрам микроконтроллера. Мы уложились всего в 4 строчки кода и здесь всё понятно и просто.

Так же это поможет сократить занимаемую память и увеличить скорость работы до 5 раз. Это было описано в этом уроке.

Подведём итог.
Вот так выглядит код всех трёх примеров на одной странице. Каким способом пользоваться решайте сами, но знать и уметь пользоваться разными способами надо уметь, вдруг когда-нибудь пригодится.

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

 

Скетчи

Arduino IDE: цикл while — STEMpedia

Об этом руководстве

В этом руководстве обсуждается, что такое цикл while, его общий синтаксис в Arduino IDE, чем он отличается от цикла for и как он работает.

Учебная информация

Требуемые компоненты

Изображение Компонент Количество Доступен в комплекте
ивив 1
  • евив
Кабель USB A-B 1
  • евив

Введение

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

Структура

В следующем примере показаны общие в то время как синтаксис цикла в Arduino IDE. В скобках написано управляющее выражение, т.е. условие. В отличие от цикла for , цикл while имеет только одно выражение в скобках, а поведение цикла зависит от активности внутри тела цикла.

while (условие) {
Тело цикла while
}

Ниже представлена ​​блок-схема, показывающая, как работает цикл while :

Пример

 

[tutorialRelatedProjects]

Программирование

. Есть ли способ перейти к началу функции void loop(), похожей на ключевое слово «продолжить» в циклах c?

спросил

Изменено 1 год, 4 месяца назад

Просмотрено 585 раз

Я новичок в программировании Arduino и пытаюсь создать машину, избегающую препятствий, с ультразвуковым датчиком и дифференциальной моделью драйвера. Изучая, как его кодировать, я узнал, что вы можете выйти из функции void loop() с помощью exit(0) , чтобы завершить программу, аналогичную ключевому слову break на языке C. Есть ли что-нибудь подобное, что я могу использовать для имитации ключевого слова «продолжить», скажем, если я не хочу запускать код после определенной строки в функция void loop() .

  • программирование

4

В функции loop() return выполнит эту функцию. При выходе из функции цикл for() в main() (которого мы не видим) снова повторяется, снова вызывая loop() .

Другой способ сделать то же самое — написать все в вашей функции setup() , включая любую конструкцию цикла, которую вы хотите, и использовать перерыв; и продолжаются; Операторы , к которым вы привыкли:

 void setup(){
 // вызовы pinMode() и digitalWrite()
 // Инициализируем последовательный порт, если вам нужно
 // Любая другая разовая настройка
 //
 // Здесь все происходит:
 за( .

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

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