Как Arduino может выводить конкретную (т.е. 56 кГц) несущую частоту?

9

Я работаю над проектом по космической оптике для беспроводной передачи данных между двумя точками. Для этого я использую ИК-светодиод, подключенный к Arduino Uno, который пульсирует с несущей частотой 56 кГц для передатчика, и второй Arduino с модулем ИК-детектора 56 кГц для приемника.

Я попытался использовать delayMicroseconds () между командами pin high и pin low для создания несущей частоты. Этот вид работает, но частота не всегда одинакова, и любые дополнительные задержки для импульсного сигнала (т. Е. Время, необходимое для вызова функции и уменьшения) могут изменить ее.

Читая таблицу данных для ATmega328, кажется, что есть способ установить более точный импульс, используя таймеры чипа. Возможно ли это, и если да, то как создать импульс 56 кГц, используя таймеры?

jlbnjmn
источник
Какая точность вам нужна для вашей частоты 56 кГц? Т.е. какой частотный диапазон приемлем в вашем проекте? Я спрашиваю, потому что, используя одни таймеры Arduino, точность имеет ограничения.
jfpoilpret
От 55,5 до 56,5 кГц было бы идеально для поддержания высокого уровня чувствительности детектора.
jlbnjmn

Ответы:

10

Действительно возможно генерировать сигнал 56 кГц с таймером Arduino .

Таймер фактически может рассматриваться как специальный регистр в MCU, который содержит значение (начиная с 0), которое увеличивается с частотой, равной тактовой частоте MCU (16 МГц на Arduino Uno), вероятность делится на коэффициент, называемый предделитель . Когда это значение достигает заданного вами предела, называемого « Сравнение совпадений» , происходят две вещи:

  • Значение регистра таймера сбрасывается на 0.
  • Вызывается одна функция обратного вызова ISR (подпрограмма обработки прерываний) (вы можете определить ее так, чтобы она указывала на ваш собственный код).

Идея состоит в том, чтобы использовать этот ISR для изменения выхода логического вывода каждый раз, когда он вызывается ( HIGHтогда LOW, потом HIGH...).

Теперь, чтобы сгенерировать прямоугольную волну 56 кГц, вам нужно, чтобы ваш ISR вызывался 56000 * 2раз в секунду ( * 2потому что вам нужно менять выходное значение дважды за период).

Вы можете выбрать желаемое значение прескалера для таймера из следующего списка:

  • 1 (тактовая частота не делится, следовательно, 16 МГц)
  • 8 (тактовая частота делится на 8, следовательно, 2 МГц)
  • 64
  • 256
  • 1024

В Arduino Uno есть два размера таймеров / счетчиков (на самом деле они называются таймер / счетчик ): 8 бит и 16 бит.

В Arduino Uno (ATmega328P) у вас всего три таймера, но некоторые из них могут использоваться базовой библиотекой Arduino или другими библиотеками, используемыми в ваших эскизах (вы должны проверить это самостоятельно):

  • таймер0 (8 бит)
  • таймер1 (16 бит)
  • timer2 (8-битный): у этого есть больше параметров предварительного масштабирования (1, 8, 32, 64, 128, 256 и 1024)

Теперь вам нужно сгенерировать волну 56 кГц из 16 МГц, следовательно, без предварительного масштабирования, вам нужно посчитать:

16000000 / (56000 * 2) - 1 = 141.857( - 1потому что таймер считает от 0 до этого значения и сбрасывается только после его достижения)

Из этого расчета мы можем сделать два наблюдения:

  1. 141.857 не является целым числом, и, следовательно, вы не сможете генерировать волну ровно 56 кГц.
  2. Без предварительного масштабирования вам понадобится 16-битный таймер, поскольку 285 не представляется как 8-битное целое число без знака.

Отныне у вас есть два варианта:

  1. Используйте 16-битный таймер ( timer1 ), используйте prescaler = 1 и выберите 142в качестве сравнения совпадения; это даст вам следующую частоту:16000000 / (2 * (142 + 1)) = 55944 Hz
  2. Используйте 8-битный таймер ( timer0 ), используйте prescaler = 8 и выберите 17в качестве сравнения совпадения; это даст меньшую точность при следующей частоте: 16000000 / (8 * 2 * (17 + 1)) = 55555 Hzкоторая все еще находится в требуемом диапазоне.

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

Конечно, полная таблица данных ATmega328P также важна, если вы хотите в мельчайших подробностях понять, что вы делаете.

Некоторые важные замечания:

  • ISR выполняется с отключенными прерываниями и поэтому должен быть как можно короче. В частности, есть несколько функций из библиотеки Arduino, которые не должны вызываться из ISR.
  • Часы Arduino Uno не очень точные (вместо кварца используется керамический резонатор, что было бы гораздо точнее), поэтому выходная частота будет смещаться дальше.
jfpoilpret
источник
2
Также, когда указанный предел достигнут, аппаратное обеспечение может переключать пин-код. Таким образом, нет необходимости использовать ISR вообще. С ISR всегда будет джиттер, потому что инструкция не может быть прервана после начала. Однако аппаратное обеспечение всегда будет переключать штифт с желаемой скоростью.
Ник Гэммон
Несколько удивительно, что Arduino Uno использует керамический резонатор, но источником для него является Arduino UNO FAQ (рядом с «Uno использует резонатор или кристалл для тактовой частоты процессора?» ).
Питер Мортенсен
3

Я нашел tone()полезным для генерации высокочастотных импульсов на любом контакте. Он должен быть в состоянии обрабатывать 56 кГц. (Редактировать: как отмечает jfpoilpret, самое близкое, что вы могли бы получить на Arduino 16 МГц, - около 55,944 КГц)

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

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

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

Питер Блумфилд
источник
Приемники часто имеют активные низкие выходы вообще. Если вы подключаете верхнюю часть светодиода к 56 кГц, а нижнюю - к выводу данных, когда вывод данных становится низким, вы получаете ИК-выход, что должно привести к снижению уровня приемника. Нет и затвора нужны, просто светодиод и резистор. Единственная проблема заключается в том, что текущие штырьки ввода-вывода могут работать.
EternityForest
2

Принятый ответ jfpoilpret очень хорошо написан, совершенно действителен, и в 99% случаев я буду делать именно то, что он объясняет. Его решения находятся в пределах ваших определенных параметров, поэтому они должны работать очень хорошо. Но что лучше, чем « очень хорошо »? Совершенство! В конце концов, вопрос в том, чтобы получить точное значение. Как уже говорилось, достаточно близко в большинстве случаев хорошо (возможно, во всех), и даже при работе с чем-то вроде часов, когда 1 секунда должна быть 1 секунда, вы все равно должны страдать от недостатков унаследованных частей.

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

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

В вашем случае вам нужна конкретная частота, и самое приятное в этом то, что фактически 56 кГц можно достичь очень легко (не считая практических недостатков деталей). Так что это тоже идеальный пример.

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

Для начала напомним, что из-за переключения состояния вывода необходимо выполнить ISR в два раза больше, чем частота сигнала. Это 112 000 раз в секунду. 56 000 и 16 000 000 не складываются очень хорошо, как уже отмечалось. Нам нужно изменить либо частоту сигнала, либо частоту тактов. Давайте разберемся с неизменной частотой сигнала и найдем лучшую тактовую частоту.

Было бы очень просто выбрать часы с некоторым порядком величины, превышающим 56 кГц (или 112 кГц, но это практически то же самое), так как вы добавляете только нули, и этот тип математики является самым простым для большинства людей. К сожалению, все в этом мире является своего рода компромиссом с чем-то. Не каждое значение будет работать.

Первый пример со слишком низкой скоростью тактового генератора.

Если вы выберете тактовую частоту 56 000 Гц, вы ничего не сможете сделать, так как вам нужно будет звонить в ISR каждый цикл и больше ничего не делать. Это совершенно бесполезно. Если вы выберете в 10 раз более высокую скорость (560 кГц), у вас будет 9 (10 циклов для достижения таймером максимального значения - один цикл для вызова функции ISR), чтобы микроконтроллер выполнял вашу работу, и этого вполне может быть недостаточно. Вам просто часто требуется больше вычислительной мощности.

Если вы выберете слишком большое значение с другой стороны, то при 56 МГц микроконтроллер просто не сможет с ним работать. Это слишком быстро. Таким образом, простой выбор самой большой цены в магазине также не снизит ее.

Оригинальные Arduino Uno R3 имеют штатные часы на 16 МГц, поэтому все, что работает медленнее, гарантированно будет работать. Следующее значение, которое на порядок больше 56 и ниже 16 МГц, составляет 5,6 МГц. Это позволит вызывать ISR каждые 50 циклов и создать идеальную частоту таймера 112000 Гц. И ваш сигнал будет ровно 56 кГц. У вас будет 49 циклов микроконтроллера для выполнения вашей программы между вызовами ISR, но она по-прежнему будет примерно на 1/3 скорости исходных часов. Можно использовать 112 в качестве базы и использовать тактовую частоту 11,2 МГц, и это даст около 2/3 стандартного резонатора 16 МГц. Функция ISR будет вызываться каждые 100 циклов и при этом генерировать идеальный сигнал 56 кГц.

Однако существуют две основные проблемы с этими значениями.

  • Первая проблема сильно зависит от ваших потребностей: вы жертвуете примерно 1/3 (с 11,2 МГц) своей максимальной вычислительной мощности, чтобы получить точную частоту сигнала, которая использует легко обнаруживаемое значение регистра (OCR iirc ). Вы можете быть в порядке с этим или нет.

  • Вторая проблема - это жесткая демонстрация : очень легко найти значения, но очень часто они просто не существуют как изготовленный источник часов. Это веб-страница резонатора Фарнелла, которой просто не хватает 5,6 МГц и 11,2 МГц.

Чтобы обойти это, мы можем посмотреть на доступные значения резонатора и найти что-то еще, что можно использовать для генерации точно желаемых значений. Если мы разделим 56 на 4, мы получим 14 и, к счастью, есть резонатор 14 МГц. Это дает нам гораздо более высокую скорость и большую мощность, а также одинаково легко найти значение регистра. Чтобы вызывать ISR 112 000 раз в секунду, нам нужно поместить десятичное значение 124 или шестнадцатеричное 0x7C в регистр OCR, поэтому, посчитав 124 цикла + 1 для вызова ISR, мы получим желаемое идеальное значение.

NB

  1. ISR - подпрограмма обработки прерываний (это код, который выполняется только для сгенерированных прерываний)
  2. Насколько большой может быть ваша программа, зависит от объема памяти! Это не имеет ничего общего с тактовой частотой и не имеет отношения к тому, как часто вы звоните ISR.
  3. Когда микроконтроллер запускается с помощью команды программы, счетчик увеличивается. Если генерируется прерывание, вызывается ISR, и это значение сохраняется в специальном регистре. Когда код ISR завершается, значение счетчика программы восстанавливается из этого специального регистра, и программа продолжается с того места, где оно было прервано, как если бы это никогда не происходило.

    Я приведу крайне тупой пример. Если вы пурист, я предупреждаю вас: может возникнуть кровотечение из носа и глаз.

    Представьте, что вам нужно идти откуда-то куда-то. Пошаговые инструкции по маршруту - ваша основная программа и ее команды. Как быстро вы идете или бежите, зависит от вашей «тактовой частоты», но не от инструкций по маршруту (30 шагов вперед, 1 поворот 90 град. Влево, 10 шагов вперед, 45 град. Вправо и т. Д.) Они всегда одинаковы , Теперь представьте, что маленький ребенок или жадный коррумпированный местный политик время от времени развязывают ваши ботинки. Это событие, которое генерирует прерывание. Затем вы останавливаетесь после последнего шага, становитесь на колени и снова завязываете обувь. Это ваша программа ISR.

    Затем вы продолжаете с того места, где остановились; Вы не начинаете с начала. Когда вы идете без заботы в мире и все время, вам все равно, даже если вы должны завязывать обувь каждый второй шаг. Однако, если вы делаете это с временными ограничениями, такими как бег на 100 метров на Олимпиаде (или бег от голодного хищника, питающегося мясом), остановка и завязывание вашей обуви могут иметь ужасные последствия. То же самое с микроконтроллерами. Даже если вы выполните только одну строку кода, ваша программа будет продолжаться, хотя и медленно. Если вам не важна скорость, это не будет проблемой. Если вам нужно выполнить какое-то время, например, используя другие действия, зависящие от таймера, помехи могут быть очень нежелательными и проблемными.

  4. Меньше - больше! Более быстрые часы не всегда лучше. Устройства с меньшей тактовой частотой потребляют значительно меньше энергии. Это может быть решающим моментом в устройстве с батарейным питанием.

  5. Необходимые циклы выводятся из следующих формул:
    (тактовая частота / (предскалерное значение * необходимая частота вызовов ISR)) - 1

ZZZ
источник
TLDR: Desolder керамического генератора 16 МГц , и заменить его другим , что позволяет точно 56 кГц от целочисленного деления (например , 14 МГц и разделить на 250).
Питер Мортенсен
0

Вы можете включать и выключать несущую, просто переключая режим вывода несущей между выходом и входом. Я использовал это для управления тепловым насосом через инфракрасный порт (дистанционное управление) 37 кГц.

kiwiron
источник
0

Нет необходимости использовать ISR для создания носителя. Просто установите таймер для получения 50% ШИМ-выхода на необходимой несущей частоте. ISR тогда просто отвечает за модуляцию несущей - обычно с интервалами 0,5 или 1 мс - гораздо более удобная скорость. По моему опыту, ошибка 5% в несущей частоте допускается большинством ИК-приемников. Я использовал Freetronics EtherMega 2560 (который имеет много таймеров), но я уверен, что другие процессоры будут работать так же хорошо.

kiwiron
источник
Как именно осуществляется модуляция несущей? Изменение режима для вывода захвата выхода таймера между входом (несущая выключена) и выходом (несущая включена)?
Питер Мортенсен,