Управление длительностью импульсов

piggy197
Offline
Зарегистрирован: 12.02.2016

Добрый день. Встала задача сгенерировать простейший импульсный сигнал. Под рукой имеется arduino 2560. Начал разбираться как и что, и вот сразу столкнулся с проблемой. Набросав незамысловатый код, оказался неприятно удивлен. 

analogWrite(pin,HIGH);

delayMicroseconds(1);

analogWrite(pin,LOW);

delayMicroseconds(1);

Осцилограф говорит, что длительность не 1 мкс, как этого бы хотелось, а целых 8,7+. С утра пытаюсь найти решение проблемы, но в итоге пишу сюда, господа знатоки. Очень прошу подсказать нубу его ошибку. 

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

Благодарю за внимание.

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015
piggy197
Offline
Зарегистрирован: 12.02.2016

Благодарю за ответ. Однако micros(), как я понял, измеряет время. Мне же необходимо его назначить. Я хочу получить импульсную модуляцию со скважностью 50% и длительностью импульса 1мкс.

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

уберите delay и получите 4 мкс :) c кварцем 16мГц, читайте работу таймеров

piggy197
Offline
Зарегистрирован: 12.02.2016

Его я тоже убирал и получал эти 4мкс. Выходит, что уменьшить это время до 1 мкс технической возможности у этой платы нет? Или я опять что-то не так понял?

Gres
Gres аватар
Offline
Зарегистрирован: 26.03.2013

Только таймеры помогут Вам. Вот по теме, там и пример есть. Есть еще такая функция, но частоты естественно ограничены.

piggy197
Offline
Зарегистрирован: 12.02.2016

Пытался использовать и tone(). Логика моих рассуждений такова: длительность 1мкс = 1МГц частоты. Осцилограф показывает 30мкс. Я и игрался с частотами, но меньше 12 никак не получалось. Сейчас буду изучать таймеры, надеюсь смогу решить свою проблему.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

piggy197, если вам нужны микросекундные точности то забудьте про ардуиновские функции. Насовсем :)

Quant
Offline
Зарегистрирован: 31.01.2016

Кстати, а зачем вам такая точность?

piggy197
Offline
Зарегистрирован: 12.02.2016

Чуял, что просто не будет :) Может подскажете, что надо вспомнить? Мозгом понимаю, что задача совсем не сложная, однако пятая точка испытывает противоположные ощущения.

piggy197
Offline
Зарегистрирован: 12.02.2016

Сказали копать - я копаю. Скажут не копать - не буду :)

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

piggy197 пишет:

Я хочу получить импульсную модуляцию со скважностью 50% и длительностью импульса 1мкс.

Скважность в % не измеряется. Предполагаю, что Вам нужен прямоугольный сигнал со сважностью 2 (меандр) и частотой 500кГц. Правильно?

Тогда держите:

void setup() {
	pinMode(9, OUTPUT);
	TCCR1A = 0x40;	// Переключение пина 9 по сравнению
	TCCR1B = 0x09;	// Установить СТС режим и делитель частоты 1
	OCR1A = 15;	// установить TOP равным 15
}

void loop() {}

Нужный Вам сигнал на цифровом пине 9.

А вот здесь есть много букв на эту тему.

piggy197
Offline
Зарегистрирован: 12.02.2016

Знаете, все ваши примеры, почему-то не дают никаких результатов. Сигналы отсутствуют.

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

piggy197, разумеется примеры то для УНО :)

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

piggy197 пишет:

Знаете, все ваши примеры, почему-то не дают никаких результатов. Сигналы отсутствуют.

Это Вы мне. Мой пример не даёт результата? 

Ну, а на чём Вы его запускаете? А-а-а- у Вас же Мега!!!!

Виноват - эти примеры для UNO-подобных ардуин.

Значит, так. Для меги это БЕЗУСЛОВНО возможно и так же просто и коротко, как и здесь. 

Лично я переделывать не буду - меги нет. Почитайте про таймеры и переделайте - это несложно. Или попросите кого-нибудь, у кого Мега есть.

И последнее. В примере (из этой темы), время будет точнее если 15 заменить на 16  - будет точно 1 мкс. Я тут чуть-чуть ошибся.

Когда будете переделывать на мегу - не забудьте, 15 замените на 16.

piggy197
Offline
Зарегистрирован: 12.02.2016

ЕвгенийП пишет:

Почитайте про таймеры и переделайте - это несложно.

Буду пытаться, только я, как абсолютный новичок, не очень понимаю магии заклинаний, типа TCCR1A, OCR1A и тд. Пока что :)

Gres
Gres аватар
Offline
Зарегистрирован: 26.03.2013

Информация 1. Информация 2. Информация 3. Её много есть, лучше конечно читать даташит на конроллер, но по ссылкам более подробно расписано. Да и ЕвгенийП Вам привел примеры, осталось только сменить регистры и их значения.

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

piggy197 пишет:

Буду пытаться, только я, как абсолютный новичок, не очень понимаю магии заклинаний, типа TCCR1A, OCR1A и тд. Пока что :)

Заодно и научитесь - будете понимать. Главное, теперь Вы уверены, что результат достижим и достижим совсем несложно, так что Вам нужно просто "дожать" и любая неудача - лишь повод искать ошибку, а не сомневаться в самом подходе. Всё, что Вам нужно сделать: установить CTC режим, установить сброс таймера по сравнению на нужном пине, поставить делитель частоты 1 и вставить в качестве предельного значения счётчика 16. И всё заработает.

Не забудьте про мою ремарку насчёт "заменить 15 на 16" - не знаю как я так лопухнулся. Там ведь всё просто - это число есть ни что иное, как количество тактов. Если тактовая частота 16МГц, то конечно же в 1 мкс должно быть 16 тактов, а не 15.

Удачи!

piggy197
Offline
Зарегистрирован: 12.02.2016

ЕвгенийП пишет:

Удачи!

Спасибо за столь мотивационный пост :) Если вас не затруднит, объясните, пожалуйста, почему в регистры TCCR1A и TCCR1B вы заносите 64 и 9 соответственно?

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

ЕвгенийП пишет:

И последнее. В примере (из этой темы), время будет точнее если 15 заменить на 16  - будет точно 1 мкс. Я тут чуть-чуть ошибся. Когда будете переделывать на мегу - не забудьте, 15 замените на 16.

Вы не ошибались Евгений :) Всё точно. Счёт регистра OCR идёт с ноля. При OCR=0 таймер будет дёргать свою ногу каждый такт мк, т.е. получим частоту 16/2= 8МГц. При OCR=15 таймер дёргает свою ногу на каждый 16-й такт, т.е. получим частоту 500кГц или ширину одного импульса 1us. Ровно что и хотел Т.С.

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Два самых старших бита регистра TCCR1A отвечают за то, что будет делать таймер в тот момент, когда значение его счётчика совпадёт со значением для сравнения, которое хранится в регистре OCR1A (в общем случае не обязательно в нём, но мы ниже ещё укажем, что у нас оно хранится именно в нём).

00 - ничего
01 - инвертировать соответсвующий (для счётчика 2 - девятый) пин
10 - установить пин в LOW
11 - установить пин а HIGH

Нам с Вами надо инвертировать, вот и пишем туда 01. Ну, а поскольку это самые старшие биты, а другие биты у нас должны быть нулями, получается. что мы туда пишем B01000000 или, что тоже самое 0x40

(кстати, два следующих бита точно такие же, но отвечают за пин 10. Поэтому, если мы вместо 0x40 загоним туда 0x10, то всё будет работать точно также, но с пином 10, а не 9).

В ТССR1B мы пишем 9 (это B00001001). Три самых правых бита выбирают делитель частоты для таймера. У нас написано 001 - делитель 1, т.е. таймер тикает на каждый такт процессора. Два следующих (влево) бита (у нас 01) устанавливают СТС режим со значением для сравнения, хранящимся в регистре OCR1A.

Ну, и последнее, что есть в том примере - в этот самый OCR1A заносится нужное значение.

Дальше всё работает так:

1. таймер стартует с 0 и на каждом такте процессора прибавляет единичку к своему счётчику.
2. как только значение счётчика становится равным числу, хранящемуся OCR1A, таймер инвертирует пин, сбрасывает счётчик в 0 и ... см. п.1

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

dimax пишет:

ЕвгенийП пишет:

И последнее. В примере (из этой темы), время будет точнее если 15 заменить на 16  - будет точно 1 мкс. Я тут чуть-чуть ошибся. Когда будете переделывать на мегу - не забудьте, 15 замените на 16.

Вы не ошибались Евгений :) Всё точно. Счёт регистра OCR идёт с ноля. При OCR=0 таймер будет дёргать свою ногу каждый такт мк, т.е. получим частоту 16/2= 8МГц. При OCR=15 таймер дёргает свою ногу на каждый 16-й такт, т.е. получим частоту 500кГц или ширину одного импульса 1us. Ровно что и хотел Т.С.

Точно? Меня смутило следющее. Вот смотрите:

1. В начальный момент, в счётчике 0, а когда там стало 1, то 1/16 мкс уже прошла, когда там стало 2, то уже 2/16 мкс прошли.
2. Когда в счётчике стало 16 - прошло ровно 16/16 мкс.
3. Как раз в этот момент он и сбрасывается в 0 и инвертирует пин.

Разве нет? Получается, чтобы он ждал 16 периодов, в регистре должно быть именно 16. Разве нет?

Впрочем, в любом случае. ТС возьмёт осциллограф, посмотрит и оставит как ему лучше. Я бы так и сделал на его месте :)

dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

ЕвгенийП, какие-то сложные конструкции вы в голове выстраиваете :) Счёт времени ведь идёт с конца предыдущего такта, а не ноля ocr.    ИМХО удобнее считать как делитель.   0 - F_CPU /1 ;  1 - F_CPU /2;   2 - F_CPU /3 , итд..

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Ну и слава Богу. Значит моё первое интуитивное решение было правильным, пока не начал лукаво мудрствовать. "Сороконожка не ведала горя, пока не задумалась в какой последовательности она переставляет ноги" :)

piggy197
Offline
Зарегистрирован: 12.02.2016

Большое спасибо за доступные для новичка объяснения! Задачу выполнил, настроил 2 выхода диференцированно, все как и хотел. Евгений, действительно, в 1 случае вы были абсолютно правы - максимальным значением надо делать 15 (проверенно осцилографом :)).

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

piggy197 пишет:

Задачу выполнил, настроил 2 выхода диференцированно, все как и хотел. 

С Победой Вас! 

Как видите, не боги горшки обжигают

Теперь, когда Вы всё сделали сами, Вы вполне сможете  довести немного до ума. Я про это не писал Вам раньше, чтобы мозги не пудрить лишними заботами.

Вот смотрите. мои примеры расчитаны на то, чтобы показать как это делается, а не на то, чтобы испольщовать их в серьёзных проектах. Поэтому они упрощены. В частности, я тупо выставляю нужные биты и присваиваю значение всему регистру целиком. При этом я "попутно" устанавливаю в ноль те биты, которые мне не вовсе не нужны. Если кроме моего примера никто не работает, то это приемлемо. А вот если там ещё работают какие-то библиотеки и т.п., то луше делать не так, а аккуратно выставлять в 0 или 1 те биты, которые для нас важны и НЕ ТРОГАТЬ те биты, которые нам фиолетово. Оставлять в покое их прежние значения. То, что сейчас мы все эти фиолетовые биты забиваем нулями, какой-то библиотеке может серьёзно помешать. Для того, чтобы так делать, нужно использовать не присваивание, а аккуратные побитовые операции. Это понятно?

piggy197
Offline
Зарегистрирован: 12.02.2016

ЕвгенийП пишет:

Задачу выполнил, настроил 2 выхода диференцированно, все как и хотел. 

 Для того, чтобы так делать, нужно использовать не присваивание, а аккуратные побитовые операции. Это понятно?

Спасибо за дельное замечание, в будующем обязательно это буду учитывать. Моя задача была - сгенерировать 2 меандра, 1 со сдвигом на пол периода. Я это сделал, однако меня смущает задержка между ними в 70 нс. Я так понимаю, эта задержка обусловолена временем исполнения одного такта. Хотелось бы одновременного выхода двух сигналов. Наверное, буду искать другое решение своей задачи. Или найду ардуинку с большей частотой. Еще раз большое спасибо за помощь!

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

piggy197 пишет:

меня смущает задержка между ними в 70 нс. Я так понимаю, эта задержка обусловолена временем исполнения одного такта. 

Наверное. Такт - 62,5 нс.

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