Как сделать один цикл на ардуино: Циклы FOR и WHILE в Arduino
Ускорение и торможение движения робота | Учи Урок информатики
В предыдущем задании мы рассматривали сигналы широтно-импульсной модуляции (ШИМ, PWM). С помощью сигналов ШИМ мы можем плавно увеличивать и уменьшать скорость движения робота.
Описание команды analogWrite
Команда analogWrite (pin, value) записывает значение, используя схему с широтно-импульсной модуляцией (ШИМ, PWM), на выходной вывод, помеченный как PWM. Смотрите карту выводов.
На модуле Arduino с микропроцессором ATmega168 (328) эта функция работает на выводах 3, 5, 6, 9, 10 и 11. Значение может быть задано как переменная или константа в диапазоне 0–255. Значение 0 генерирует устойчивое напряжение 0 вольт на выходе заданного вывода; значение 255 генерирует 5 вольт на выходе заданного вывода. Для значений между 0 и 255 вывод быстро переходит от 0 к 5 вольтам: чем больше значение, тем чаще вывод в состоянии HIGH (5 вольт).
Например, на диаграмме действующих значений, представленной здесь выше, при значении 64 вывод будет в 0 три четверти времени, а в состоянии 5 вольт – одну четверть; при значении 128 половину времени будет вывод будет в 0, а половину – в 5 вольт; при значении 192 четверть времени вывод будет в 0 и три четверти – в 5 вольт.
Описание конструкции for
Для организации ветвления необходимо воспользоваться оператором for:
1 2 3 4
|
for (инициализация; условие; выражение) { действия (тело цикла); }
|
Конструкция команды используется для повторения блока выражений, заключённых в фигурные скобки заданное число раз.
Наращиваемый счётчик часто используется для увеличения и прекращения цикла. Есть три части, разделённые точкой с запятой, в заголовке цикла for: «инициализация» локальной переменной, или счётчика, имеет место в самом начале и происходит только один раз. При каждом проходе цикла проверяется «условие». Если условие остаётся истинным, то следующее выражение и блок выполняются, а условие проверяется вновь. Когда условие становится ложным, цикл завершается.
Конструкция, позволяющая нам последовательно увеличивать или уменьшать значение ШИМ, включает цикл for (инициализация; условие; приращение) и блок операторов, заключенный в скобки.
1 2 3 4 5 6
|
for (int i = 40; i < 255; i++) { analogWrite (SPEED_R, i); analogWrite (SPEED_L, i); delay(50); }
|
Эта запись означает следующее:
К целочисленной переменной i, которая вначале равна 40 прибавляется единичка 1 (i++), пока её значение меньше либо равно 255. При каждом значении переменной i будут выполняться операции, записанные в фигурных скобках (тело цикла). Значение ШИМ, читай напряжение на моторе, каждый цикл продолжительностью 50 миллисекунд от значения 40 будет возрастать до значения 255. Каждый раз в цикле проверяется условие i<255. Если условие верно, то выполняется блок операторов и приращение значения i. Затем условие проверяется вновь. Когда логическое значение условия становится ложным, цикл завершается. В результате наш робот начинает двигаться с постоянной максимальной скоростью.
Торможение робота
Точно так же будет происходить и уменьшение скорости.
for (inti = 255; i > 0; i—)
Цикл for мы можем использовать так же и для записи однотипных команд. В блоке setup нам необходимо пины 2,3,4,5 определить как выходы (OUTPUT). И вместо команды для каждого пина (pin), как мы делали ранее,
1 2 3 4 5 6 7
|
void setup() { pinMode (DIR_R, OUTPUT); pinMode (SPEED_R, OUTPUT); pinMode (DIR_L, OUTPUT); pinMode (SPEED_L, OUTPUT); }
|
пишем цикл, в котором в качестве переменной i указываем номера пинов.
1 2 3 4 5
|
voidsetup () { for (inti=2; i<=5; i++) { pinMode (i, OUTPUT); } }
|
Переходим к практической части задания.
Листинг кода
Скопируйте текст программы и вставьте его в скетч Arduino IDE. После проверки загрузите код в контроллер и включите питание на роботе. Итак, код программы готов, сравните его с тем, что получилось у вас.
Пожалуйста, оцените статью
4.19 из 5. (Всего голосов:261)
Как сделать «двойной break», то есть выйти из вложенного цикла, в Python?
Условие:
Перебрать все пары символов в строке, и остановиться при нахождении двух одинаковых символов.
Решение достаточно очевидное, но возникает вопрос:
s = "какая-то строка"
for i in range(len(s)):
for j in range(i+1, len(s)):
if s[i] == s[j]:
print(i, j)
break # Как выйти сразу из двух циклов?
Если бы мы программировали, например, на Java, то мы могли бы воспользоваться механизмом меток:
outterLoop: for(int i=0; i<n; i++){
for(int j=i; j<n; j++){
if(/*something*/){
break outterLoop;
}
}
}
Однако в Python такого механизма нет. Требуется предложить наиболее удобное в использовании и читаемое решение.
Возможные варианты ответа
- Поместить цикл в тело функции, а затем сделать
return
из неё:def func(): s="teste" for i in range(len(s)): for j in range(i+1, len(s)): if s[i]==s[j]: print(i,j) return func()
Почему это плохая идея: разумеется, сама задача в условии — лишь абстрактный пример. В жизни циклов может быть гораздо больше, и создавать по функции для каждого из них как-то неестественно, не так ли?
- Выбросить исключение и поймать его снаружи цикла:
try: s="teste" for i in range(len(s)): for j in range(i+1, len(s)): if s[i]==s[j]: print(i,j) raise Exception() except: print("the end")
Почему это плохая идея: здесь мы используем механизм исключений как особую форму
goto
, но ведь на самом деле ничего исключительного в коде не произошло — это обычная ситуация. Как минимум, причины такого злоупотребления этим механизмом будут непонятны другим программистам. - Можно создать булевую переменную, которая будет хранить информацию о том, нужно ли выходить из внешнего цикла на данной итерации:
exitFlag=False s="teste" for i in range(len(s)): for j in range(i+1, len(s)): if s[i]==s[j]: print(i,j) exitFlag=True break if(exitFlag): break
Почему это плохая идея: из всех перечисленных выше идей эта, пожалуй, лучшая. Тем не менее, это весьма низкоуровневый подход, и в языке Python есть возможность реализовать задуманное гораздо лучше.
- Использовать вместо двух циклов
for
одинwhile
:s="teste" i=0 j=1 while i < len(s): if s[i] == s[j]: print(i, j) break j=j+1 i=i+j//len(s) j=j%len(s)
Почему это плохая идея: вам не кажется, что такой код читается хуже всех предложенных вариантов?
Решение на пятёрку
Давайте ещё раз внимательно прочитаем условие:
Перебрать все пары символов в строке, и остановиться при нахождении двух одинаковых символов.
Где там вообще хоть слово про двойной цикл или про перебор двух индексов? Нам нужно перебирать пары. Значит, по идее, мы должны написать что-то вроде этого:
s = "teste"
for i, j in unique_pairs(len(s)):
if s[i] == s[j]:
print(i, j)
break
Отлично, так мы будем перебирать пары. Но как нам добиться именно такой формы записи? Всё очень просто, нужно создать генератор. Делается это следующим образом:
def unique_pairs(n):
for i in range(n):
for j in range(i+1, n):
yield i, j
«Как это работает?» — спросите вы. Всё просто. При вызове unique_pairs(int)
код в теле функции не вычисляется. Вместо этого будет возвращён объект генератора. Каждый вызов метода next()
этого генератора (что неявно происходит при каждой итерации цикла for
) код в его теле будет выполняться до тех пор, пока не будет встречено ключевое слово yield
. После чего выполнение будет приостановлено, а метод вернёт указанный объект (здесь yield
действует подобно return). При следующем вызове функция начнёт выполняться не с начала, а с того места, на котором остановилась в прошлый раз. При окончании перебора будет выброшено исключение StopIteration
.
Итак, самый true pythonic way в решении этой задачи:
def unique_pairs(n):
for i in range(n):
for j in range(i+1, n):
yield i, j
s = "a string to examine"
for i, j in unique_pairs(len(s)):
if s[i] == s[j]:
print(i, j)
break
UPD: в комментариях подсказывают, что такой генератор уже реализован в стандартной библиотеке:
itertools.combinations(s, 2)
Что же, для данной задачи это действительно более pythonic решение. Хочется отметить, что целью статьи было скорее познакомить новичков с механизмом генераторов, нежели действительно решить проблему, заявленную в первом абзаце 😉
Свои варианты предлагайте в комментариях!
Разбор взять из статьи «Breaking out of two loops»
Модуль Type C to UART
Была когда-то в обиходе фраза » В Греции все есть». В текущих реалиях ее можно было бы перефразировать, » В Китае все есть». И все к этому более-менее привыкли / адаптировались. В какой-то момент я поменял свой телефон с microUSB на уже всем привычный Type C. И через некоторое время оказалось, что найти дома шнур microUSB стало сильно сложнее, чем Type C. Кроме всего прочего, здесь недавно подняли тему Гайвер-лампы, которую я повторил. И снова оказалось, что программировать и питать лампу через один и тот-же Type C разъем банально удобней. Встраивать в поделки мне очень нравится модули ESP-M3. Они очень компактного размера. По-этому не имеют встроенного uart-а. Все сложилось, и я решил прикупить себе модулей Type C to UART, зашел на Aliexpress, и… ничего не нашел. НИЧЕГО, Карл. Дальнейшее развитие событий и отсыл к пословице «Хочешь сделать хорошо — либо делегируй задачу профессионалам, либо сделай сам» под катом
Задача изначально казалась простой. Type C уже давно в обиходе, значит и преобразователей китайцы должны были наштамповать. На уже привычной элементной базе. Но потратив на поиски такой банальщины несколько дней — я понял, что готового ничего интересного нет.
В процессе поиска наткнулся на сайт человека, который столкнулся с похожей проблемой. Прошерстил github, и понял, что полностью устраивающего меня варианта в доступе нет. Ок. Остается делегирование, либо сам. Я решил, что вариант «сам» — лично мне интересней.
Осталось определиться с постановкой задачи и инструментом, с помощью которого эта задача будет решена.
С задачей понятно, устройство должно:
1) Быть Type C to UART преобразователем, очень желательно, отлично работающим на 921600 (практически все поделки от esp отлично шьются на этой скорости). Соответственно — есть возможность уменьшить время однотипной задачи — уменьшаем.
2) Быть с разъемом Type C Female, т.е. «мама», для встраивания в готовые устройства.
3) Этот же разъем предполагается использовать для питания устройства, поскольку до 100Вт (китайских 🙂 ) можно использовать один и тот-же разъем, это удобно и аккуратно.
4) Поскольку завелось все с момента очередного всплытия gyver lamp — то на ней и обкатываем. Строить ее я собрался на ESP-M3. И это вносит ограничение на обновление по воздуху, поскольку там используется esp8285, а у нее всего 1МБ флешка. Но об этом чуть ниже вспомним. Соответственно — распиновку подгоню под эту плату, для аккуратности.
5) Опять же — использую вполне конкретную плату, соответственно GPIO0 для прошивки нужно дергать вручную. Учтем.
6) На данной плате будут и другие устройства, многим вполне хватит 500мА при 3.3В, но реле / силовая часть вполне может питаться от 12В и выше. Учтем.
7) — ошибся, не получилось — Нужно отдельно управлять питанием, не отсоединяя uart от компьютера. Предполагалось использовать отключаемый стабилизатор напряжения, который отключает нагрузку, и по задумке — конденсатора в 100мкФ (наибольшая емкость в еще удобном габарите) должно было хватить на пару секунд поддержки питания на преобразователе, что бы он не отключался от компьютера. Но если бы предварительно посчитал запасенную энергию — то не ошибся бы здесь 🙂
8) Желательно, но не обязательно, что бы можно было спаять все одним паяльником, без применения паяльной пасты / фена / печи.
Именно первая ссылка подсказала, что есть у китайцев Ch430N в SOP-8 корпусе, для которой еще и кварц не нужен. Ее и было решено использовать. Есть еще Ch440N, в этом же корпусе. И по факту, как я понял — это какая-то программируемая логика, подгоняющаяся под конкретную задачу на финальном этапе. У меня из 10шт в ленте — девять 330N, один 340N.
С питанием — у меня уже есть опыт использования KF33, но опять-таки начало приходить много подделок, плюс выбирал из доступного, плюс что-то свеженькое, проект то некоммерческий. Остановился на LT17633 высокое допустимое входное напряжение, до 20В, мало обвязки, достаточная нагрузочная способность, низкое собственное потребление Цена в районе $0,7 когда подбирал (по факту, скорее всего из-за временного отсутствия в результате цена оказалась $7, что запредельно, пришлось искать на али, нашел).
Свои изделия делаю в KiCad, но и здесь решил поэкспериментировать, поигравшись с автотрассировкой в EasyEda. На текущий момент — там и трехмерная визуализация присутствует и автотрассировщик. Плата мелкая — выбор сделан.
Схема не сложная, выбирал компоненты из доступных на складах (думал заодно протестировать полный цикл от одного поставщика — JLCPCB). Прикинул по справочнику Стеля размер платки — получил 20х20мм. Вроде нормально. Нарисовал схему, раскинул детальки, включил автотрассировку и… получил плату со второй итерации. Опс. Так скоро не ожидал, начал смотреть, удобны ли эти 20х20 — понял, что не очень. Уменьшил размеры, сделал продолговатую плату, с возможностью припаивания на плату. Внешне получалось примерно так:
Вроде бы нормально, но трассировка не завершается, неразведенными остаются от 3 до 9 линий. Менял, компоновал — не выходит. Заодно пощупал принцип автотрассировщика, он начинает работать, когда есть свободное время, но китайцы трудолюбивый народ, и начиналась трассировка один раз из 10-ти. Почитал, что можно скачать модуль трассировщика локально, и запускать тот-же автотрассировщик локально. И да — это работает каждый раз 🙂 Стало чуть быстрей, но не разводится все-равно.
Решил сделать третью итерацию, расположив все пины с одной стороны — это с одной стороны позволит размещать модуль как в горизонтальном расположении на плате, так и в вертикальном, заодно и подправит геометрию. Итого — одна сторона ограничена необходимым количеством пинов, вторая — разъемом Type C. И третья итерация развелась с третьей попытки. Получилось так:
Дальше — заказ плат, заказ компонентов, неувязка с питанием, но уже переделывать не хотелось, отбрасывание варианта как сборки на заводе, так и трафарета. Решил не заморачиваться пока.
Время, ожидание, результат:
Часть железок не доехало, поставил то, что было, спаял — не работает. Опс… Модуль определяется в системе как USB-SERIAL Ch440 но дальше — непонятки. Пока разбирался — обнаружил, что впаянная микросхема Ch440N, хотя 9 оставшихся на той-же ленте Ch430N.
В общем — проблема ни в схемотехнике и ни в микросхеме. Все завелось. Сразу стало понятно, что 100мкФ не удержат питание 2сек, соответственно можно не ставить, развязывающий диод — заменить перемычкой. У модуля есть возможность быть запитанным как от впаянного разъема Type C, так и от любого другого варианта USB, четыре контакта выведены специально для этого. Если использовать встроенный разъем — то можно использовать связку USB A — Type C и Type C — Type C. Если Type C на 4 проводка — то с другой стороны должен быть только USB A (компьютер). Если ответная часть в БП или свежую яблочную продукцию — то питание не поднимется. На вход можно подавать до 20В, т.е. можно подать 12В, с того-же контакта питать силовую часть 12В, а 3.3В нагрузка будет запитана от 3.3В. До 20В напряжение поднимал — все отлично.
Дальше — пришли свежезаказанные ESP-M3, подключил — и меня ждал сюрприз. Посмотрел визуально — отличаются от оригинальных плат от DoIt. Расстроился. Но подключив — обрадовался. В свежих модулях отсюда используются более свежие esp8285 (ESP8285h26), у которых на борту — 2МБ флешка и индустриальным диапазоном температур. И это радует — можно и ОТА использовать, и на улицу выставлять. Просто замечательно.
Тестовая сборка выглядит так:
Сюда подпаял и отдельный модуль с Type C, который можно и вынести на достаточное расстояние. Прошивается на 921600 без проблем, с обоих входов.
Нажатием на среднюю кнопку — снимается питание с нагрузки (из-за недочета и с ch430n, т.е. порт отваливается в системе, можно просто использовать вместо выдергивания шнурка), нажатием на крайнюю кнопку — прижимается к земле пин, подключенный к ext выводу. В моем случае — это GPIO0, для перевода модуля в режим программирования.
По итогу — получился вполне неплохой модуль, для использования в своих поделках. Спаял себе еще несколько, заодно выявил, что ch440n тоже работает, но не работает свежевынутый из ленты ch430n. Обратил внимание, что один модуль при первом (абсолютно первом) включении стартовал дольше обычного, затем определялся моментально. Из всей совокупности предполагаю, что внутри какая-то программируемая логика, которая при первом включении что-то в себя прописывает, и если неудачно — то ch430n остается в коматозе навсегда. Но это только предположение.
Вот несколько фото, для понимания итоговых размеров.
В общем — теперь у меня есть свежая кучка преобразователей, которые буду использовать везде, где они нужны.
Паяются просто паяльником (у меня T12 и жало K).
Питание можно подавать до 20В, без ущерба для платы.
Type C разъем можно припаивать, а можно выносить на 4 проводках.
Кнопкой можно временно приземлять любой нужный контакт при программировании.
Если есть желающие повторить — гербер по ссылке https://drive.google.com/file/d/1y0GJEGyJkRDQfeLgmM0MGsR4YLpyOQaM/view?usp=sharing
Разброс по параметрам можно использовать достаточно приличный, я поставил 4,7кОм, вместо 5,1кОм, 100nF вместо 10nF, резисторы по 20 Ом. Токоограничивающие резисторы, возможно, придется подбирать под используемые светодиоды. В паре, как на схеме — используются одинаковые (я поставил по 1,5кОм), но если использовать два отдельных, то у меня на первой плате получилось 1кОм на красном и 4,7кОм на зеленом, для получения схожей яркости. Еще зеленый и красный светодиод — лучше поменять местами, так более логично при использовании, ИМХО.
Себестоимость комплектующих не считал, однозначно это количество получилось с диким оверпрайсом. Но не в деньгах же счастье… а в их количестве 🙂 Удачи всем.
»Заблуждения об Arduino 2: Arduino« медленный »
Что касается второго поста о заблуждениях Arduino, то распространено мнение, что Arduino «медленный». Чаще всего я слышу это в контексте реакции на ввод пользователя, работы с несколькими датчиками, использования светодиодных или ЖК-дисплеев или действия как часть контура управления. Люди советуют более быстрые микроконтроллеры, такие как серия ARM Cortex.
Давайте посмотрим на основы здесь:
- ATmega328P на платах Arduino работает на частоте 16 МГц — это 16 миллионов циклов в секунду.
- Команды ATmega328P занимают от 1 до 3 тактов (за исключением инструкций, связанных с подпрограммами, которые занимают 4 или 5 циклов). Среднее значение составляет от 1 до 2 для наиболее скомпилированного кода C.
- Тогда мы можем сделать вывод, что ATmega328P может выполнять не менее 8 миллионов инструкций в секунду!
- Трудно напрямую перевести эти инструкции в строки кода C. То, что кажется простым в C, может содержать десятки инструкций, а то, что кажется сложным, можно сделать за одну.
- Мы все еще можем сказать, что ATmega328P разорвет ваш код со скоростью узлов, намного быстрее, чем думает большинство людей.
Так почему люди говорят, что это медленно? Я бы назвал следующие причины:
- Это 16 МГц, а компьютеры и телефоны большинства людей работают в диапазоне 1 ГГц, так что это не так уж много. Однако ATmega328P выполняет совершенно другие задачи.
- Это 8 бит, а большинство современных процессоров 32 или 64 бит. Это не имеет большого значения для проектов, использующих Arduino (но будет связано с моим следующим заблуждением!)
- Частое использование delay () в коде Arduino.Delay () заставляет процессор просто работать — он не может делать ничего другого во время работы. Поэтому, если у вас есть 4 кнопки, которые предназначены для включения 4 соответствующих светодиодов на 2 секунды, система перестает отвечать, если вы используете delay () для 2 секунд.
- Частое использование Serial.print () в большинстве программ для отладки или отчетов о состоянии. Arduino pre-1.0 используется для блокировки при отправке данных через последовательный порт. Это означало, что вывод 80-символьной строки со скоростью 9600 бит / с (по какой-то причине по умолчанию) занимал бы более 80 мс, в течение которых процессор больше ничего не мог делать! Даже сейчас, когда используются прерывания, вывод строк по-прежнему занимает много времени.
- Slow digitalRead и digitalWrite — эти две функции на порядки (~ 60 циклов) медленнее, чем прямой доступ к порту (~ 1 цикл!). В результате тяжелый ввод-вывод может выглядеть медленным или скрытым.
- Плохой код — Arduino исключительно прост в использовании без понимания каких-либо основополагающих концепций микроконтроллеров. В результате код иногда бывает просто плохим.
Более быстрый микронный контроллер может замаскировать некоторые из этих проблем, но, не понимая некоторых ключевых концепций (обработка прерываний и хорошо структурированные конечные автоматы), вы снова столкнетесь с той же стеной в кратчайшие сроки.
Нельзя сказать, что более быстрые микроконтроллеры иногда не нужны — для чего-то с тяжелым вычислением чисел требуется нечто большее, — но для многих ситуаций Arduino более чем способна в руках хорошего разработчика.
Эта запись была размещена в Arduino, Без категории и помечена как arduino. Добавьте в закладки постоянную ссылку.
Управление двигателем постоянного тока
с использованием сигналов ШИМ — Arduino — Robo India || Учебники || Изучите Arduino |
В этом руководстве Robo India объясняется, как управлять скоростью двигателя постоянного тока с помощью сигналов ШИМ.
1. Введение
Скорость двигателя постоянного тока в целом прямо пропорциональна напряжению питания, поэтому, если снизить напряжение с 9 до 4,5 вольт, наша скорость станет вдвое меньше той, что была изначально. Но на практике для изменения скорости двигателя постоянного тока мы не можем постоянно изменять напряжение питания. ШИМ-регулятор скорости для двигателя постоянного тока работает путем изменения среднего напряжения, подаваемого на двигатель
.
Сигнал
PWM — это, по сути, высокочастотный прямоугольный сигнал (обычно более 1 кГц).Рабочий цикл этой прямоугольной волны варьируется, чтобы изменять мощность, подаваемую на нагрузку.
Входные сигналы, которые мы подаем на ШИМ-контроллер, могут быть аналоговыми или цифровыми в зависимости от конструкции ШИМ-контроллера. Контроллер ШИМ принимает управляющий сигнал и регулирует рабочий цикл сигнала ШИМ в соответствии с требованиями. На приведенной ниже диаграмме показаны формы сигналов, полученные на выходе при различных требованиях напряжения.
В этих волнах частота одинакова, но время включения и выключения разное.
1,2 Требуемое оборудование
1,3 вывод IC драйвера двигателя L293D вне
Драйвер двигателя — это модуль для двигателей, который позволяет управлять рабочей скоростью и направлением двух двигателей одновременно. Этот драйвер двигателя спроектирован и разработан на основе L293D IC.
L293D — это 16-контактная ИС с восемью контактами на каждой стороне для одновременного управления двумя двигателями постоянного тока. Для каждого двигателя имеется 4 контакта INPUT, 4 контакта OUTPUT и 2 контакта ENABLE.
Контакт 1: когда Enable1 / 2 находится в HIGH, левая часть IC будет работать, т.е. двигатель, подключенный к контактам 3 и 6, будет вращаться.
Контакт 2: Вход 1, когда этот контакт ВЫСОКИЙ, ток будет проходить через выход 1.
Контакт 3: Выход 1, этот контакт подключен к одной клемме двигателя.
Контакт 4/5: контакты GND
Контакт 6: Выход 2, этот контакт подключен к одной клемме двигателя.
Контакт 7: Вход 2, когда этот контакт ВЫСОКИЙ, ток будет проходить через выход 2.
Контакт 8: VSS, этот контакт используется для подачи питания на подключенные двигатели с максимальным напряжением от 5 В до 36 В в зависимости от подключенного двигателя.
Контакт 9: когда Enable 3/4 находится в HIGH, правая часть IC будет работать, то есть двигатель, подключенный к контакту 11 и контакту 14, будет вращаться.
Контакт 10: вход 4, когда этот контакт ВЫСОКИЙ, ток будет проходить через выход 4.
Контакт 11: Выход 4, этот контакт подключен к одной клемме двигателя.
Контакт 12/13: Контакты GND
Контакт 14: Выход 3, этот контакт подключен к одной клемме двигателя.
Контакт 15: Вход 3, когда этот контакт ВЫСОКИЙ, ток будет течь через выход 3.
Контакт 16: VCC, для питания IC, например, 5 В.
2. Соединения с Arduino
1. Модуль 5V (VCC) — Arduino 5V.
2. Модуль GND — Arduino GND.
3. Модуль 1 — Arduino D8.
4. Модуль 2 — Arduino D9.
5. Модуль 3 — Arduino D10.
6. Модуль 4 — Arduino D11.
7.Модуль EN12 — Arduino D5.
8. Модуль EN34 — Arduino D6.
9. Модуль двигателя Винтовые клеммы — двигатели постоянного тока.
10. Модуль VSS power Винтовой зажим — Внешний источник питания 9В.
Обязательно удалите предустановку перемычки на контактах включения модуля, чтобы мы могли подключить вход ШИМ к этому контакту и контролировать скорость двигателей. Если мы соединим эти контакты с землей, то мотор отключится.
3. Программирование:
Вот код для запуска этой схемы.
Вы можете скачать этот код (Arduino Sketch) отсюда.
// Учебное пособие от RoboIndia по управлению двигателем с использованием сигналов ШИМ // Требуемое оборудование: драйвер двигателя (от RoboIndia и Arduino) // Мотор A const int inputPin1 = 10; // Вывод 15 микросхемы L293D const int inputPin2 = 11; // Вывод 10 микросхемы L293D // Двигатель B const int inputPin3 = 9; // Вывод 7 микросхемы L293D const int inputPin4 = 8; // Вывод 2 микросхемы L293D int EN1 = 5; // Вывод 1 микросхемы L293D int EN2 = 6; // Вывод 9 микросхемы L293D установка void () { pinMode (EN1, ВЫХОД); // где двигатель подключен к pinMode (EN2, ВЫХОД); // где двигатель подключен к pinMode (inputPin1, ВЫХОД); pinMode (inputPin2, ВЫХОД); pinMode (inputPin3, ВЫХОД); pinMode (inputPin4, ВЫХОД); Серийный номер . begin (9600); Serial .println («Введите значения от 0 до 255»); } пустой цикл () { if ( Серийный номер .available ()) { int speed = Serial .parseInt (); // Получение значения от последовательного монитора Серийный .println (скорость) analogWrite (EN1, скорость); // устанавливает скорость двигателей analogWrite (EN2, скорость); // устанавливает скорость двигателей digitalWrite (inputPin1, HIGH); digitalWrite (inputPin2, LOW); digitalWrite (inputPin3, HIGH); digitalWrite (inputPin4, LOW); } }
4.Выход
После подключения вы скопируете и вставите этот код в Arduino IDE, чем загрузите код. Откройте Serial Monitor и отправьте входные значения в Arduino. Вы можете контролировать скорость двигателя постоянного тока, отправляя различные значения в диапазоне от 0 до 255.
Если у вас есть какие-либо вопросы, напишите нам по адресу [email protected]
Благодарности и приветы
Команда разработки контента
Robo India
https: // roboindia. ком
Fast PWM на Arduino Leonardo
Сегодня я расскажу о генерации ШИМ.
Платы Arduino обеспечивают псевдоаналоговые выходы с помощью функции analogWrite (). Эта функция доступна не на всех контактах, а только на тех, которые отмечены символом ~. Функция аналоговой записи обеспечивает не реальный аналоговый выход, а сигнал ШИМ.
Плата Arduino Leonardo |
Сигнал PWM (широтно-импульсная модуляция) представляет собой импульсный двоичный сигнал.Поскольку он двоичный, он может иметь только два состояния выхода: «ВЫСОКИЙ» и «НИЗКИЙ». Аналоговая информация не об уровнях сигнала, а о ширине генерируемых импульсов. Мы определяем ширину импульса как ширину ВЫСОКОГО импульса, а рабочий цикл, представленный буквой дельты в нижнем регистре, как долю ширины импульса от ширины импульса. общий период T сигнала. Частота сигнала ШИМ определяется как величина, обратная периоду.
ШИМ-сигнал |
Среднее значение сигнала ШИМ зависит от рабочего цикла и значений напряжения, связанных с ВЫСОКИМ и НИЗКИМ уровнями:
Если НИЗКИЙ уровень равен нулю, среднее значение сигнала ШИМ равно:
Таким образом, среднее значение сигнала пропорционально рабочему циклу.
Функция Arduino analogWrite () преобразует входное значение от 0 до 255 в рабочий цикл от 0% до 100%. Поскольку уровень HIGH составляет около 5 В, а уровень LOW близок к нулю, среднее значение сигнала, генерируемого с помощью analogWrite (pin, x), составляет:
Если устройство, подключенное к выводу, имеет более низкую полосу пропускания, чем частота сигнала ШИМ, оно будет работать как нижний проход для сигнала и будет видеть только среднее значение. Контакты Arduino Leonardo PWM используют частоты 488 Гц или 976 Гц. Когда вы используете аналоговую запись для светодиода, поскольку светодиоды обычно имеют полосу пропускания более 1 кГц, светодиод будет полностью включаться и выключаться, как указано в сигнале ШИМ. Наш глаз, однако, имеет полосу пропускания (частоту слияния) примерно до 100 Гц в зависимости от уровня внешней освещенности. Поскольку светодиодный индикатор пульсирует с более высокой частотой, чем ширина полосы пропускания глаза, мы видим только среднее значение и кажется, что светодиод горит на промежуточных уровнях между включением и выключением.
То же самое применимо, если мы используем сигнал ШИМ для управления двигателем. Обычные двигатели постоянного тока из-за их инерции имеют полосу пропускания, близкую или ниже частоты ШИМ Arduino, поэтому двигатель работает так, как будто применяется постоянное переменное напряжение.Фактически, ШИМ-режим на низкой частоте может улучшить работу двигателя на низких скоростях.
В общем, имеющаяся в наличии Arduino частота ШИМ от 500 Гц до 1 кГц подходит для управления двигателями. Однако, если мы хотим генерировать аудиосигнал, функция analogWrite не работает. Полоса пропускания слуха у людей составляет около 20 кГц, что намного выше, чем частота ШИМ Arduino. Типичные динамики обычно проектируются в полосе частот человеческого слуха, поэтому подача на них сигнала ШИМ будет производить слышимый тон с частотой ШИМ.
Одна из утилит для генерации высокочастотного ШИМ-сигнала выходит за пределы полосы частот динамика и слуха, поэтому мы можем использовать ШИМ-сигнал для генерации аудиосигнала.
Stock PWM на Arduino Leonardo
Сначала мы начнем объяснять, как реализована ШИМ на плате Arduino Leonardo. На большинстве плат Arduino сигналы ШИМ генерируются с помощью таймеров. Периферийные устройства таймера обеспечивают аппаратную генерацию ШИМ, так что ЦП не нужно использовать какие-либо ресурсы выполнения для генерации сигналов.Каждый таймер имеет ограниченное количество сигналов ШИМ, которое может быть сгенерировано аппаратно.
Arduino Leonardo, Micro и Esplora используют микроконтроллер ATmega42u4. Он включает в себя четыре таймера: Таймер 0, Таймер 1, Таймер 3 и Таймер 4. Таймеры 1 и 3 равны, но остальные таймеры совершенно разные. Другие платы Arduino используют другие таймеры, предоставляемые используемыми ими микроконтроллерами.
В следующей таблице показано использование таймеров для генерации ШИМ на плате Arduino Leonardo. Вы можете увидеть это и дополнительную информацию в моей электронной таблице Arduino Leonardo.
Таймеры ШИМ в Arduino Leonardo |
Arduino использует таймеры для других функций. Например, Timer 0 также используется для записи времени, необходимого для функций millis (), micros (), delay () и delayMicroseconds (). Вы не хотите связываться с таймером 0, так как это нарушит все функции синхронизации.
Некоторые библиотеки Arduino также используют таймеры. Библиотека Servo использует Таймер 1 на Леонардо, а библиотека MsTimer2 использует Таймер 4.Вы должны знать, что использование любой библиотеки, для которой нужен таймер, повлияет на любой вывод ШИМ, связанный с этим таймером.
Существует несколько двух основных способов создания сигнала ШИМ с использованием таймера.
Односторонний ШИМ
Таймеры обычно основаны на счетчике. Счетчик использует тактовый вход, и на каждом активном фронте тактового сигнала счетчик меняет состояние. Один типичный режим работы таймера включает увеличение счетчика на каждом тактовом фронте, пока он не достигнет максимального значения. По достижении этого значения счетчик возвращается к нулю, и процесс повторяется.Это дает пилообразную форму волны на значениях счетчика, как показано на рисунке ниже. Для одного полного цикла пилы потребуется Count Max + 1 такт.
ШИМ с одним наклоном |
Периферийные устройства таймера обычно включают несколько регистров захвата / сравнения. Для создания сигнала ШИМ регистр сравнения связан с аппаратным выходом MCU таким образом, чтобы этот выход был высоким, если значение счетчика ниже или равно значению регистра сравнения. Это даст для каждого регистра сравнения сигнал ШИМ, рабочий цикл которого зависит от значения сравнения.
Все ШИМ-сигналы, генерируемые одним и тем же таймером, будут иметь одинаковую частоту, так как начало генерируемых импульсов всегда будет на заднем фронте пилообразного сигнала.
Если у нас есть несколько сигналов ШИМ, сгенерированных с разным сравнением
регистров на одном таймере, все они будут иметь нарастающий фронт на
в то же время.
Аналог ArduinoWrite ()
функции работают с таймером 0 ATmega 32u4 с одинарным наклоном.250 кГц
Используемая частота получается делением на 64 системной частоты 16 МГц. Финал
Частота ШИМ будет 976 Гц.
Таймер 0 имеет два канала сравнения A и B, связанных с двумя регистрами сравнения OCR0A и OCR0B. Два канала связаны с двумя аппаратными выходами OC0A и OC0B, которые используются в качестве контактов Arduino с номерами 11 и 3.
Двухканальный ШИМ
Другой способ генерации сигнала PWM настраивает счетчик на увеличение на каждом фронте тактового сигнала, и когда он достигает максимального значения, начинает уменьшать одно число за каждый тактовый цикл, пока оно не достигнет нуля, и шаблон повторяется снова. Это даст треугольную форму волны вместо пилообразной.
ШИМ с двойным наклоном |
Мы также можем настроить регистр захвата так, чтобы генерируемый выходной сигнал был высоким, когда счетчик ниже этого регистра. Это будет генерировать сигнал ШИМ, как в случае с одним наклоном. Разница в том, что если у нас есть несколько регистров сравнения, сигнал ШИМ, генерируемый каждым из них, будет синхронизирован в центре генерируемых импульсов.
Это удобно при некоторых видах управления моторикой, но подробности выходят за рамки этой статьи.
В любом случае частота ШИМ будет одинаковой для всех каналов сравнения, а также будет равна половине значения, которое мы получили бы, если бы использовали счетчик Single Slope.
Функции Arduino analogWrite () управляют таймерами 1, 3 и 4 микроконтроллера ATmega 32u4 в режиме Dual Slope. Возможная причина, по которой Таймер 0 не работает также в режиме Dual Slope, вероятно, может быть связана с тем фактом, что Таймер 0 используется для записи хода времени, и такое использование трудно реализовать на таймере с двойным наклоном. При работе с двойным наклоном все выводы ШИМ, связанные с этими выводами, используют половину частоты таймера 0, работающего на частоте 488 Гц.
Таймер 1 включает три канала сравнения A, B и C, связанных с регистрами сравнения OCR1A, OCR1B, OCR1C, связанными с аппаратными выходами OC1A, OC1B и OC1C. Программное обеспечение Arduino использует только каналы A и B, которые связаны с выводами 9 и 10 Arduino. Выход канала C OC1C связан с тем же выводом 11 Arduino, управляемым таймером 0. По какой-то причине разработчики Arduino предпочитали управлять выводом 11 с помощью таймера 0. при одиночном наклоне, чем при использовании таймера 1 при двойном наклоне.
Таймер 3 включает только один аппаратный выход OC3A на выводе 5 Arduino, связанный с регистром сравнения OCR3A.
Таймер 4 — это специальный таймер, но в отношении ШИМ он работает как таймеры 1 и 3 в режиме двойного наклона. Он включает в себя три аппаратных выхода OC4A, OC4B и OC4D, связанных с регистрами OCR4A, OCR4B и OCR4D. В стандартной версии Arduino для контактов 13 и 6 используются только каналы A и D. Канал B связан с тем же выводом, который управляется OC1B, поэтому для этого вывода используется Таймер 1 вместо Таймера 4.
Все это дает таблицу с 7 выводами Arduino с включенной ШИМ.
Быстрая ШИМ по таймеру 1
Если максимальных 976 Гц, которые есть у Arduino analogWrite, недостаточно, нам нужно разработать собственные функции ШИМ. Таймер 1 — хороший кандидат, поскольку он имеет три доступных канала сравнения и не мешает функциям задержки Arduino. Вам следует позаботиться о том, чтобы использовать библиотеку Servo, потому что она также использует таймер 1.
Таймер 1 основан на 16-битном счетчике. Это означает, что он может считать от 0 до 65535 до переполнения.Таймер имеет несколько режимов работы, включая 12 режимов ШИМ. Самый быстрый из доступных режимов ШИМ — это 8-битный одинарный режим, считая от 0 до 255. Поскольку одинарный наклон быстрее, чем двойной, его также называют режимом Fast PWM.
Вы также можете иметь 9-битные и 10-битные режимы ШИМ с 511 и 1023 счетчиками клемм, которые могут работать в режимах с одним и двумя наклонами. Трехразрядные режимы 8, 9 и 10 для одно- и двухскатной ШИМ дают всего 6 режимов ШИМ. Остальные 6 дополнительных режимов ШИМ используют программируемые счетчики клемм, которые могут иметь любое 16-битное значение и не ограничиваются 255, 511 или 1023.
Таймер получает свои часы от глобального предварительного делителя MCU, который обеспечивает пять частот от системных часов. Коэффициенты деления равны 1, 8, 64, 256 и 1024. Это дает, используя системные часы Arduino Leonardo с частотой 16 МГц, пятичастотные и однократные частоты, показанные ниже для стандартных 8-, 9- и 19-битных режимов:
При использовании двойного наклона максимальная частота будет вдвое меньше. Мы видим, что максимально доступная частота ШИМ на Таймере 1 — 62.5 кГц. Этого достаточно, чтобы сгенерировать какой-то звуковой сигнал, так как он выходит за пределы слышимого диапазона частот.
Чтобы настроить таймер, мы должны запрограммировать регистры таймера 1 TCCR1A и TCCR1B.
Биты 0, 1 и 2 TCCR1B (CS10, CS11 и CS12) настраивают параметры синхронизации в соответствии со следующей таблицей.
Бит 1 TCCR1A (WGM11) и биты 3 и 4 TCCR1B настраивают форму сигнала для таймера в соответствии с таблицей:
Режимы 1, 2, 3, 5, 6 и 7 соответствуют 6 стандартным режимам ШИМ.
Когда таймер настроен на один режим ШИМ, каждый из трех каналов сравнения A, B и C может быть включен для генерации сигнала ШИМ. Для этого биты COM1x0 и COM1x1 в регистре TCCR1A, связанные с конкретным каналом x (A, B, C), должны быть настроены в соответствии с таблицей:
Значение PWM для каждого канала должно быть запрограммировано в каждом регистре сравнения каналов OCR1A, OCR1B и OCR1C.
Все приведенные выше таблицы взяты из таблицы данных ATmega32u4.
Настройка битов TCCR1A недостаточна для генерации сигнала ШИМ на выходных контактах.Нам также необходимо настроить их в режиме вывода. Из ATmega32u4 мы видим, что выходы таймера 1 OC1A, OC1B и OC1C связаны с линиями портов PB5, PB6 и PB7 (выводы 9, 10 и 11 Arduino). Нам нужно установить эти контакты в режим вывода, используя регистр направления данных порта B DDRB.
Быстрая ШИМ по таймеру 4
Используя таймеры 0, 1 или 3, мы можем получить ШИМ-сигналы с частотой до 62,5 кГц, но максимально возможная частота ШИМ доступна только на Таймере 4.
Таймер 4 — это 10-битный таймер, который может работать с очень высокой скоростью благодаря опциям источника синхронизации.
Микроконтроллер ATmega32u4 включает периферийное устройство USB. Этому периферийному устройству требуется тактовая частота 48 МГц, которая превышает максимальную системную тактовую частоту 16 МГц. Чтобы генерировать частоту USB, MCU включает внутреннюю ФАПЧ. В Arduino Leonardo ФАПЧ принимает в качестве входных данных системные часы 16 МГц и умножает их на 6, чтобы получить выходную частоту 96 МГц.
Вы не хотите связываться с конфигурацией PLL на Arduino Leonarda, поскольку это нарушит связь USB. Единственное, что вам нужно знать о ФАПЧ, это то, что ее выход может быть источником периферийного устройства Таймера 4.
Регистр PLL PLLFRQ включает, помимо прочего, два бита PLLTM0 и PLLTM1, которые определяют тактовую частоту входа таймера 4.
Существует четыре варианта: не используйте ФАПЧ в качестве источника таймера (он будет получен системными часами) или используйте выход ФАПЧ, разделенный на 1, 1,5 или 2. Это даст тактовые частоты 96 МГц, 64 МГц или 48 МГц.
На момент написания вышеупомянутой таблицы не было в официальном техническом описании ATmega32u4. Мне нужно было найти более старую таблицу, чтобы получить полное содержимое регистра конфигурации PLL.
Таймер 4 имеет дополнительный делитель, сконфигурированный с битами с CS40 по CS43 регистра конфигурации TCCR4B.
Доступные варианты:
Таким образом, используя делители PLL и Timer 4, вы можете получить входные частоты от 96 МГц до 5859 Гц.
Подобно таймеру 1, таймер 4 должен выбирать режим работы формы сигнала с помощью битов WGM40 и WGM41 регистра TCCR4D.
Доступные варианты:
Режим 00 является одинарным, а режим 01 — двойным.
Обратите внимание на то, что сигнал PWM имеет максимальное значение счетчика, определенное в регистре OCR4C.Поскольку регистр канала сравнения C используется для счетчика клемм, независимый выход PWM канала C отсутствует.
PWM6 — это специальный режим работы PWM, который использует все три доступных канала A, B и D для управления двигателем. Подробности, выходящие за рамки этого документа, можно найти в таблице данных MCU.
После настройки тактового сигнала каждый канал x = A, B и D таймера 4 может быть настроен со своими собственными битами COM4x0, COM4x1 и PWM4x в регистрах TCCR4A и TCCR4C.
Как мы объяснили, канал C, используемый в качестве терминального счетчика, не имеет блока вывода, поэтому его нельзя использовать для генерации ШИМ.
Для работы с одним каналом x в режиме PWM вам необходимо установить в «1» соответствующий бит PWM4x. После этого COM4x0 и COM4x1 определяют режим работы ШИМ. В случае канала А в режиме быстрой ШИМ мы можем выбрать:
Нормальная работа ШИМ соответствует режиму 10. Режим 11 дает дополнительный выход, тогда как режим 01 дает два дополнительных выхода ШИМ на разных выводах. Между дополнительными сигналами может быть некоторая зона нечувствительности, так что один сигнал и его дополнение никогда не будут активны одновременно.
Подобные таблицы можно найти для каналов B и D.
Код теста быстрой ШИМ
Я собрал все вышеперечисленные методы для генерации ШИМ в скетче FastPWM Arduino.
Скетч включает необходимый код для управления 5 контактами, связанными с таймерами 1 и 4 в быстрых режимах ШИМ.
Код таймера 1
Код, связанный с таймером 1, включает 4 функции и несколько определений. Он может использовать все три канала сравнения Таймера 1 для генерации сигналов ШИМ на выводах 9, 10 и 11 Arduino.
Функция pwm
configure должна вызываться перед вызовом любой другой функции, связанной с этим таймером. Он настраивает таймер для работы в режиме однократной быстрой ШИМ и устанавливает предварительный делитель в режим, указанный в аргументе функции.
Пять возможных режимов — это PWM62k, PWM8k, PWM1k, PWM244 и PWM61, и они связаны с четырьмя доступными частотами в режимах 8-битной ШИМ с одним наклоном.Функции pwmSet9, pwmSet10 и pwmSet11 настраивают каналы Таймера 1, связанные с контактами 9, 10 и 11, для работы в режиме ШИМ и устанавливают заданное значение ШИМ (от 0 до 255).
После вызова одной из трех вышеуказанных функций значение ШИМ можно быстро изменить, используя прямой доступ к соответствующему регистру сравнения. Для облегчения доступа три определения PWM9, PWM10 и PWM11 связаны для сравнения регистров OCR1A, OCR1B и OCR1C.
Таймер 4 Код
Код, связанный с таймером 4, включает 3 функции, а также несколько определений. Он использует два из трех доступных каналов сравнения A и D, связанных с контактами 13 и 6 Arduino.Он не использует канал B, потому что его вывод 10 Arduino конфликтует с ранее использовавшимся каналом B.
Функция pwm613configure аналогична той, которая определена для таймера 1. Она устанавливает режимы PLL и PWM для правильной настройки таймера 4 в высокоскоростном режиме от отвода PLL 48 МГц и устанавливает счетчик клемм в OCR4C на 8 бит (255).
Входной аргумент устанавливает одну из семи доступных частот предварительного делителя для тактового входа таймера 4 48 МГц: PWM187k (187500 Гц), PWM94k (93750 Гц), PWM47k (46875 Гц), PWM23k (23437 Гц), PWM12k (11719 Гц), PWM6k ( 5859 Гц) и PWM3k (2930 Гц).Если вы помните опции Timer4, там 15 опций предварительного делителя частоты. Более низкочастотные не реализованы в определениях, поскольку они не дают преимущества перед стандартными функциями analogWrite.
Функции pwmSet13 и pwmSet6 настраивают каналы таймера 4, связанные с контактами 13, 6, для работы в режиме ШИМ и устанавливают заданное значение ШИМ (от 0 до 255).
Аналогично таймеру 1, после вызова одной из двух вышеуказанных функций значение ШИМ может быть изменено.
быстро меняется с помощью прямого доступа к соответствующему сравнению
регистр.Два определения PWM13 и PWM6 связаны для сравнения регистров OCR4A и OCR4D. Дополнительное определение PWM6_13_MAX было добавлено для доступа к регистру OCR4C, который устанавливает счетчик клемм PWM, который по умолчанию установлен на 255 (8 бит).Настройка и код цикла
Для проверки всех вышеперечисленных функций Таймер 1 настроен в настройке для генерации сигналов ШИМ 62,5 кГц. Таймер 4 настроен на 187 кГц. Генерируются 4 сигнала. На выводах 11 и 13 установлены фиксированные значения ШИМ 11% и 75%.Для контактов 6 и 9 внутри функции цикла программируется переменное значение ШИМ от 0% до 100%.
Формы генерируемых сигналов
На следующем рисунке показаны сгенерированные формы сигналов, захваченные с помощью Logic Analizer области Analog Discovery.
Сигналы таймера 1 на выводах 9 и 11 имеют такой же фронт нарастания, что и в режиме ШИМ с одним линейным изменением. То же самое относится к сигналам на контактах 6 и 13, которые зависят от таймера 4. Сигналы в разных таймерах имеют разную частоту, поэтому нарастающие фронты обычно не совпадают для обоих сигналов таймера.
На этом пока все. Таймеры — очень полезное периферийное оборудование. ШИМ — только одно из приложений таймера. В будущем я планирую поговорить также о генерации периодических событий.
Код на Github (02.11.2018)
Код сейчас на Github:
https://github.com/R6500/Leonardo/blob/master/FastPWM.ino
Tweaking4All.com — Программирование Arduino для начинающих
Обзор этой главы
Полный обзор этого курса можно найти здесь: Обзор курса .
Назначение петель
Прежде чем мы начнем работать с циклами, мы, вероятно, должны понять, когда и где мы будем использовать циклы.
Наиболее распространенное применение — это когда нам приходится многократно повторять определенный набор инструкций либо на основе условий, либо на основе подсчета.
Допустим, у нас есть 5 лампочек, каждая со своим выключателем. Чтобы включить весь свет, нам необходимо:
Включить свет 1,
Включить свет 2,
Включить свет 3,
Включить свет 4,
Включить свет 5.Итак, мы повторяем ту же инструкцию (включить свет) для каждого из 5 огней.
Мы могли бы также записать это как:Сосчитайте от 1 до 5 и для каждого числа включите свет.
Тада! Мы только что создали цикл, который избавляет нас от повторения (почти) одного и того же предложения снова и снова.
Можете ли вы представить, сколько мы сэкономили бы, если бы нам пришлось считать до 1000?
Это не только для нашего набора текста, это экономит место — ваш исходный код будет короче и легче читается, но также и скомпилированная программа для Arduino будет намного меньше, а может быть, даже быстрее.Бонус в том, что когда нам нужно изменить наш код на большее или меньшее количество огней, мы просто меняем одно число.Циклы используются для повторения определенных инструкций
Довольно часто для подсчета используются переменных , поэтому наш предыдущий оператор мог бы быть:
Счетчик для A = от 1 до 5
Выключатель света A наНаписание такого программного кода также называется «Псевдокодом». Псевдокод
— это, по сути, написание программы (например, на бумаге), более похожий на человеческий язык, но с использованием «конструкций», которые похожи на те, которые мы используем в выбранном нами языке программирования.Мы не можем использовать этот псевдокод в нашей программе, но он помогает записывать шаги, которые мы хотим предпринять в нашей программе, или объяснять код более понятным для человека способом.
Если хотите, можете сразу забыть о жаргоне.Цикл for
Оператор «for» — один из тех операторов, которые мы можем использовать для создания цикла. Мы «считаем», и счет ведется целыми числами!
Сам того не зная, ты уже добрый-а столкнулся с этим только что.Счетчик для A = от 1 до 5
Выключатель света A наЕсли мы запишем это более сложным образом:
для A = 1 и A должно быть меньше или равно 5, увеличивайте A на единицу каждый раз, когда
включает свет A наВот как цикл for работает на языке C, который мы используем для программирования Arduino, и в коде это может выглядеть так:
для (A = 1; A <= 5; A ++) {
Serial. print («Включай свет, чтобы свет»);
Serial.println (A);
}Давайте рассмотрим это подробнее.
Очевидно, мы используем выражение «for». Параметры, которые нам нужны для выражения «for»:
- Начать с «A = 1»
- Имейте в виду, что «A <= 5»
- Каждый раз, когда мы проходим цикл, увеличиваем A на единицу (A ++)
Подсчет в цикле for может быть выполнен только с целыми числами (byte, int.длинные и т. д.),
или другими словами: тип данных, который можно перечислить (считать целыми числами и с фиксированными приращениями).
Поскольку мы только что вызвали эти параметры, нам нужно заключить их в круглые скобки, как мы видели с другими функциями, которые получают параметры (например,
Serial.print ()
).Следующее, что вы увидите, — это то, что мы создаем закрытый блок кода — так же, как мы видели это с оператором «if».
Все, что находится в этом кодовом блоке, будет повторяться до тех пор, пока выполняются условия для цикла «for».
Вы должны иметь в виду, что «A ++» — один из тех сложных операторов, которые сбивают с толку, как мы видели в части 3.
«A ++» означает: « увеличивает значение A на 1 и возвращает старое значение A. “.
Это фактически означает, что мы работаем со «старым» значением «A» в кодовом блоке, но как только кодовый блок будет завершен, A примет новое (увеличенное) значение.
Теперь вы знаете, почему я не поклонник использования этих составных операторов — особенно вначале они могут сбивать с толку.Придерживайтесь правила, что составные операторы
« ++ » (счет ВВЕРХ) или
«–– » (счет ВНИЗ)
всегда помещаются после переменной в «for». петля .Мы только что сказали «обратный отсчет»? Да, мы сделали!
В цикле for также можно вести обратный отсчет с помощью составного оператора «––». Если мы возьмем наш предыдущий пример, но вместо того, чтобы считать от 1 до 5, теперь мы хотим отсчитать от 5 до 1, то наш код будет выглядеть так:для (A = 5; A> = 1; A--) {
Serial.print («Включай свет, чтобы свет»);
Serial.println (A);
}Обратите внимание, что теперь мы начинаем с «A = 5» и хотим, чтобы A было больше или равно 1. В конце концов, в этом примере мы ведем обратный отсчет.
Теперь одна вещь, которую мы до сих пор упускали из виду … определение нашей переменной A.
Один из способов определить «A» — это обычное определение переменной (перед циклом):
int A;
int A;для (A = 1; A <= 5; A ++) {
Serial.print («Включить свет для света»);
Серийный.println (А);
}Другой способ — определить «A» в операторе «for», что идеально, если мы используем только «A» в цикле и не будем нуждаться в нем где-либо еще — помните эту тему о «области действия»? Это делается в коде:
для (int A = 1; A <= 5; A ++) {
Serial. print («Включить свет для света»);
Serial.println (A);
}Обратите внимание, что мы ввели «int A» внутри параметров for?
Это относительно распространенный метод, но вы должны иметь в виду, что если мы определим нашу переменную в выражении «for», то она будет известна только в блоке кода оператора «for».Об этом принципе «объема» мы говорили ранее.Если мы попробуем следующий код, ваш компилятор Arduino выдаст вам сообщение об ошибке «Ошибка :« A »не был объявлен в этой области ».
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
пустая настройка () {
// устанавливаем скорость для последовательного монитора:
Serial.begin (9600);
для (int A = 1; A <= 5; A ++) {
Серийный.print («Включай свет, чтобы свет»);
Serial.println (A);
}Serial. println (A); // это строка, которая выдает ошибку!
}void loop () {
// пока оставим пустым
}Помните «Область действия» переменной, как обсуждалось в Части 3?
«Область действия» «A» будет блоком кода цикла «for». Итак, «A» — это неизвестная переменная в строке 10, что означает, что она не определена (объявлена).Переменная для нашего цикла «for» может быть определена в операторе «for»,
, однако его область действия будет ограничена блоком кода цикла for!
Если переменная цикла for не была определена, Arduino все равно определит ее как
, как если бы она была определена в цикле for.Однако хорошей практикой является правильное определение переменной либо перед циклом, либо в операторе «for».Так что обратите внимание, если переменная была определена заранее и / или если переменная нужна вне цикла!
Давайте представим все это на рабочем примере, который мы можем запустить на нашей Arduino.
В этом примере я включил и обратный, и обратный счет:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void setup () {
// устанавливаем скорость для последовательного монитора:
Серийный.begin (9600);
Serial.println ("Подсчет:");
для (int A = 1; A <= 5; A ++) {
Serial.print («Включи свет на свет»);
Serial.println (A);
}Serial.println ("Обратный отсчет:");
for (int A = 5; A> = 1; A--) {
Serial.print («Включить свет для света»);
Serial.println (A);
}
}void loop () {
// пока оставим пустым
}Результат будет выглядеть примерно так:
Подсчет:
Включить свет для света 1
Включить свет для света 2
Включить свет для света 3
Включить свет для света 4
Включить свет для света 5
Обратный отсчет:
Включить свет для света 5
Включение света для освещения 4
Включение света для освещения 3
Включение света для освещения 2
Включение света для освещения 1В блоке кода мы можем прочитать и использовать переменную, которую мы использовали для цикла «for» (A). Мы можем, в отличие от некоторых других языков программирования, даже изменить значение A в этом цикле — хотя я бы не рекомендовал этого, если у вас нет опыта работы с циклом for и не знаете, что вы делаете.
Допустим, мы бы присвоили новое значение A в цикле для регулярного подсчета, изменив цикл на:
1
2
3
4
5
для (int A = 1; A <= 5; A ++) {
Serial.print («Включай свет, чтобы свет»);
Serial.println (A);
А = 7;
}Тогда наш результат будет:
Подсчет:
Включить свет для света 1
Обратный отсчет:
Включить свет для света 5
Включить свет для света 4
Включить свет для света 3
Включить свет для света 2
Включить свет для света 1Проходя код, мы запускаем цикл, в котором A начинаем с 1.Мы выполняем блок кода, но в этом блоке кода мы устанавливаем A равным 7, что больше 5. Итак, когда мы проходим следующий шаг (итерацию) цикла. Цикл «for» теперь увидит, что A = 7 и, следовательно, больше не <= 5, посчитает цикл «выполненным» и завершит работу.
Вот почему мы видим только одну строку для обычного счетного цикла.Каждый раз, когда мы проходим цикл, это называется « итерация »,
, поэтому в нашем примере есть 2 цикла «for», каждый с 5 « итерациями ».Теперь вы можете представить, что произойдет, если вы сделаете ошибку и вместо «A = 7» наберете «A = 1»?
Цикл будет продолжаться вечно — эффект, который мы, возможно, не захотим видеть в нашей программе, поскольку он никогда не выйдет из цикла, и весь следующий код будет проигнорирован.Изменение переменной цикла в цикле — плохая идея!
Если вы хотите остановить цикл for в середине выполнения, вы можете использовать оператор break.
«break» используется для выхода из цикла, как мы уже видели с «переключателем». Это будет работать для циклов «for», «while» и «do… while…».Вы можете выйти из цикла с помощью оператора « break ».
Например:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
пустая установка () {
// устанавливаем скорость для последовательного монитора:
Серийный.begin (9600);
для (int A = 1; A <= 5; A ++) {
Serial.print («Включи свет на свет»);
Serial.println (A);
если (A == 3) {
перемена;
}
}
}void loop () {
// пока оставим пустым
}Теперь мы увидели простой пример: счет от 1 до 5 и от 5 до 1. Однако нам не нужно начинать с 1. На самом деле довольно часто начинать с нуля (0), но вы можете начать с любого числа, которое захотите.
«Условия» в цикле «for» также не обязательно должны быть фиксированными числами. Помните, что переменные можно использовать для замены значения в вашем коде. Таким образом, будет работать и следующее:
int Start = 1;
int Stop = 5;для (int A = Start; A <= Stop; A ++) {
Serial.print («Включить свет для света»);
Serial.println (A);
}Сейчас хорошее время, чтобы немного поэкспериментировать с вашим кодом. Измените некоторые значения, сделайте несколько ошибок и познакомьтесь с циклами «for».
циклы «пока»
Теперь мы увидели цикл «for» с предопределенными «диапазонами», в которых мы «считаем». Но мы также можем создавать циклы, в которых подсчет вообще не используется. Подумайте примерно так:
Пока на улице темно, светится ВКЛ.
Здесь нет подсчета, поэтому мы не можем решить эту проблему с помощью цикла «for» (естественно, в любом случае есть уловки, чтобы выполнить это с помощью цикла «for», но если вы хотите хорошо программировать , тогда это не должно быть способом сделать это). Здесь вступает в игру цикл «while», я уверен, вы уже догадались об этом, основываясь на том, как я записал пример.
В то время как DarkOutSide
LightsOnИтак, этот цикл сначала проверит, темно ли на улице. Если это так (условие дает true ), мы выполняем блок кода (LightsOn). После выполнения мы повторяем эти шаги снова, снова и снова, пока условие не приведет к ошибке false , что приведет к выходу из цикла.
Цикл while сначала проверяет, истинно ли условие
, и если да, выполняет блок кода и повторяет цикл
до тех пор, пока условие не станет ложным и цикл не будет завершен.Вы могли видеть это как бесконечную повторяющуюся проверку «если». Он продолжает повторяться, пока условие истинно, в отличие от оператора «if», который проходит через код только один раз, если условие выполняется.
При программировании Arduino на языке C это будет выглядеть примерно так:
while (DarkOutside == true) {
Serial. println ("Свет включен");
}Пока « DarkOutside » == true , ваш Arduino будет продолжать печатать «Lights ON».
Мы также можем переписать это, как показано ниже. В конце концов, переменная DarkOutside знает только 2 значения: истина или ложь, что делает ее логической.
в то время как (DarkOutside) {
Serial.println («Свет включен»);
}Этот трюк, конечно, не сработает, если вы работаете с числами или текстом, поскольку они могут иметь больше возможных значений.
Однако есть одна маленькая вещь, на которую мы должны обратить внимание…
Когда (в этом коде) изменится значение DarkOutside?
В конце концов, если «DarkOutside» никогда не изменится, цикл «while» будет продолжаться вечно…Есть 2 возможных способа изменить значение «DarkOutside»…
Первый способ — мы меняем значение в кодовом блоке.Например расчет. Таким образом, мы можем имитировать цикл «for». Вот пример:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
пустая установка () {
// устанавливаем скорость для последовательного монитора:
Serial.begin (9600);
// определяем нашу переменную
int A = 1;, а (A <= 5) {
Последовательный.print («Включай свет, чтобы свет»);
Serial.println (A);
А = А + 1;
}
}void loop () {
// пока оставим пустым
}Это будет делать то же самое (и вы можете видеть, что цикл «for» кажется более эффективным):
1
2
3
4
5
6
7
8
9
10
11
12
13
пустая установка () {
// устанавливаем скорость для последовательного монитора:
Серийный. begin (9600);
для (int A = 1; A <= 5; A ++) {
Serial.print («Включи свет на свет»);
Serial.println (A);
}
}void loop () {
// пока оставим пустым
}Другой способ изменения значения — влияние извне, например, считывание показаний датчика или переключателя.
Итак, мы еще ничего не сделали с ними, и, поскольку чтение переключателя требует немного больше работы, мы сохраним это на потом.
Имейте в виду, что когда условие цикла while НЕ выполняется,
цикл будет завершен! Не забывай!«do… while…» циклы
Цикл «do… while…» — это еще один цикл, который мы можем использовать, он в основном такой же, как цикл «while», мы просто меняем порядок, в котором выполняются действия. Сначала мы что-то делаем, а затем проверяем условие. Если условие соблюдено, мы его еще раз переберем. Если условие не выполняется, цикл закончен.
Цикл «do… while…» сначала выполнит инструкции в блоке кода
и после , который проверяет , если условие истинно.
Если истина, цикл будет повторен.
Если false, то выходим из цикла.Обозначение немного отличается от цикла «while»:
делать {
// что-то делать
} while (условие);Мы видим, что начинаем с оператора do, за которым следует блок кода, и заканчиваем оператором while.
Применение этого типа цикла, например, если нам нужно что-то вычислить, и повторять вычисление до тех пор, пока условие «while» не перестанет выполняться.
Вот пример цикла «while» и «do… while…», выполняющих одно и то же:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void setup () {
// устанавливаем скорость для последовательного монитора:
Серийный.begin (9600);
int A = 1;while (A <= 5) {
Serial. println ("WHILE: A все еще <= 5");
А = А + 1;
}A = 1;
do {
Serial.println ("DO WHILE: A по-прежнему <= 5");
А = А + 1;
} while (A <= 5);
}void loop () {
// пока оставим пустым
}Результат будет выглядеть так:
WHILE: A по-прежнему <= 5
WHILE: A по-прежнему <= 5
WHILE: A по-прежнему <= 5
WHILE: A по-прежнему <= 5
WHILE: A по-прежнему <= 5
DO WHILE: A по-прежнему <= 5
DO WHILE: A по-прежнему <= 5
DO WHILE: A по-прежнему <= 5
DO WHILE: A по-прежнему <= 5
DO WHILE: A по-прежнему <= 5Что-то может пойти не так с циклом «do… while…», главным образом потому, что мы проверяем условие после того, как мы выполнили наш блок кода.Представляете, что произошло бы, если бы мы изменили строки 5 и 12 на:
A = 10;
?Цикл while не будет выполняться. И это хорошо.
Цикл «do… while…», однако, БУДЕТ выполнять первую итерацию и выводит (ошибочно): «DO WHILE: A все еще <= 5».Используя любой из этих циклов, будьте осторожны, чтобы он делал то, что вы от него ожидаете!
- Проверить сначала и сделать позже ? (цикл while)
- Первые и проверят позже ? (цикл выполнения)
Это означает, что мы должны следить за тем, когда использовать «while» или «do… while…», я подозреваю, что цикл «while» является наиболее распространенным.
Если у вас есть вопросы, просто задавайте их ниже в разделе комментариев и имейте в виду: глупых вопросов не бывает! В какой-то момент нам всем пришлось начать!
Следующая глава: Программирование Arduino для начинающих - Часть 6: Функции
Управление скоростью двигателя постоянного тока с использованием Arduino и PWM с программой и схемой
Управление скоростью двигателя постоянного тока с использованием Arduino и PWM
Управление скоростью двигателя постоянного тока с помощью интерфейса ПК - это простой проект, сделанный своими руками. В этом проекте скорость двигателя постоянного тока контролируется путем отправки команды через ПК. Arduino напрямую подключается к ПК через USB-кабель, и команда подается на Arduino на последовательном мониторе Arduino IDE.
Двигатель подключен к транзистору, а база транзистора подключена к выводу PWM Arduino, и скорость двигателей изменяется в соответствии с сигналом PWM, поступающим от Arduino.
Управление двигателем постоянного тока Arduino - Работает
Arduino подключается к ПК через USB-кабель.Мы можем отправить команду на ПК на последовательном мониторе. Мы можем изменить скорость двигателя от 0 до 9. Когда 0 посылается через Serial Monitor, двигатель работает с минимальной скоростью (то есть нулевой). Когда скорость изменяется от 1 до 9, скорость увеличивается, при этом значение 9 устанавливается как максимальная скорость двигателя.
Для управления скоростью используется технология контроллера двигателя постоянного тока с ШИМ. В ШИМ Arduino посылает пульсирующую волну, которая похожа на нестабильный режим микросхемы таймера 555.
ШИМ-контроль скорости (широтно-импульсная модуляция)
Микроконтроллер и Arduino - цифровые устройства; они не могут дать аналоговый выход.Микроконтроллер выдает на выходе НУЛЬ и ЕДИНИЦУ, где НУЛЬ - логический НИЗКИЙ, а ЕДИНИЦА - логический ВЫСОКИЙ. В нашем случае мы используем 5-вольтовую версию Arduino. Таким образом, логический НУЛЬ - это нулевое напряжение, а логический ВЫСОКИЙ - 5 напряжений.
Цифровой выход хорош для цифровых устройств, но иногда нам нужен аналоговый выход. В таком случае очень полезен ШИМ. В ШИМ выходной сигнал переключается между нулем и единицей, на высокой и фиксированной частоте, как показано на рисунке ниже.
Выходной сигнал ШИМ
Как показано на рисунке выше, время включения - «Ton», а время выключения - «Toff».T - это сумма «Ton» и «Toff», которая называется периодом времени. В концепции ШИМ «T» не меняется, и «Ton» и «Toff» могут меняться, таким образом, когда «Ton» увеличивается, «Toff» будет уменьшаться, а «Toff» увеличиваться, когда «Ton» уменьшается пропорционально.
Рабочий цикл - это часть одного периода времени. Рабочий цикл обычно выражается в процентах или соотношении. Период - это время, необходимое сигналу для завершения цикла включения и выключения. В качестве формулы рабочий цикл может быть выражен как:
РАБОЧИЙ ЦИКЛ = (Тонна ÷ Т) x100%Теперь скорость двигателя меняется в зависимости от рабочего цикла.Предположим, что коэффициент заполнения равен нулю, двигатель не работает, а при коэффициенте заполнения 100% двигатель работает на максимальных оборотах. Но эта концепция не всегда верна, потому что двигатель запускается после подачи некоторого фиксированного напряжения, называемого пороговым напряжением.
Транзистор (2N2222)
Микроконтроллер
и Arduino могут обрабатывать сигналы и потреблять ток от 20 до 40 мА, но двигателям нужен высокий ток и напряжение, поэтому мы используем транзистор для управления двигателем. Транзистор подключен последовательно с двигателем, а база транзистора подключена к выводу PWM Arduino через сопротивление. Сигнал PWM поступает от Arduino, и транзистор работает как переключатель и замыкает эмиттер (E) и коллектор (C), когда сигнал PWM находится в состоянии High, и обычно открывается, когда сигнал PWM находится в состоянии LOW. Этот процесс работает непрерывно, и двигатели работают с желаемой скоростью.
Компоненты
Компоненты Спецификация Количество Ардуино Нано 1 Двигатель постоянного тока Низкое энергопотребление 1 Транзистор 2N222 1 Адаптер питания 12 В 1 Сопротивление 1K 1 Диод 1N4004 1 Кабель USB Для Arduino Nano 1 Управление двигателем постоянного тока Arduino - Схема
Принципиальная схема показана на рисунке ниже. Если вы делаете эту схему на печатной плате общего назначения (ZERO PCB) или макетной плате, этот рисунок будет полезен.
Контроль скорости двигателя постоянного тока Arduino
Более того, если вы хорошо разбираетесь в травлении печатных плат, используйте изображения, представленные ниже.
Arduino-PWM Управление двигателем постоянного тока - Дизайн печатной платы
Контроль скорости двигателя постоянного тока
В схеме используется Arduino Nano , очень маленький по размеру и дружественный к макетной плате.
Вывод BASE транзистора (2n2222) подключен к выводу D9 Arduino через сопротивление 1 кОм, сопротивление используется для ограничения тока. Двигатель подключен между коллекторным выводом транзистора и Vcc. Диод (1n4004) подключен параллельно двигателю с обратным смещением; он используется для блокировки обратного тока. Эмиттерный вывод транзистора подключен к земле. Эта схема питается от адаптера на 12 В.
Управление двигателем с ШИМ Arduino - видео
Управление двигателем постоянного тока Arduino
Управление двигателем Arduino PWM
Управление скоростью двигателя постоянного тока - Загрузить программу
Скачать программу / код
В начале кода объявлены два целых числа с именами «out1» и «val», где out1 равно 9, что показывает, что вывод D9 Arduino используется как вывод вывода (или вывод ШИМ).Более того, данные, поступающие от последовательного монитора, сохраняются во втором целом числе «val».
В void setup () последовательная связь начинается с использования функции «Serial.begin (9600)», где 9600 - скорость передачи последовательного монитора. После этого «out1» объявляется как выход, потому что двигатель является выходным устройством.
В цикле void «serial.available» используется внутри условия «если», оно становится истинным, когда какие-либо данные отправляются через монитор последовательного порта. Эти данные сохраняются в виде целого числа val с использованием Serial.читать ».
После этого используется много условий «если», в первом «условии если», когда через монитор последовательного порта отправляется «0», оно становится истинным. В скобках «analogWrite (out1, 0)» используется для запуска двигателя при нулевом значении ШИМ. В функции analogWrite (out1, 0) «out1» используется для обозначения вывода, который мы хотим использовать, а «0» - это значение ШИМ на этом выводе. После этого на последовательном мониторе отображается «Speed is = 0» с помощью функции «Serial.println». После этого целое число «val» обновляется до 10, где 10 - случайное значение, отличное от 0 до 9.
В следующей строке, если условие используется для «val == 1», в это время двигатель работает со значением PWM, равным 175. Те же условия используются до 9, в 9 двигателях используется значение 255 PWM, 255 - это максимальное значение PWM. ценить.
Процесс
- Подключите Arduino через USB и загрузите код
- Откройте монитор последовательного порта и установите скорость передачи 9600
- Теперь введите любое число от 0 до 9.
После ввода любого значения от нуля до 9 скорость двигателя меняется, но мы не можем правильно увидеть изменение скорости на видео, но вы можете увидеть это вживую.
Arduino IDE: оператор увеличения и уменьшения
Оператор увеличения
Оператор инкремента - это арифметический оператор Arduino, который увеличивает целочисленную переменную на единицу. Это полезно в определенных типах петель.
Две возможные структуры оператора приращения:
- Имя_переменной ++: Поскольку знак ‘ ++’ стоит после имени переменной, это операция приращения после . Это означает, что переменная - первая , используемая в операторе, и увеличивается на после выполнения оператора.
- ++ Имя переменной: Поскольку знак ‘++’ стоит перед именем переменной, это операция приращения от до . Это означает, что переменная увеличивается на перед выполнением инструкции на .
Пример, показывающий работу операции приращения post :
Пример, показывающий работу операции приращения до :
Оператор уменьшения
Оператор декремента используется для уменьшения целочисленной переменной на единицу.
Две возможные структуры оператора приращения:
- Имя_переменной - -: Поскольку знак ‘ –‘ стоит после имени переменной, это операция уменьшения после . Это означает, что переменная - первая , используемая в операторе, и уменьшенная на после выполнения оператора.