Официальный сайт компании Arduino по адресу arduino.cc
Генерация высокочастных импульсов с помощью ардуино Леонардо ATmega32u4
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Нужна программа для ардуино которая генерирует серию импульсов нужной частоты в течении заданного периода времени.
Параметры импульсов задаются пакетом посылаемого на КОМ-порт. Формат пакета (A - частота импульсов в герцах, B - длительность серии импульсов в миллисекундах).
В конечном итоге нужно получить частоты порядка 1 МГц, 500 КГц, 100 КГц, 50 КГц. Я понял как работать с таймером на прерываниях а вот как быстро дёргать цифровой выход проблема. Можно дергать через регистры но боюсь испортить контроллер.
Дергать цифровые выходы командой digitalWrite() не получается, открыв библиотеку увидел много строк кода, а мне необходимо изменять состояние цифрового выхода один раз в восемь тактов, это при максимальной частоте.
Из всего этого вытекает вопрос.
Какой частоты можно добиться с помощью ATmega32u4?
>Дергать цифровые выходы командой digitalWrite() не получается
И в чем это "не получается", проявляется?
>Можно дергать через регистры но боюсь испортить контроллер.
Зря. Собственно "много кода" digitalWrite это просто выяснение какой порт и какой бит нужно установить на разных платах. А, в итоге, это все равно будет запись в порт. Просто digitalWrite долго до него добирается.
Испортить контроллер вы можете только большоим током через ножку. Например ногу подключенную напрямую к земле, включить на выход и дать в него HIGH. А чем вы это сделаете - digitalWrite или прямой записью - не важно.
Так чтоhttp://arduino.ru/Tutorial/Upravlenie_portami_cherez_registry. Но вначале неплохо-бы убедится что digitalWrite действительно не справляется с задачей.
>Я понял как работать с таймером на прерываниях а вот как быстро дёргать цифровой выход проблема.
Погуглите "arduino секреты PWM" (вот к примеру http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM), еще может помочь книга "arduino cookbook". Ну либо вкуриватся в даташиты в раздел работы с таймером самостоятельно. Cмотреть как сконфигурировать таймер, что-бы он по переполнению самостоятельно переключал ногу, без отвелечение проца на это.
Кстатит искать это можно не только "в ардуино" сайтах, но и про про AVR микроконтроллеры.
А ишо можно попробовать воспользоватся библиотекой Tone. Не знаю правда какую частоту из нее можно выжать.
Задача поставлена слишком неконкретно, потому сказать что либо нереально. Многие вопросы уже leshak объяснил
Согласен задачу нужно уточнить. Сейчас нужно заставить генерировать серию импульсов длительностью 0, 5 сек. с четырьмя частотами (1МГц, 500КГц, 100 КГц и 50 КГц). Запуск генерации начинается по команде с ком порта. До 100 КГц как я понял более или менее нормально а вот с высокими частотами все трудно, чего не получается.
Прошу помощи сам пока новичок
Как я понял, ком порт дает конфигурацию и старт. Если так, то возможно получится. Хотя бы один близкий пример последовательности можете привести?
Конкретно сколько импульсов, какой частоты, время между переключениями частот и т.п.
Пакет конфига такой <A B>
где А - частота импульсов а В - длительность серии импульсов.
Ком порт ждет конфигурацию, пока эта серия импульсов не закончится порт больше не прослушивается, как только серия закончилась останавливаем таймер и опять ждем пока на порт не придет пакет конфига следующей серии импульсов.
Попробуйте так - идёте в arduino\hardware\arduino\cores\arduino находите файл Tone.CPP в нем находите функцию void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)... меняете int(выделен жирным) на long. Сохраняете файл, запускаете ArduinoIDE и пользуетесь функцией tone. Теоретически должна работать, если есть осцилограф, то проверьте посмотрите так ли оно или хотябы частотомером мерьте.
Так и сделал, при компиляции выдала ошибку undefined reference to `tone(unsigned char, unsigned int, unsigned long)'
В тойже папке есть файл Arduino.h в нем в конце void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); тоже int на long исправьте.
Нашел обьявление функции в Arduino.h подправил и его буду проверять)
Заработало но больше 60 КГц не повышается если выставить 300 КГц и период 5 секунд идет сигнал в 60 КГц но не 5 сек а почти 25 секунд
Тоесть видимо количество импульсов правильно считает а вот интервал непрвильно считает видимо внутренние переменные тоже надо менять. Давно не програмировал но вроде вспоминаю быстро)
В Tone.cpp в функции tone во всех строках с расчетом ocr = F_CPU / frequency / 2 / 8 - 1; добавьте ко всем делителям букву L :
ocr = F_CPU / frequency / 2L - 1;
.....
ocr = F_CPU / frequency / 2L / 8L - 1;
.....
и т.д.
но мне кажется, что дело уже не в этом...
Да не помогло(
Судя по всему, функция софтовая, хоть и использует таймер0. Больше не сможет. Остается таймер, но там можно будет получить тоько фиксированную сетку частот. Если не устроит - то только внешний DSP
Да устроит, частоты фиксированые 50КГц, 100КГц, 500КГц и 1МГц. Но у меня опыта работы с прерываниями 0. ( В плане программирования на с++ более или менее нормально но С на компе преподавали а с железом мало работал. Курю мануалы уже 3и сутки а каменный цветок не выходит. Результат надо завтра послезавтра показывать а у меня максимум 60 КГц. На одном буржуйском сайте создатель tone.cpp писал что до 1 мегагерца реально дотянуть, мне в принципе и более маленькая частота устроит но не менее 500 КГц
Имелось ввиду, что они фиксированы не так как вы захотите, а как может их генерить МК - в зависимости от предделителя и тактовой частоты.
Хм. по идее тактовая частота атмеги 16МГц поделив на 8 получим 2МГц. Этого должно хватить для генерации импульсов частотой 1МГц? а поделив на 16 можем сгенерировать 500 КГц, а на 64 125КГц и использовав предделитель 128 получаем 62,5 КГц этого более чем достаточно.
Вопрос как мне безопасно дергать цифровой выход? И какой? Как я понял 1 и 2 нельзя 8 вроде безопасно, но дергать их надо через регистры, я боюсь получить мертвый камень, програматора нет, есть более старая ардуина на атмеге 328 её пока колупаю. Но за неё тоже переживаю не хочется трупов)
Что вы за них переживаете? ничего с ними не случится, и что вы так боитесь регистров? Какая у вас дуина на 328 атмеге?
Проверьте, будет ли 1 мегагерц на 9 цифровом выводе? Обратите внимание на первую строку.
Проверил, измерил осцилографом получилось 256 МГц сейчас попробую делитель уменьшить.
В функции
не удалось разглядеть включения режима CTC (set bit WG12/WGM12 to 1; WG13/WGM13 - факультативно). Для этого необходимо дополнительно установить бит 3 регистра TCCR1B:
В противном случае счетчик будет находиться в обычном режиме и генерировать прерывание TIMER1_OVF при достижении значения TOP=0xFFFF, т.е. при переполнении счетчика. Прерывания по совпадению (TIMER1_COMPA) не произойдет. Ибо даташит гласит:
"The simplest mode of operation is the Normal mode (WGMn3:0 = 0). In this mode the counting direction is always up (incrementing), and no counter clear is performed. The counter simply overruns when it passes its maximum 16-bit value (MAX = 0xFFFF) and then restarts from the BOTTOM (0x0000)."
И таки да - здесь настоятельно необходимо уходить от магических чисел и использовать макроопределения. Т.е. вместо
писать (вариант для ATMega328)
для ATMega32u4, соответственно, не WGnX а WGMnX:
и так далее.
Меньше шансов запутаться. Проще сверяться с даташитом. Дидактичнее.
Проверил, измерил осцилографом получилось 256 МГц сейчас попробую делитель уменьшить.
Что-то у вас не в порядке с осциллографом. Может быть Гц? ATMega, затактированная на 16 МГц никак не может выдавать на гора частоту больше своей тактовой.
Опечатался 250 килогерц
В функции
не удалось разглядеть включения режима CTC (set bit WG12/WGM12 to 1; WG13/WGM13 - факультативно). Для этого необходимо дополнительно установить бит 3 регистра TCCR1B:
В противном случае счетчик будет находиться в обычном режиме и генерировать прерывание TIMER1_OVF при достижении значения TOP=0xFFFF, т.е. при переполнении счетчика. Прерывания по совпадению (TIMER1_COMPA) не произойдет. Ибо даташит гласит:
"The simplest mode of operation is the Normal mode (WGMn3:0 = 0). In this mode the counting direction is always up (incrementing), and no counter clear is performed. The counter simply overruns when it passes its maximum 16-bit value (MAX = 0xFFFF) and then restarts from the BOTTOM (0x0000)."
Да, точно.
И таки да - здесь настоятельно необходимо уходить от магических чисел и использовать макроопределения. Т.е. вместо
писать (вариант для ATMega328)
для ATMega32u4, соответственно, не WGnX а WGMnX:
и так далее.
Меньше шансов запутаться. Проще сверяться с даташитом. Дидактичнее.
А вот с этим... не знаю по какой причине, НО уже не первый раз наблюдаю у людей проблему со стандартными хэдэрами для МК, то есть IDE на имена битов тупо ругается, поэтому и "магические числа".
Проверил, на буквы ide действительно заругался, использовал магические числа. осцилограф dso nano показал 270 КГц. но у него частота дискретизации 1 МГц, может импульсы просто сливаются? форма сигналов стала более неравномерная но это опятьже может быть косяком дискретизации
А если так
И вы так и не ответили, на какой дуине тестируете?
Сейчас тестирую на 328
сейчас показывает 113 КГц форма сигнала стала неравномаерная
У вас что то с осцилографом, не на чем больше померить? А попробуйте в 10 строке 8 заменить на 1.
Лучше 8 заменить на 49999 - должны получить частоту 16000000/2/50000=160 Гц. Легче контролировать частоту - даже плохоньким осциллографом или тем же скетчем (завести выходную ногу на любой цифровой пин и, считывая его состояние в цикле loop(), определить время между фронтами/рассчитать частоту).
Возможно осцилограф гонит, другого нет пока другой обещали дать послезавтра. 32u4 нет в списке ide, я под убунтой сижу. пока леонардо в её списке нет(
Леонардо нет, потому что у вас версия IDE ниже 1.0.1, да и не надо леонардо. Так что у вас осцил показывает с 1 и с 49999 ?
Нашел хороший осцилограф без последних изменений показывает 750 КГц, это тоже неплохо. Завтра изменю программу и посмотрю что покажет с последними правками. Машину с иде настраиваю
Долго разбирался с аппаратной частью не касающейся генератора но недавно вернулся к генератору. После экспериментов с параметром uint16_t c = 8 получил искомый мегагерц) и даже больше. Теперь встал вопрос об изменении частоты генерации а также об её остановке.
Как вынести запуск генерации в отдельную функцию?
И можно ли добавить прерывание которое будет запускать и останавливать генерацию?
Вот ряд частот, которого можно добиться
Да именно это я и наблюдал на осцилографе при изменении параметра с. Но теперь необходимо менять частоты и выключать генерацию через определённый промежуток времени, я попробовал вынести код иннициализации из функции setup в отдельную но это не помогло, плюс не совсем понимаю как добавить дополнительное прерывание для остановки генерации.
Вы вроде хотели частоту задавать из сериал-монитора?
Да именно так, с ком портом разобрался а вот как менять частоту и запускать-останавливать генерацию понять не могу. По идее надо это вынести в отдельную функцию как tone. Начал её разбирать но понял что только сильнее запутался.
Да и еще один момент при попытке сгенерировать 50 кГц ардуина начала выдавать два быстрых импульса и длинный промежуток между ними.
В общем методом проб удалось выяснить следующее - на частотах свеше 320 кГц перестает работать сериал, хотя не знаю как себя будет вести сериал на ATmega32u4, потому как проверяю на ATmega328.
Заливаете скейтч, запускаете сериал-монитор, пишите в него нужную частоту в Гц, нажимаете Send, в ответ приходит значение реальной частоты и на 9 ноге генерится сигнал.
В леонардо можно задействовать PLL для получения высокочастотного ШИМ. Сам, правда, не пробовал.
Вести с полей)) Делал усилитель сигнала, много времени ушло.
Но есть проблемма решения которой я не нашел. После выставления частоты выше 500 кГц ардуина переставала отвечать на команды. После отключения сериал монитора ардуина перестаёт генерировать сигнал.
Пробовал отсылать команды миникомом, после разрыва связи подобного эффекта не наблюдал. Сломал голову не понимаю почему так происходит, прошу совета гуру.
Походу просто не хватает процессорного времени при генерации такой частоты, не работает ни millis() ни delay() ни _delay_ms () ни while(), так что походу только ресет.
Тоесть если сбрасывается уарт происходит ресет ардуины? Но ведь прерывания забиты и опросить порт она не может
Если UART завис, а нужно выбрать другую частоту, то нажимаете RESET.
Закрытие окна сериал монитора приводит к прекращению генерации даже мегагерца. Как я пония при этом посылается "волшебный" пакет на ардуину как я понял это ат команда установки обрыва связи.
Так а зачем вы его закрываете, чем вам это окно мешает? У вас просто дуина ресетится и все.
Так дело в том что генерацию надо вырубать, постоянно перезагружать не есть гуд. А как только закрывается окно терминала генерация прекращается. Именно это и необходимо.
Так а зачем вы его закрываете, чем вам это окно мешает? У вас просто дуина ресетится и все.
А чего она ресетится на ЗАКРЫТИЕ? Или это именно леонардовский прикол? Обычно же вроде на открытие ресет идет?
UPD: глянул в описалово леонардо. Он и на открытие не должен ресетится. У него ребут идет при открытии/закрытии порта на 1200
UPD2: попроуйте сменить на Serail.begin на другую скорость. Возможно из за муток с таймерами у него сносит башню и он опознает текущиую скорость как 1200, что в свою очередь, выглядит как "нужно ребутнутся при закрытии".
Все опыты пока ставлю на 328 атмеге но в понедельник проверю на леонардо.
На открытие вроде не ресетится при бросе пишет start в ком порт но если переподключаешься при генерации частоты ниже 500 кГц start не приходит, соответственно ребута нет.