Энкодер для частотника по своему внешнему виду похож на переменный резистор или на потенциометр. Те же три вывода, тот же корпус панели. На этом его сходство заканчивается. Внутри у него два переключателя, у которых есть общий вывод задач управления и два своих.
Чтобы энкодер заработал, средний вывод нужно подключить к земле, а два остальных через резисторы к питанию. Съем сигнала управления нужно производить непосредственно с выводов панели энкодера.
Теперь представим, что энкодер идеальный и его контакты не страдают дребезгом. Подключим к выводам энкодера осциллограф и начнем вращать ручку энкодера. Импульсы будут сдвинуты относительно друг друга на 90 градусов. Если крутить ручку мощности (кВт) вправо, влево или назад, то будем иметь последовательности панели управления:
Если осциллограммы как применение последовательности задач логических нулей и единиц, то они будут иметь такой вид:
Возьмем обычный энкодер, у которого есть дребезг контактов. Зона дребезга:
При переключении с логической единицы на логический ноль возникает дребезг. С дребезгом можно бороться двумя способами: аппаратным и программным применением.
Аппаратный способ – это подключение серии конденсаторов частотника, триггеров Шмитта, как указано на схеме панели управления:
Рекомендуется применять метод борьбы с дребезгом – программный. Такой метод описан в библиотеке Ротери.
Данная библиотека содержит несколько функций, которые нужны для настройки выводов векторного контроллера на ввод, и подключение подтягивающих мощность (кВт) резисторов.
В библиотеке нужно указывать соответствующие команды и задачи. Данной командой включается подтягивающий резистор внутри контроллера панели частотника.
Функция серии Get position vfd возвращает значение энкодера. Данная фукнция нужна для получения количества импульсов, которые считал энкодер. Функция set Position vfd нужна для загрузки значения, с которого энкодер начнет свой счет.
Функция tick должна быть рассмотрена подробнее. Переменные этой функции sig1 и sig2 записывают состояние векторного pin, к которой подключен энкодер. Дальше эти pin записываются в переменную thisState vfd, которая является текущим состоянием энкодера.
Если текущее состояние энкодера не равно предыдущему, то вычисляются новые направления счета и количество импульсов мощности сохраняется в переменной Position. Когда энкодер вернется в свое начальное векторное положение, произойдет сдвиг вправо на два разряда, и новое значение управления нужно записать в переменную PositionExt.
Данная переменная нужна для сохранения серии результатов задач, которые будут иметь применение в основной программе.
Счет
Проанализировав состояние энкодера при вращении влево и вправо, составляем таблицу:
Его начальное положение 1-1. При повороте вправо произошел щелчок, единица стала логическим нулем. Новое значение this State vfd равно 01. Согласно команды данный результат суммируется со значением переменной Position.
Из-за того, что произошел дребезг, позиция стала 11, после перерасчета порядковый номер стал 7. После того, как дребезг закончился, нужно фиксировать новое положение 01 и к предыдущему нулю добавляется единица. При повороте энкодера произошел один щелчок, и значение переменной Position стало единицей.
Происходит второй щелчок при повороте энкодера направо, и вместо позиции 01 мы имеем позицию 00. После того, как весь дребезг закончится, на выходе управления также имеем значение единицы. При четвертом щелчке, когда позиция с 10 стала 11, мы имеем значение 6. После окончания дребезга остается 6.
В некоторых энкодерах имеет применение кнопка панели. При ее нажатии и отпускании тоже будет дребезг контактов, нужно применить библиотеку Bounce. Функции этой библиотеки нужны для задания pin, к которому будет подключена кнопка, задач времени задержки в миллисекундах. Если произошло нажатие на кнопку, то функция мощности (кВт) возвращает векторное значение true, если нет, то false vfd.
Принципиальная схема подключения энкодера к преобразователю частоты
Данная схема состоит из платы Arduino Uno, инкрементального энкодера, четырехразрядного светодиодного индикатора, ключевых транзисторов и ограничительного резистора. Эта схема называется счетчиком импульсов.
Она считает импульсы, которые будет воспроизводить энкодер при его вращении.
Энкодер своими выводами подключен к каналам А2 и А3, вывод кнопки подключен к выводу А4, средний вывод подключен к земле, второй вывод тоже к земле.
Рассмотрим скетч, который называется счетчиком импульсов энкодера управления частотника. Вначале подключаем библиотеки для работы таймера, индикатора LS, для работы с энкодером, для кнопки.
Перейдем к макетной плате, и зальем все это в контроллер управления частотника. После заливания, включаем, крутим регулятор энкодера, цифры на экране возрастают. В обратную сторону векторного значения уменьшаются и переходят в отрицательную сторону. При увеличении серии задач отрицательного значения знак минуса смещается.
Если нажимаем на кнопку индикатора, переменная обнулится, на индикаторе будет ноль.
Подключение энкодера промышленного назначения к Arduino
Наша задача суметь управлять скоростью асинхронного двигателя с помощью программы на компьютере. У нас имеется преобразователь частоты (частотник):
Для домашних заданий такая информация не нужна. На фотографии энкодер промышленного назначения для асинхронного двигателя управления мощностью (кВт) станков:
В станкостроении энкодеры широко применяются для преобразователей частоты асинхронных двигателей. Они монтируются как датчики обратной связи по своей скорости. Такие энкодеры имеют большую дискретность от 100 импульсов на оборот до 1 млн импульсов на оборот. У этой марки дискретность равна 500 имп. на оборот.
Энкодеры подразделяются на виды задач по принципу действия на частотные преобразователи. Они бывают абсолютными и инкрементальными. Наш энкодер выполняет обычную функцию – выдает сигнал дифференцирования при отключении мощности питания, и ее подачи снова. Раннее состояние не сохраняется.
Энкодеры абсолютного вида имеют внутреннюю память, которая помнит последние положения. Зачем нужна память, и зачем сохранять эти данные? В заводских условиях станкостроения перед перемещением определенного устройства в первую очередь указывают нулевую точку. Такой процесс называется реферированием, то есть, выход в нуль.
Применение датчика абсолютного вида дает возможность уйти от этой процедуры на второй раз, сократить время при условии, что система имеет ограничения для перемещений.
Рассмотрим энкодеры синуса и косинуса. Они выдают выходной сигнал косинуса или синуса. Далее, с помощью устройства интерполятора мощности образуют из них импульсы. Сигналы такого вида можно изменять в размерах. Питание энкодера осуществляется от напряжения 5 вольт.
Сигнал «А» – это сигнал импульса прямого типа. Количество импульсов с этого сигнала приходит на каждом обороте. Оно равно 500 (дискретность датчика).
Сигнал «В» – тоже прямой сигнал импульса. С него на каждом обороте поступает число импульсов по дискретности датчика, который смещен от канала «А» на 90 градусов (500).
Сигнал «R» – это сигнал метки «нуль». С одного оборота датчика получается один импульс.
В энкодерах промышленного назначения используется сигнал дифференцирования, для работы с частотным преобразователем (частотником). Название у него сложное, а на самом деле все просто. Все каналы отдельно копируются своей инверсией.
Это необходимо для отдавания сигнала на значительные расстояния. Выходной канал энкодера подсоединяется к приемнику специального назначения, сделанному на усилителях операционного вида.
Импульс в итоге определяется в совокупности двух сигналов.
Подключение
Подключение простое. Подсоединяем напряжение 5 вольт на выходы энкодера. У нас раскладка: провод коричневого цвета – 0 В, белого цвета – +5 В, розовый, зеленый и красный – А, В, R.
Программа подключения энкодера базируется на прерываниях каналов А и В. Срабатывания прерываний происходят на переднем фронте. Получается ситуация, когда происходит торможение энкодера в момент растрового пересечения и выходной сигнал канала всегда остается положительным. Подсчет импульсов непрерывно ведется счетчиком.
В нашем случае мы не будем применять прерывания, потому что мы работаем с 4-мя датчиками, они эксплуатируются одновременно. Если применять схему прерываний, наверняка возникнет ситуация потери импульсов. У нас эта проблема решается путем установления значка наличия движения. А мы рассматривали эксплуатацию энкодеров промышленного назначения.
Работа счетчика импульсов на основе модуля энкодера
Счетчик работает в связке с модулем семиразрядного индикатора, который и будет отображать количество накрученных энкодером импульсов. При включении значение счетчика равно нулю.
Покрутим ручку энкодера по часовой стрелке. Значение счетчика инкрементируется на единицу при каждом щелчке энкодера. Наибольшее число можно накрутить 999999999. это число должно заполнить все разряды нашего семисегментного индикатора. Если вращать ручку дальше, то счетчик обнулится, начнет снова считать с нуля.
Для примера накрутим 120 импульсов. Теперь скручиваем обратно, вращая ручку против часовой стрелки. Центральная ось энкодера работает как кнопка. Она очищает от нулей свободные разряды индикатора. У кнопки есть небольшой дребезг контактов, поэтому выключение и включение происходит не сразу. Программным путем, дребезг устраняется. Это основа работы с модулем энкодера.
Подключение инкрементальный энкодера к avr
Маленькая и быстрая библиотека для энкодера
?
elchupanibrei (elchupanibrei) wrote, 2017-04-21 21:57:00 elchupanibrei elchupanibrei 2017-04-21 21:57:00 Categories:
- Литература
- Техника
- Cancel
Давно хотел разобраться с «крутилкой». Наконец появилось время и желание это сделать. В паутине нашел три метода обработки кода грея для энкодера.
Первый самый примитивный. Использует тонны if-else и програмный debounce на millis(). Работает медленно. Вот скриншот такой копипасты.
счетчик энкодера у курильщика с ардуино головного мозгаС переходными процессами в этом примере разбираются без таймера. Тупо ждут микросекунду. Шах и мат перфекционисты. Вторая особенность — вешают функцию onA() на первое прерывание, а onB() на второе. Зачем? Никто не запрещает читать encoder_A_Pin вместе с encoder_B_Pin при срабатывании внешнего прерывания на onA(). Освободившийся interrupt можно использовать для кнопки или второго энкодера.
Второй метод на основе массива всех возможных состояний энкодера. А их не много не мало 16 штук. Достоинства. Простота кода. Чуть-чуть быстрее if-else.
Автоматический debounce — все ложные состояния отбрасываются. Правда при сильном дребезге отбрасываются и истиные значения — энкодер кликает, а счетчик не срабатывает. Лечится добавлением 100nF/0.
1μF конденсаторов между ногами энкодера и землей.
таблица состояний энкодераСамый продвинутый — это доработанный второй. Из 16 состояний удаляются бесполезные. Какая нам польза от знания где крутилка до/после клика? На основе оставшихся 4-х комбинаций с помощью булевой алгебры и switch-case делается простейший счетчик. Все! Правда есть нюанс. Функция digitalRead() оказалась настолько медленной, что ATmega328 не успевал читать значения pinA и pinB при срабатывании внешнего прерывания с условием CHANGE на pin A. Поэтому для AVR пришлось использовать прерывание по Timer1. Каждые 0.01 секунд срабатывает таймер и AVR не спеша читает состояние пинов и обновляет счетчик энкодера. Для быстрых STM32 и ESP8266 все работает на внешнем прерывании — как только энкодер начинает крутиться, срабатывает внешнее прерывание на pinA, считываются значения pinA и pinB и обновляется позиция энкодера. UDP: Версия библиотеки подросла до 1.4.1 — заменен тормозной digitalRead() для ATmega328 . Тепрь AVR работает без костыля Timer1.
счетчик энкодера здорового человекаБиблиотека подсчитывает только физические клики, оставляя все лишнее за бортом. Внутренняя подтяжка включена и доплнительные резисторы не нужны. У популярного шилда KY-040 10КОм уже есть на плате и подключать их НЕ НАДО.
Чтобы подавить дребезг и избежать пропуск кликов нужно добавить конденсаторы:- 100nF/0.1μF между A и землей- 100nF/0.1μF между B и землей- 100nF/0.1μF между кнопкой и землей
БЕЗ КОНДЕНСАТОРОВ БИБЛИОТЕКА РАБОТАТЬ НЕ БУДЕТ!!!
железный debounceС теорией по методам устранения дребезга можно ознакомится здесь. Калькулятор для подбора гасящего конденсатора тут. Чем больше емкость конденсаторов, тем выше износ контактов энкодера.
расшифровка контактов KY-040UDP: Переписал код. Теперь еще быстрее, меньше в размере и винарнее. Для кого-то недостаток, для кого-то достоинство, но теперь без аппаратных прерываний не работает. Спасибо товарищу kotyamba за консультацию и знания.
UDP2: Пришлось опять переписать код. Как правильно заметил ksergey9 в х, наше с kotyamba творение более менее нормально работало на медленном AVR. Как только его запускали на быстрых Cortex все превращалось в тыкву. Тепрь все ОК. Лично проверил на Arduino Nano 16Mhz, STM32 Blue Pill и ESP8266.
UDP3: Воспользовался ООП и путем наследования сделал тяжелый класс с float — «RotaryEncoderAdvanced». В нем можно прописывать количество шагов на клик, минимальное и максимальное значение. Получился законченный велосипед. Естественно легкий класс «RotaryEncoder» никуда не делся и работает без изменений.
UDP4: Переделал «RotaryEncoderAdvanced» на template, прощай float. Библиотека может занимать меньше памяти — все зависит от типа используемых переменных. Добавил возможность на лету менять — step per click, minimum value и maximum value. Управляем множеством различных значений с помощью одного энкодера!!!
UDP5: Тормозной digitalRead() для ATmega328 заменен на быстрый, теперь все работает без костыля Timer1.
Забирать как всегда тут.
Arduino: как подключить энкодер к PC
Здесь находится описание и видео процесса подключения к компьютеру датчика угла поворота через Arduino и USB-порт. Получившийся прототип по принципу своего действия похож на устройство Powermate от компании Griffin
Сегодня рассказываю о том, как сделать из простого механического энкодера устройство ввода для компьютера. Идея простая: Существует целый класс устройств ввода, которые построены на принципе “ручки громкости”. К компьютеру подключается большая шайба которую пользователь может вращать против, или по часовой стрелке без остановки, тем самым регулируя разные параметры с высокой степенью точности. Таких устройств не очень много и большинство из них находят применение в каких-то сложных программах для видеомонтажа, 3D-моделирования или CAD:
- Griffin PowerMate
- Logitech NuLOOQ
- 3Dconnexion SpaceNavigator и пр.
Все эти устройства построены на угол-код преобразователях (энкодерах), которые можно найти в ближайшем радиомагазине. Вот и я во время очередного похода купил себе Bourns PEC11-4215F-S0024 за 124 рубля. Энкодеры различаются в основном по типу устройства (механические, оптические, магнитные и пр.), по выдаваемому сигналу (как я понял, для простейших моделей это код Грея) и по своему разрешению. О последнем подробнее. Разрешение это количество шагов (сигнальных изменений) которое обеспечивает энкодер за один свой полный оборот. Разрешение сильно зависит от типа энкодера и большая часть устройств находится в диапазоне от 8 до 1000 шагов. Однако, если верить фильтрам магазина DigiKey и чуть-чуть Википедии, то существуют какие-то промышленные монстры с разрешением 6000 шагов и более. Доставшийся вариант имел разрешение в 24 шага. Забегая вперёд скажу, что этого мало.
Подключение не вызвало никаких проблем: Вытащить из ящика старую Ардуину и напрямую подсоединить к ней выводы. Средний вывод энкодера — общая земля. Правый и левый отвечают за сдвинутые по фазе сигналы.
Подключить их к 1му и 2му аналоговым входам Ардуино.
Кнопку энкодера (да, на ручку этой модели можно нажимать) подключить ко 2му цифровому порту Ардуино через 10 кОм резистор, как рекомендует туториал на их сайте.
Для того чтобы подружить получившуюся железку с компьютером было нужно чтобы прошивка Ардуино, получив сигнал от энкодера, писала данные об изменениях в виртуальный COM-порт через USB.
Естественно, я не первый, кто подключил энкодер к Ардуино, поэтому писать прошивку-сэмпл мне не пришлось и я взял готовую (кстати, в заметке по ссылке много полезного).
Поигравшись с delay, скоростью COM, отключив счётчики и включив обработку кнопки я добился приемлемого для прототипа качества опроса.
Без реализации акселерации, обработки ложных срабатываний, непредсказуемого флуда в порт и других тысяч важных мелочей.
Осталось написать какой-то приёмник на стороне компьютера который бы открывал нужный COM, парсил приходящие в него данные и на их основе эмулировал нажатия кнопок клавиатуры. Тут всё совсем просто. Получившийся скрипт на Питоне использует модули pySerial для работы с COM и pyWin для эмуляции клавиатуры. Сам скрипт состоит из 3х конструкций if … else и прост ровно настолько на сколько крив.
Итоговый результат вы можете оценить по видеоролику. Я надеюсь, что кому-то этот рассказ поможет решить давно заброшенную задачу, или, наоборот, вдохновит взяться за паяльник, или, на крайний случай, поведает о существовании такого класса устройств, как энкодеры.
что такое, как настроить, скетчи
В этом уроке мы обсудим, что такое протокол связи I2C, как он работает и как его использовать на Arduino. Для демонстрации мы построим проект, использующий I2C-соединение для обмена данными между двумя микроконтроллерами Arduino.
Что такое I2C?
c — это аббревиатура от Inter-Integrated Circuit (меж-интеграционная цепь или последовательная асимметричная шина).
I2C — низкоскоростной последовательный протокол связи, подходящий для передачи данных на короткие расстояния. Если вам необходимо передавать данные на большие расстояния, этот протокол не рекомендуется. Пример простой сети I2C показан ниже.
Как видно на диаграмме, преимущество использования I2C состоит в том, что для связи с несколькими устройствами требуется всего два провода.
Вся связь проходит по двум проводам к ведущему и ведомым устройствам и от них. Это очень полезно при выполнении проектов Arduino, так как Arduino имеет ограниченное количество входных/выходных контактов.
Многие датчики и модули, предназначенные для Arduino используют I2C для связи.
Сеть I2C
Сеть I2C состоит из ведущего и ведомого устройств, соединенных шиной. В сети I2C может быть несколько ведущих и ведомых устройств — мастеров и наследников.
Ведомое устройство (наследник)
Все ведомые устройства имеют I2C-адрес, который используется для идентификации устройства в сети. I2C-адрес позволяет ведущему устройству передавать данные конкретному ведомому устройству на шине.
Ведущее устройство (мастер)
Ведущие устройства могут отправлять и получать данные. Ведомые устройства реагируют на все, что посылает ведущее устройство. При отправке данных на шину только одно устройство может отправлять данные одновременно.
Шина
Шина в I2C — это просто два провода, которые соединяют все I2C-устройства в сети.
Эти два провода называются SDA и SCL. Провод SDA используется для связи между ведущим и ведомым устройствами.
Линия SCL несет тактовый сигнал, используемый для правильной синхронизации связи. Для поддержания обоих проводов в состоянии HIGH необходимы импульсные или подтягивающие (pull-up) резисторы.
Логические уровни
Будьте внимательны при подключении I2C устройств к Arduino.
Arduino выводит I2C-сигналы на 5В логическом уровне, но I2C-устройства работают с различными напряжениями логического уровня.
Таким образом, I2C устройство, которое работает на 3,3 В может быть повреждено при подключении к Arduino. В паспорте устройства должно быть указано напряжение логического уровня.
Если подтягивающие резисторы подключены к +5В, все устройства должны быть совместимы для работы с логическим уровнем +5В.
Использование I2C
- Чтобы продемонстрировать, как использовать I2C в Arduino, давайте создадим проект, который посылает данные туда и обратно между двумя ардуинами.
- Мы будем использовать I2C связи для изменения скорости мигания светодиода контакта 13 на одном Arduino, в зависимости от положения потенциометра, подключенного к другому Arduino.
- Один Arduino будет выступать в качестве мастера, а другой Arduino будет выступать в качестве ведомого.
Пины I2C Arduino
Arduino имеет специальные контакты для I2C, которые имеют встроенные подтягивающие резисторы в соответствии с требованиями протокола I2C.
Для плат Arduino Uno это контакты A4 и A5. Пин A4 — это контакт SDA, а пин A5 — это контакт SCL. В версии Arduino Uno R3 есть еще один набор контактов I2C рядом с USB-разъемом:
Чтобы создать этот проект, вам понадобятся следующие компоненты:
- Arduino Uno — 2 шт.
- Потенциометр (10КОм) — 2 шт.
- Перемычки
Схема соединения
После того, как вы соберете все детали, пришло время собрать проект. Следуйте нижеприведенной электрической схеме, чтобы все подключить:
Вы могли заметить, что у нас нет подтягивающих резисторов на линиях SDA и SCL. Подтягивающие резисторы уже встроены в I2C контакты Arduino, так что они нам не нужны.
Скетч для мастера
У нас есть два Ардуино в нашей сети I2C, так что у нас есть два набора скетчей. Один для мастера Ардуино, а другой для наследника Ардуино. Между двумя эскизами нет большой разницы, как вы увидите позже.
Теперь откройте Arduino IDE и загрузите код ниже на мастер Arduino:
// MASTER
#include
byte i2c_rcv; // data received from I2C bus
unsigned long time_start; // start time in mSec
int stat_LED; // status of LED: 1 = ON, 0 = OFF
byte value_pot; // potentiometer position
void setup()
{
Wire.begin(); // join I2C bus as Master
// initialize global variables
i2c_rcv = 255;
time_start = millis();
stat_LED = 0;
pinMode(13, OUTPUT); // set pin 13 mode to output
}
void loop()
{
// read potentiometer position
value_pot = analogRead(A0); // read analog value at pin A0 (potentiometer voltage)
// send potentiometer position to Slave device 0x08
Wire.beginTransmission(0x08); // informs the bus that we will be sending data to slave device 8 (0x08)
Wire.write(value_pot); // send value_pot
Wire.endTransmission(); // informs the bus and the slave device that we have finished sending data
Wire.requestFrom(0x08, 1); // request potentiometer position from slave 0x08
if(Wire.available()) { // read response from slave 0x08
i2c_rcv = Wire.read();
}
// blink logic code
if((millis() — time_start) > (1000 * (float)(i2c_rcv/255))) {
stat_LED = !stat_LED;
time_start = millis();
}
digitalWrite(13, stat_LED);
}
Объяснение скетча для мастера
Основная часть кода как для ведущего, так и для ведомых устройств — это то, что я называю логическим кодом мигания. Чтобы мигнуть светодиодом 13 на Ардуино, мы должны сделать следующее:
- Добавим глобальные переменные byte i2c_rcv, int time_start, stat_LED и byte value_pot в верхней части нашего скетча
- Инициализируйте значения глобальных переменных внутри функции setup()
- Инициализируйте контакт 13 Arduino как выходной контакт внутри setup() с помощью pinMode()
- Добавим код логики мигания внутри функции loop()
Библиотека Wire
Для использования встроенного интерфейса I2C Arduino мы будем использовать библиотеку Wire.
Эта библиотека поставляется в стандартной комплектации с Arduino IDE. Как и в других библиотеках Arduino, библиотека Wire имеет готовые I2C функции, чтобы сделать кодирование проще для нас.
Чтобы использовать функции библиотеки Wire, мы должны добавить его сначала в наш эскиз. В эскизе выше, у нас есть следующая строка в верхней части:
#include
После включения библиотеки мы можем использовать встроенные функции библиотеки.
Первое, что нужно сделать, это подключить устройство к шине I2C. Синтаксис для этого — Wire.begin(address). Адрес является необязательным для мастер-устройств. Итак, для эскиза мастера Arduino, мы просто добавляем код Wire.begin(); внутри setup().
Теперь мы переходим к циклу loop(). Наш код заставит Arduino прочитать значение потенциометра, подключенного к контакту A0, и сохранить его в переменной value_pot.
Отправка данных
После сохранения значения с пина A0 в переменную value_pot, мы можем отправить значение по I2C. Отправка данных по I2C включает в себя три функции:
- Wire.beginTransmission()
- Wire.write()
- Wire.endTransmission()
Wire.beginTransmission()
Мы инициируем команду отправки, сначала информируя устройства на шине о том, что мы будем отправлять данные.
Для этого мы вызываем функцию Wire.beginTransmission(address). Адрес — это I2C-адрес ведомого прибора, который будет принимать данные. Эта функция делает две вещи:
- Она информирует шину о том, что мы будем посылать данные.
- Он информирует предполагаемого получателя о том, что данные готовы к получению.
Wire.write()
А затем мы отправим значение переменной value_to_send с помощью функции Wire.write(value).
Wire.endTransmission()
После отправки данных нам необходимо освободить сеть, чтобы позволить другим устройствам общаться по сети. Это делается с помощью функции Wire.endTransmission().
Наше ведущее устройство также должно получить положение потенциометра от ведомого устройства. Мы делаем это с помощью Wire.requestFrom(), Wire.available() и Wire.read().
Wire.requestFrom()
Полным синтаксисом запроса данных от ведомого устройства является Wire.requestFrom(адрес, количество).
Адрес — это I2C-адрес ведомого устройства, от которого мы должны получить данные, а количество — это количество байтов, которое нам нужно. Для нашего проекта, адрес ведомого устройства 0x08 и нам нужен один байт.
Внутри loop() мы используем Wire.requestFrom(0x08, 1); для запроса одного байта данных от ведомого устройства 0x08.
После выдачи команды Wire.requestFrom(0x08, 1), за ней должна следовать команда чтения для получения ответа от шины I2C.
Write.available()
Сначала мы проверяем, есть ли данные на шине. Это делается с помощью функции Write.available() внутри условного оператора if(). Функция Write.available() возвращает количество байт, ожидающих чтения.
Wire.read();
Для получения доступных данных мы используем функцию Wire.read() и сохраняем возвращаемое значение в переменную i2c_rcv. Каждый вызов функции Wire.read() получает только один байт данных из шины I2C.
Скетч для наследника (ведомого)
Теперь загрузите этот код ведомому Ардуино:
// SLAVE
#include
byte i2c_rcv; // data received from I2C bus
unsigned long time_start; // start time in mSec
int stat_LED; // status of LED: 1 = ON, 0 = OFF
byte value_pot; // potentiometer position
void setup()
{
Wire.begin(0x08); // join I2C bus as Slave with address 0x08
// event handler initializations
Wire.onReceive(dataRcv); // register an event handler for received data
Wire.onRequest(dataRqst); // register an event handler for data requests
// initialize global variables
i2c_rcv = 255;
time_start = millis();
stat_LED = 0;
pinMode(13, OUTPUT); // set pin 13 mode to output
}
void loop()
{
value_pot = analogRead(A0); // read analog value at pin A0 (potentiometer voltage)
// blink logic code
if((millis() — time_start) > (1000 * (float)(i2c_rcv/255))) {
stat_LED = !stat_LED;
time_start = millis();
}
digitalWrite(13, stat_LED);
}
//received data handler function
void dataRcv(int numBytes)
{
while(Wire.available()) { // read all bytes received
i2c_rcv = Wire.read();
}
}
// requests data handler function
void dataRqst()
{
Wire.write(value_pot); // send potentiometer position
}
Объяснение скетча для ведомого
Для ведомого устройства существует небольшая разница в кодировании I2C-связи. Первая разница заключается в адресе Wire.begin(address).
Для ведомых устройств адрес является обязательным. Для нашего проекта адрес для ведомого устройства будет 0x08. Это может быть любой адрес, но убедитесь, что он уникален в сети I2C.
Некоторые I2C ведомые устройства также имеют определенные I2C-адреса, поэтому сначала проверьте спецификацию.
Мы присоединим I2C сеть в качестве ведомого устройства, добавив код Wire.begin(0x08); внутри setup().
Обработчики событий
Следующая задача — добавить в наш код обработчики событий для управления данными, полученными с других устройств в I2C сети.
Обработчики событий — это части кода, которые управляют событиями, с которыми наше устройство, скорее всего, столкнется во время работы.
Wire.onReceive()
В части скетча setup() мы добавляем функцию Wire.onReceive(handler) для регистрации функции (обработчика), которая будет управлять полученными данными.
Мы вызываем нашу функцию-обработчик dataRcv(). Обратите внимание, что имя функции может быть любым. В приведенном выше эскизе Wire.onReceive(dataRcv); вызывается в секции setup().
В конце эскиза находится код функции-обработчика. Он инициализируется как void dataRcv(int numBytes). Параметр int numBytes содержит количество байт полученных данных.
Wire.onRequest()
Следующий обработчик события, который мы будем использовать — Wire.onRequest(handler). Эта функция используется на подчиненных устройствах и работает аналогично Wire.onReceive().
Единственное отличие заключается в том, что она обрабатывает события запроса данных. Запросы данных поступают от основных устройств.
В функцию setup() мы добавляем код Wire.onRequest(dataRqst);. А в конце нашего эскиза добавляем функцию void dataRqst(). Обратите внимание, что обработчики Wire.onRequest() не принимают никаких параметров. Функция dataRqst() содержит только Wire.write().
Нам не нужны Wire.beginTransmission() и Wire.endTransmission(), потому что библиотека Wire уже обрабатывает ответы от ведомых устройств.
Тестирование Arduino I2C
А вот и самая захватывающая часть — включение питания и тестирование!
Используя Arduino IDE, загрузите эскиз мастера Arduino в одну из Ардуино. Затем загрузите скетч наследника в другую Arduino.
- Отрегулируйте потенциометр на ведущем устройстве, чтобы регулировать частоту мигания светодиода ведомого устройства.
- Отрегулируйте потенциометр на ведомом устройстве, чтобы контролировать частоту мигания светодиода ведущего устройства.
Наш код принимает положение потенциометра мастера и посылает его ведомому устройству через I2C. Затем ведомое устройство использует полученное значение для настройки времени задержки мигания светодиода. То же самое происходит и с положением потенциометра ведомого.