ATmega. Счетчик импульсов ШИМ. Подключаем Arduino к счетчику электроэнергии Начальная схема подключения узла измерения

  • Tutorial

Задача на сегодня: как определить угол поворота инкрементального энкодера?

Сегодня в серии публикаций про ардуино головного мозга коротенькая статья с небольшим экспериментом и парой рецептов. В комментариях к одной из моих прошлых статей меня обвинили в том, что ардуиной подсчитывать импульсы энкодера - фу так делать:
Оптически энкодер 1000/оборот и ATMega не имеющая аппаратной схемы работы с энкодером (как у серий STM32, например) - это тупик.
Дальше в комментариях было много теоретизирования, которое лучше пропустить. Давайте лучше попробуем протестировать в железе, насколько это тупик. Для начала, что такое инкрементальный энкодер? Тот, кто помнит эпоху до-оптических мышек, ответ знает точно. Внутри энкодера есть диск с прорезями, вот для наглядности я сделал фотографию диска с пятьюстами прорезями:


С одной стороны этого диска помещают светодиод, с другой фотодиод:

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

Как же определяется направление вращения? Очень просто: в датчике не одна, а две пары светодиод-фотодиод. Давайте нарисуем наш диск, точки A и B показывают положение фотодатчиков. При вращении вала энкодера снимаем два сигнала с этих фотодатчиков:

Датчики поставлены на таком расстоянии, чтобы при вращении с постоянной скоростью генерировался меандр, свинутый на четверть периода. Это означает, что когда фотодатчик А стоит напротив середины прорези, то фотодатчик B стоит ровно на границе прорези. Когда датчик крутится (условно) по часовой стрелке, то при восходящем фронте на сигнале B сигнал A равен единице. Когда же датчик крутится в обратную сторону, то при восходящем фронте на сигнале B а равен нулю.

Это всё прекрасно, но что мне копипейстить в мой проект?

Вот это:

Volatile long angle = 0; volatile char ABprev = 0; const int increment = {0,-1,1,0, 1,0,0,-1, -1,0,0,1, 0,1,-1,0}; ISR (PCINT0_vect) { // D8 or D9 has changed char AB = PINB & 3; angle += increment; ABprev = AB; } void setup() { pinMode(8, INPUT); // A pinMode(9, INPUT); // B PCICR |= (1 << PCIE0); // interrupt will be fired on any change on pins d8 and d9 PCMSK0 |= 3; ABprev = PINB & 3; Serial.begin(115200); } void loop() { Serial.println(angle); delay(100); }
Давайте объясню, как этот код работает. Я тестирую код на ATmega328p (Arduino nano), выходы энкодера поставлены на пины d8 и d9 arduino nano. В терминах ATmega328p это означает, что младшие два бита порта PINB дают текущее состояние энкодера. Функция ISR будет вызвана при любом изменении в этих двух битах. Внутри прерывания я сохраняю состояние энкодера в переменную AB:

Char AB = PINB & 3; // Внимание, ардуиновский digitalRead() противопоказан, // когда нам критична скорость работы
Для чего? Давайте посмотрим на предыдущий график, в нём пунктирными линиями обозначены моменты вызова прерывания (любой фронт на любом сигнале). Для каждого вызова прерывания цифры внизу - это состояние переменной AB:

Видно, что при вращении по часовой стрелке переменная AB меняется с периодом в четыре значения: 23102310 2310. При вращении против часовой стрели переменная AB меняется 01320132 0132.

Если у нас оба фотодатчика были перекрыты (переменная AB=0), а при вызове прерывания AB становится равной 2, то датчик вращается по часовой стрелке, добавим к счётчику единицу. Если же AB переходит от 0 к 1, то датчик вращается против часовой стрелки, отнимем единицу от счётчика. То же самое и с другими изменениями переменной AB, давайте составим таблицу:

Обратите внимание, что таблица заполнена не до конца. Что вставить на месте вопросительных знаков? Например, по идее, главная диагональ таблицы не должна использоваться никогда, прерывание вызывается при изменении переменной AB, поэтому перехода 0->0 случаться не должно. Но жизнь штука тяжёлая, и если микроконтроллер занят, то он может пропустить несколько прерываний и таки вызваться. В таком случае предлагаю ничего не прибавлять и не отнимать, так как нам явно не хватает данных; заполним недостающие клетки нулями, вот наша таблица:

Const int increment = {0,-1,1,0, 1,0,0,-1, -1,0,0,1, 0,1,-1,0};
Теперь, надеюсь, код понятен полностью.

В итоге на один период сигнала A у нас вызывается четыре прерывания, что при вращении датчика в одну сторону увеличит счётчик не на 1, но на 4. То есть, если на инкрементальном энкодере написано 2000PPR (две тысячи прорезей на диске), то реальное его разрешение составляет 1/8000 оборота.

Постойте, а что с дребезгом?

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

Сигнал A постоянный, поэтому согласно нашей табличке, на восходящем фронте сигнала B мы добавляем единицу, а на нисходящем вычитаем. В итоге, если мы сумеем отработать все фронты нашего дребезга, то наш алгоритм его прекрасно проглотит. И вот тут становится интересно, а сможет ли наша ардуинка отработать такие прелести? Теоретизировать можно долго, давайте ставить эксперимент.

От теории к практике

Считать импульсы будем тремя способами:
  • Софтверно на ATmega328p
  • ATmega328p, опрашивающая хардверный счётчик
Все три способа считают импульсы абсолютно одинаково, но, разумеется, хардверные способы имеют существенно большую скорость опроса сигналов. Энкодер используется Omron E6B2-CWZ6C (2000PPR).

Подключение

Софтверный счётчик

Подключение простейшее, достаточно два провода от энкодера завести на ноги d8 и d9 ардуины.

HCTL-2032

Подключение hctl-2032 к ардуине выглядит примерно вот так:

Чтобы не занимать все ноги ардуины, я поставил ещё 74hc165.

BeagleBone Blue


BeagleBone Blue имеет встроенный квадратурный декодер, поэтому 3.3В энкодеры можно просто завести на соответствующий коннектор. У меня энкодер имеет 5В логику, поэтому я добавил двусторонний преобразователь уровней на bss138 :

Эксперимент первый

Я взял свой стенд с маятником, который уже описывал :

Каретка ездить не будет, просто повешу три счётчика на энкодер маятника. Почему именно маятник? Потому что сила тяжести даёт неуплывающий маркер: каждый раз, как маятник успокаивается в нижем положении, счётчики должны показывать число, кратное 8000 (у меня энкодер 2000ppr).

Вот три счётчика, подключенные параллельно, сверху вниз: биглбон, софтверный счётчик, hctl2032. ШИМ-драйвер для двигателя каретки в данном тесте не используется:

Начало испытаний, маятник неподвижен, два монитора последовательных портов и счётчик биглбона, запущенный по ssh:

Рукой делаю один полный поворот маятника, жду, пока он снова успокоится в нижнем положении:

Все три счётчика показывают ровно 8000, как и положено! Хорошо, из комментариев мы вынесли, что из-за дребезга софтверный счётчик должен сильно ошибаться при низких скоростях маятника. Десять раз повторяю процедуру: качаю маятник так, чтобы он сделал один оборот, а затем жду, пока полностью успокоится. Затем снова качаю, жду, покуда успокоится. Трение низкое, одна итерация занимает пару минут, в итоге примерно полчаса работы счётчиков.

Ха, а ведь опять ни один не ошибся!

Эксперимент второй

Итак, дребезг в реальности оказался не столь страшным, как казалось. Снимаю маятник, и цепляю к оси энкодера шуруповёрт:

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

100 оборотов в минуту - порядок. 500 оборотов в минуту - порядок, согласие полное. 900 оборотов в минуту: АГА! Останавливаю шуруповёрт:

Хардверные счётчики по-прежнему согласны между собой, а вот софтверный прилично отстал. Давайте считать, насколько это согласуется с теорией. Мануал на ATmega328p говорит, что обработка (пустого) прерывания - это минимум 10 тактов микроконтроллера. Работа со стеком, чуть кода внутри прерывания - это в сумме тактов 40 на одно прерывание. 8000 тысяч прерываний на 900 оборотов в минуту (15 оборотов в секунду) на 40 тактов = 4800000 тактов в секунду. В целом наша оценка весьма недалека от тактовой частоты ардуины, то есть, 1000 оборотов в минуту - это потолок для счётчика энкодера высокого разрешения на прерываниях, причём для ардуины, которая не делает ничего другого.

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

Подведём итог:

1. Считать на прерываниях вполне можно, 15 оборотов в секунду - это всё же весьма приличная скорость. Но если нужно обрабатывать больше одного счётчика, всё становится резко хуже. Выбор энкодера играет сильную роль, так как в хороших энкодерах подавление дребезга есть внутри, поэтому хороший энкодер и копеечный 8-битный микроконтроллер - вполне себе решение.

2. Хардверные счётчики надёжнее, но дороже.

3. hctl2032 существенно дешевле BeagleBone Blue, но и сложнее подключается к контроллеру, а биглбон и сам себе контроллер, и умеет четыре энкодера разом обрабатывать. Да и усилитель для двигателя там уже есть на борту, поэтому стенд с маятником можно собрать вообще малой кровью. С другой стороны, даже будучи довольно экзотичной, hctl-2032 стоит пять долларов за штуку, и может спасти ситуацию, когда схема с каким-нибудь пиком или атмелом уже есть, и сильно менять её не хочется.

4. Говорят, stm32 и дёшев, и имеет хардверный счётчик. Но цена вхождения (в смысле времени) в вопрос больно кусается.

В общем, как обычно, идеального решения нет, всё зависит от задачи и от доступных ресурсов.

В этой статье собраны все данные про счетчик электричества на основе Ардуино, в том числе приведены схемы, прошивки, комментарии по поводу доработки текущей версии прошивки и конструкции.

Вот так оно выглядит в конечном итоге.

Первоначально я разбил всю информацию по большой куче маленьких статей — что сделало очень неудобным поиск ее и повторение этого устройства вообще. Эта статья исправляет эту ситуацию.

Часть 1. Идея, проектирование и мысли вслух.

Некоторое время назад я установил двухзонный счетчик электроенергии, чтобы воспользоваться более выгодным ночным тарифом(50% с 2300 до 0800). Оказалось, что 45% электрики мы потребляем ночью. Но ответа как происходит потребление в разрезе мест потребления. конечно это устройство не дает.

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

  1. Текущую мощность нагрузки
  2. Потребление с начала суток
  3. Потребление с начала месяца
  4. Процент ночного потребления в %

Также устройство должно передавать, на настраиваемый интернет-адрес, данные о потреблении за последние 24-ре часа, в виде 24-х отсчетов. Интервал передачи — устанавливается в минутах 1…120.

Задаваемые в меню параметры:

  1. Час в RTC
  2. Минуту вRTC
  3. День в RTC
  4. Месяц в RTC
  5. Год в RTC
  6. Интервал отсчета 1…120
  7. сетевой адрес c указанием позиционно символов: «a-z0-9_-/: «.Редактируемый символ должен быть выделен, чтобы было понятно что именно редактируется.

Первоначальный вариант устройства будет сделан на основе следующего набора модулей:

  1. ( уточнение по поводу подключения индикатора к мега 2560)

Прибор интересует для уточнения сколько потребляет мастерская, медиа-приспособления, кухонные принадлежности. В итоге надо получить данные в виде графиков, в Интернете или на локальном сетевом сервере ()

Начальная схема подключения узла измерения.

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

Беру макетную плату, ищу подходящий трансформатор, для замера напряжения (беру от дежурки АТХ), и вперед.

UPD. Измерительный узел

Часть 2.1 Заметки про удивительные особенности ENC28J60

Удивительная вещь. Начал сегодня копать модуль работы с езернетом, для проекта «счетчик». Кто бы сомневался, было весело, и все в итоге заработало.

По подключению. Смотрим где находить SPI интерфейс с Ардуино «Мега», ну или вашей. Подключаем. Вывод CS (выбор чипа) вешаем куда нам угодно, он потом задается отдельно в инициализации библиотеки. Я «повешал» его на 42-й вывод, у вас может быть какой-то другой. Остальные MOSI/MISO/SS/OV/3.3V подключаются к соответствующим выводам Ардуины.

Оказалось, что для уменьшения использования памяти разработчик «замечательной» библиотеки EtherCard решил, и отправил некоторые строки для GET запроса в память программы. То есть, представьте, некий программист-фрилансер решил вдруг сделать себе счетчик. Чтобы все было умно он решил сделать там редактирование строки-URL, куда отправляются данные. И даже это сделал сегодня:

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

Ничего, быстро слазил в библиотеку, нашел место где заполняется запрос, исковырял его, забрал все «лишнее» на мой взгляд, конечно. В итоге отлично все работает.

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

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

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

Часть 3. Начальная отладка программного обеспечения счетчика

Сегодня немного повозился с отладкой ПО счетчика. Дело в том, что ошибочно не установил понижающий резистор, на СТ-датчик и в итоге на вход проникало слишком большое напряжение, равно как и слишком много помех. Поправил, припаял 150 ом параллельно СТ-датчику, в общем вышло около 100 ом.

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

В итоге замер расхода ЕН на закипание чайника показал тоже самое что и на китайском ваттметре. Уже хорошо, но придется проверить и по основному счетчику, как-то.

На дисплее не поместилась буква h после kW, но следует понимать что она там есть. Число показывает расход с начала текущего часа. В конце часа передается на сервер и сбрасывается в ноль. Потом, наверное сделаю чтобы сбрасывалось раз в сутки.

ПО счетчика, в текущем виде —

Часть 4. Делаем первую часть корпуса

Сделал сегодня корпус, материал, такой же как и в прошлый раз — капролон 11 мм. Крепление правда на имбусных винтах М4, в прошлый раз было м3 везде. Это слабовато для корпуса.

Для масштаба положил мышку «эйр» вовнутрь.

Остается сделать переднюю панель, закрепить модули, сделать выфрезеровки под USB и питание 12В. В случае с этим приборчиком, достаточно, наверное 0,7А будет, то есть можно применить нечто малогабаритное.

Часть 5 Делаем переднюю панель

Часть 9. Обновлено ПО, по результатам эксплуатации устройства

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

Upd 2015-09-23. Написал сегодня интерфейс для просмотра данных мониторинга. Заодно и оптимизировал прошивку, нашел ошибочек в ней. Поднял внутренний ДНС сервер, на « » это минуты дело.

Просто показал последние 48-м часов (потер статистику, поэтому там меньше на графике) в виде заглаженного графика. Всплеск — это начало работы стиралки, по У — цена в гривнах за текущий час, с учетом ночного тарифа, конечно. По Х — дата/время.

Теперь можно немного посмотреть что происходит. Маленький нюанс — расположил все в домашней сети, для большей устойчивости.

Ранее уже писал, что попробовал одно стандартное ПО, чтобы показывать расход электрики (emoncms). Непонятная мне парадигма и подход. Там раз в три секунды отсылает на сервер данные, и показывает что-то. Я сделал по другому — устройство накапливает данные 1 час, потом отсылает за последние 24-ре часа. Веб=-сервер на запустил, это NAS, с низким энерго-потреблением.

UPD. Выяснилось, что это не Интернет у меня такой, это устройство иногда не передает данные. Не понятно, с чем связано, и отловить сложновато, поэтому пошел другим путем — подсчетом промежуточных показаний на основании текущего расхода. За сутки гдето 1-2 раза происходит сбой. Такая схема позволяет отказаться от хранения почасовых данных в еепром, которое также почему-то работает не совсем корректно.

UPD. Доделал немного ПО сайта показывающего данные. Теперь там есть вольтаж по часам, почасовой и посуточный расходы.

Подумываю над размещением ПО на гитхабе. Наверное. так оно и будет.

3

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

Atmel AVR, что большинство Arduinos основаны на оборудовании счетчика/таймера, которое будет считать импульсным во входном штыре напрямую. Все, что вам нужно сделать, это настроить аппаратное обеспечение для работы счетчика и прочитать регистр счетчика. Существует небольшая сложность для 16-битных счетчиков на 8-битном устройстве, но это легко преодолеть. Arduino настраивает таймеры для операций PWM по умолчанию, но это можно переопределить, как описано (подробнее см. Руководство пользователя AVR) - вам нужно использовать таймер/счетчик в режиме CTC.

ARM на базе Arduninos и почти любой другой микроконтроллер будут иметь аналогичные аппаратные средства; некоторые из них обладают большей гибкостью, благодаря чему штыри могут использоваться для подсчета оборудования.

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

В вашем случае вам, вероятно, необходимо прочитать количество импульсов в регулярный период, который меньше времени, в течение которого счетчик будет переполняться с максимальной ожидаемой частотой пульса. Так, например, если вы использовали 8-битный счетчик, а максимальная частота пульса составляла 1 кГц, вам нужно было бы опросить каждые 256/1000 секунд или меньше, но наибольшую точность можно получить, сделав этот период как можно дольше. Так, например, вы могли бы иметь что-то вроде следующего (это не реальный код, и только фрагмент):

For(;;) { delayMS(250) ; frequency = 4 * readCounter() ; }

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

For(;;) { int start = getMillisec() ; while(!counterOVF()) { // Do nothing (or something useful but quick) } int t = getMillisec() - start ; frequency = 256 * t/1000 ; }

0

Большое спасибо за ваш вопрос. Если я правильно понял, ваша первая идея состоит в том, чтобы отключить импульсы с помощью аппаратного обеспечения, а второй - все время, когда процессор занят. Проблема в том, что мой микроконтроллер полностью загружен (поэтому простой ISR, увеличивающий счетную переменную, не будет работать) и не может быть опросом, поскольку он должен выполнять другие задачи.Кроме того, у меня больше нет аппаратных счетчиков. Есть ли другие альтернативы? Я слышал, что это возможно, используя аналоговые порты (полагаясь на сходство с PWM). Большое спасибо - manatttta 28 авг. 14 2014-08-28 08:16:36

0

В обоих случаях счетчик аппаратных средств выполняет подсчет, во втором примере мой опрос проверяет флаг переполнения, но это просто для демонстрации принципа, это не фундаментальное решение; он может в равной степени быть обработчиком прерываний - преимущество состоит в том, что вы получаете одно прерывание для каждых 256 импульсов (при условии 8 бит счетчика), а не каждый импульс, поэтому накладные расходы прерывания намного ниже. - Clifford 28 авг. 14 2014-08-28 11:10:07

0

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

Реализовывал сигнал ШИМ 25 кГц . Осциллографом не обладаю, но проверить результат хочется. Делаем счетчик импульсов, проверяем работу.

Задача

На базе ATmega 328P реализовать счетчик импульсов для проверки ШИМ 25 кГц , точность измерений до импульса не нужна, но порядок нужно знать.

Решение

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

Для считывания импульсов воспользуемся внешними прерываниями, они описаны на страницах 87-96 документации от производителя . В Atmega 328P есть два входа, которыми мы можем отслеживать внешние прерывания INT0(PD2) и INT1(PD3) , для решения задачи воспользуемся INT0 .

Настройка внешних прерываний

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

Для определения по каким событиям будет вызываться обработчик прерывания нужно настроить регистр ERICA . Биты ISC00 и ISC01 отвечают за INT0 , а ISC10 и ISC11 за INT1. Настройка отслеживаемых событий идентична, за разницей в битах:

00 — Низкий уровень сигнала;
01 — Любое логическое изменение сигнала;
10 — Нисходящий фронт сигнала;
11 — Восходящий фронт сигнала.

Для непосредственного включения входов прерываний служит регистр EIMSK , биты INT0 и INT1 отвечают за одноименные выходы. По вышеизложенному пишем код

Void int0_initial(void) { DDRD = 0x00; // Порт D как вход PORTD = (1 << 2); // Включение подтягивающего регистра EICRA = (1 << ISC00) | (1 << ISC01); // Восходящий фронт сигнала EIMSK = (1 << INT0); // Включение входа прерывания sei(); // Разрешаем прерывания }

Обработка внешних прерываний

Прерывания настроил, теперь надо их обработать. Для этого существует функция обработки прерывания ISR() , которой необходимо указать тип прерывания, в моем случае INT0_vect . В функции будем делать инкремент переменной Tic_Count :

ISR(INT0_vect) { Tic_Count ++; }

Вывод результата

Для облегчения вывода результата, дабы не прикручивать дисплей воспользовался не чистой ATmega 328P , а Arduino UNO и Arduino NANO , на борту которых тот же МК.

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

Ниже полный код решения задачи с комментариями:

#define F_CPU 1600000UL #include #include volatile unsigned int Tic_Count = 0; // Обработчик внешнего прерывания INT0 ISR(INT0_vect) { Tic_Count ++; } void setup() { int0_initial(); Serial.begin(9600); } void loop() { cli(); // Запрещаем прерывания Serial.println(Tic_Count); Tic_Count = 0; sei(); // Разрешаем прерывания delay(1000); } void int0_initial(void) { DDRD = 0x00; // Порт D как вход PORTD = (1 << 2); // Включение подтягивающего регистра EICRA = (1 << ISC00) | (1 << ISC01); // Восходящий фронт сигнала EIMSK = (1 << INT0); // Включение входа прерывания sei(); // Разрешаем прерывания }

Теперь остается подключить сигнал ШИМ к ножке PD2, и открыть монитор последовательного порта. Так же можно сформировать и проверить сигнал на одном МК.

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

Для дополнительного задания

Принципиальная схема

Схема на макетке

Обратите внимание

    В этом эксперименте мы впервые используем микросхему, в данном случае - выходной сдвиговый регистр 74HC595. Микросхемы полезны тем, что позволяют решать определенную задачу, не собирая каждый раз стандартную схему.

    Выходной сдвиговый регистр дает нам возможность «сэкономить» цифровые выходы, использовав всего 3 вместо 8. Каскад регистров позволил бы давать 16 и т.д. сигналов через те же три пина.

    Перед использованием микросхемы нужно внимательно изучить схему ее подключения в datasheet’е . Для того, чтобы понять, откуда считать ножки микросхемы, на них с одной стороны есть полукруглая выемка. Если мы расположим нашу 74HC595 выемкой влево, то в нижнем ряду будут ножки 1-8, а в верхнем 16-9.

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

    Напомним, что на изображении семисегментного индикатора подписаны номера его ножек и их соответствие сегментам.

Скетч

Для того, чтобы передать порцию данных, которые будут отправлены через сдвиговый регистр далее, нам нужно подать LOW на latch pin (вход ST cp микросхемы), затем передать данные, а затем отправить HIGH на latch pin, после чего на соответствующих выходах 74HC595 появится переданная комбинация высоких и низких уровней сигнала.

Для передачи данных мы использовали функцию shiftOut(dataPin, clockPin, bitOrder, value) . Функция ничего не возвращает, а в качестве параметров ей нужно сообщить

  • пин Arduino, который подключен ко входу DS микросхемы (data pin),