Генератор меандра с изменяемой скважностью сигнала
- Войдите на сайт для отправки комментариев
Пнд, 20/03/2017 - 17:35
Здравствуйте, задача проекта: нужен генератор сигнала, в котором пачки импульсов с частотой 32 кГц генерируются с частотой 15 Гц. Длительность импульсов в пачке 400 Нс.
генерацию сигнала написал используя материалы форума:
boolean t=0; boolean t1=0; void setup() { Serial.begin(115200); pinMode(11, OUTPUT); pinMode(3, OUTPUT); pinMode(13, OUTPUT); pinMode(9, OUTPUT); pinMode(5, OUTPUT); static uint32_t enc; uint32_t ocr; uint32_t divider; float freq; //------ Timer1 ---------- TCCR1A=0; TCCR1B=0; TCCR1A |=1<<COM1A0; TCCR1B |= (1<<WGM12); // Режим CTC (сброс по совпадению) //расчёт прескалера и OCR по нужной частоте enc=25; Serial.println(F_CPU); divider=1; ocr = (F_CPU / enc /2 /divider); if (ocr >65536) { divider=8; ocr = F_CPU / enc /2 /divider; if (ocr >65536) { divider=64; ocr = F_CPU / enc /2 /divider; if (ocr >65536) {divider=256; ocr = F_CPU / enc /2 /divider; if (ocr >65536) { divider=1024; ocr = F_CPU / enc /2 /divider; if (ocr >65536){ocr=65536; }}}}} OCR1A=ocr-1; //запись в регистр прескалера switch (divider) { case 1: TCCR1B=1|(1<<WGM12); break; case 8: TCCR1B=2|(1<<WGM12); break; case 64: TCCR1B=3|(1<<WGM12); break; case 256: TCCR1B=4|(1<<WGM12); break; case 1024: TCCR1B=5|(1<<WGM12); break; } freq= (float) F_CPU/2 / (OCR1A+1) /divider; if (freq <10000) { Serial.print(freq,1);Serial.println(" Hz "); } if (freq >10000) { Serial.print(freq/1000,3);Serial.println(" kHz");} TIMSK1 = (1<<OCIE1A); // Разрешить прерывание по совпадению //---------Timer 2------- TCCR2A = 0;// set entire TCCR2A register to 0 TCCR2B = 0;// same for TCCR2B TCNT2 = 0; TCCR2A |=1<<COM2A0; TCCR2B |= (1<<WGM12); enc=3200; Serial.println(F_CPU); divider=1; ocr = (F_CPU / enc /2 /divider); if (ocr >255) { divider=8; ocr = F_CPU / enc /2 /divider; if (ocr >255) { divider=32; ocr = F_CPU / enc /2 /divider; if (ocr >255) { divider=64; ocr = F_CPU / enc /2 /divider; if (ocr >255) { divider=128; ocr = F_CPU / enc /2 /divider; if (ocr >255) {divider=256; ocr = F_CPU / enc /2 /divider; if (ocr >255) { divider=1024; ocr = F_CPU / enc /2 /divider; if (ocr >255){ocr=256; }}}}}}} OCR2A=ocr-1; //запись в регистр прескалера freq= (float) F_CPU/2 / (OCR2A+1) /divider; if (freq <10000) { Serial.print(freq,1);Serial.println(" Hz "); } if (freq >10000) { Serial.print(freq/1000,3);Serial.println(" kHz");} Serial.println(divider); switch (divider) { case 1: TCCR2B = (1<<CS20); break; case 8: TCCR2B = (1<<CS21); break; case 32: TCCR2B = (1<<CS20)|(1<<CS21); break; case 64: TCCR2B = (1<<CS22); break; case 128: TCCR2B = (1<<CS20)|(1<<CS22); break; case 256: TCCR2B = (1<<CS21)|(1<<CS22); break; case 1024: TCCR2B = (1<<CS20)|(1<<CS21)|(1<<CS22); break; } //TIMSK2 = (1<<OCIE2A); // Разрешить прерывание по совпадению sei (); // Глобально разрешить прерывания } ISR (TIMER1_COMPA_vect) { t1=!t1; TCCR2A = (t1<<COM2A0); } void loop() { // put your main code here, to run repeatedly: }
Таймер 2 не верно работает с частотой, например, вместо 3200 выдает 976, как изменить длительность более чем 1/255 не знаю.
когда делаю другим способом
boolean t=0; uint16_t x = 3200; float y = 0.065*5; void setup() { Serial.begin(9600); pinMode(9,OUTPUT); TCCR1A=(1<<COM1A1)|(1<<WGM11); TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS10); OCR1A=0; ICR1=0; ICR1= (F_CPU/x)-1; OCR1A= ((float) y / 0.0625 ) -1 ; } void loop() { t=!t; TCCR1A=t<<COM1A0; delay(20); }
строчка TCCR1A=t<<COM1A0; убивает изменение длительности, она становится равной 50% и частота вместо 3200 Гц, становится 1600 Гц.
Как исправить изменение частоты в первом случае и как добиться требуемой скважности и частоты во втором?
Генератор меандра с изменяемой скважностью сигнала
Так не бывает. Скважность меандра всегда равна двум и изменяться не может.
Ни в коей мере не критикую (т.к. не моё дело) но, возможно, Вы опечатались. Если Ваш ник должен означать библейское Чудовище, то правильное написание "Behemoth".
некоректное название использовал. пачки прямоугольных импульсов с определнноё длительностью сигнала.
PS по поводу ника - каждый пишет как хочет; это транслит; почему бегемот - сие великая есть тайна, ответ на которую сокрыт ото всех, даже от меня.
почему бегемот - сие великая есть тайна, ответ на которую сокрыт ото всех, даже от меня.
:-))))
Ну, наверняка навеяно булгаковским котярой! Такой милый персонаж!
самый простой способ - две ардуины на логический элемент И )))
строчка TCCR1A=t<<COM1A0; убивает изменение длительности, она становится равной 50% и частота вместо 3200 Гц, становится 1600 Гц.
Похоже не знакомы с битовыми операциями, лучше не откладывать это, а выучить сразу как таблицу умножения. TCCR1A= Этой командой вы сбрасываете ранее сделанные настройки регистра конфигурации таймера. В данном случае удобно использовать команду инверсии бита, тогда и t=!t не понадобится.
Похоже не знакомы с битовыми операциями, лучше не откладывать это, а выучить сразу как таблицу умножения. TCCR1A= Этой командой вы сбрасываете ранее сделанные настройки регистра конфигурации таймера. В данном случае удобно использовать команду инверсии бита, тогда и t=!t не понадобится.
нет возможности проверить сейчас, но следует писать "TCCR1A=TCCR1A^COM1A0;" ? про регистры смотрел на http://www.gaw.ru/html.cgi/txt/doc/micros/avr/arh/mega103_38.htm, но как правильно битовые операции записывать в arduino ide? не могли бы помочь справочными материалами? что долговечнее будет - использовать ардуино в таком режиме генератора или осбрать генератор на логических элементах?
Begemot, нет. Правильно будет "TCCR1A^=1<<COM1A0;" Чтива везде полно, ищите по словам "битовые операции" "двоичные операции" "булева арифметика". Как лучше сделать -только вам решать, т.к. нам неизвестно что вы хотите получить, информация в топике не позволяет определить лучший метод, т.к. непонятно для чего это, нужно ли управление генерацией, какая требуется точность, итп. Лично я бы в общем случае взял тини13 и написал код на ассемблере, что вышло бы по-любому компактнее и проще схемотехнически, чем на "логических элементах" :)
Begemot, нет. Правильно будет "TCCR1A^=1<<COM1A0;" Чтива везде полно, ищите по словам "битовые операции" "двоичные операции" "булева арифметика". Как лучше сделать -только вам решать, т.к. нам неизвестно что вы хотите получить, информация в топике не позволяет определить лучший метод, т.к. непонятно для чего это, нужно ли управление генерацией, какая требуется точность, итп. Лично я бы в общем случае взял тини13 и написал код на ассемблере, что вышло бы по-любому компактнее и проще схемотехнически, чем на "логических элементах" :)
Программа нужна для управления матрицей светодиодов через транзистор.
Использовал команду "TCCR1A=TCCR1A^COM1A0;" и получил то, что нужно, привожу примеры сигналов, скважность увеличил для наглядности.
С вашей командой "TCCR1A^=1<<COM1A0;" получился вот такой сигнал, получается инверсия работы, а не отключение выводов.
Привожу окончательный вариант программы.
И спасибо Вам за помощь и за те программы, что выкладываете.
Использовал команду "TCCR1A=TCCR1A^COM1A0;" и получил то, что нужно, привожу примеры сигналов, скважность увеличил для наглядности. С вашей командой "TCCR1A^=1<<COM1A0;" получился вот такой сигнал, получается инверсия работы, а не отключение выводов.
С "моей" командой происходит ровно то действие которое хотели вы -то есть инверсия бита COM1A0. То, что это не давало нужный результат -следствие вашей же ошибки, т.к. инвертировать нужно было тот бит, который устанавливался ещё в сетапе -т.е. COM1A1. Т.е. то, что у вас заработало -лишь следствие случайного везения. Фактически вы не коммутировали пин, как хотели, а делали операцию исключающее ИЛИ одновременно с 1(WGM11) и 2(не используется) битом, тем самым вызывая отключение бита WGM11, что в свою очередь переключало таймер в другой режим :) Вряд ли в другой раз вам так же улыбнётся удача.. так что двоичные операции нужно подучить :)
[quote=dimax]
/quote]
Увы, я неправильно понял описание COM1A0:(
Теперь всё работает как надо, но на осцилограмме проскальзывают вот такие импульсы
Не подскажете почему так происходит и как избавиться?
Не подскажете почему так происходит и как избавиться?
Плохо видно время и потому непонятна длительность импульсов, но скорее всего это обработка прерывания переполнения нулевогог таймера. Подробнее вот в этом посте и далее в теме.
Избавиться? Ну, не знаю, есть 100500 способов. По мне так, лучше всего сделать собственную службу времени и отказаться от ардуиновского сервиса времени на нулевом таймере.
Плохо видно время и потому непонятна длительность импульсов, но скорее всего это обработка прерывания переполнения нулевогог таймера. Подробнее вот в этом посте и далее в теме.
Избавиться? Ну, не знаю, есть 100500 способов. По мне так, лучше всего сделать собственную службу времени и отказаться от ардуиновского сервиса времени на нулевом таймере.
Длительность импульса равна примерно 0,32 мс, частота импульсов заданная 3.2 кГц, т.е. этот импульс занимает время между двумя заданными. Появляется он редко, 1 раз из 100, но может сильно навредить. Вернулся к ошибочному варианту пока, костыль, но такого импульса там нет, долго писал сигнал осццилографом в режиме послесвечения и он не проявлялся.
Begemot, правильно проскальзывают :) Если бы скважность была больше, то проскальзовали бы чаще, вы же не отслеживаете перед паузой в каком состоянии был выход, в единице или в ноле. Выходы из ситуации разные есть, начиная от вашего "счастливого" костыля до более логичных решений. Например вообще отказаться от практики несинхронного наступления паузы. Паузу можно сделать контролируемой, отсчитав нужное количество импульсов в прерывании. Например так:
Например так
Большое спасибо за объяснение и предложенный вариант решения, всё работает корректно.
dimax здравствуйте. У меня есть вопрос к вам, как специалисту. Но как я понял в этом форуме личных сообщений нет.
Хотелось бы узнать можно ли сделать специфический трех канальный генератор? Но файл похоже тоже тут не втавить.
Напишите как можно отаправить вам информацию. Мой email: nignitron@mail.com скайп. ruslabx
Спасибо
RuslanX, день добрый! Если специфический, то наверное лучше что-б было 3 независимых 16-битных аппаратных канала. Это либо мега2560, либо уже МК на ARM архитектуре. Я не программист, поэтому на заказ не пишу, обращайтесь в специализированный раздел Ищу исполнителя.
dimax cпасибо за ответ. Я понял вас. Но хотел бы узнать от веас для ардуинки это сложно?
Вот ссылка на файл что должен сделать генератор.
http://zfile.in.ua/download?file=1605e8b0dab3a20eef8e5f93fdc7689d
RuslanX, посмотрел . Всё зависит от того, какая частота вам нужна. И насколько плавно её нужно менять. Судя по картинке исключительно аппаратными средствами таймеров не обойтись, нужно задействовать прерывания. А значит опорная частота будет исчисляться не более десятка килогерц. В принципе можно и одним таймером обойтись, если все регулировки будут равны минимальному "кванту" -опорной частоте. Т.е. если прерывание будет строчить 1000 раз/сек, то минимальный квант времени будет 1мс . Т.е. ширина импульсов, движение фазы -всё будет кратно 1мс.
Спасибо dimax. Сейчас прикину. Пуш-пул (длинный импульс ключа) в районе 12-40 кГц. Пакеты нужны для компенсации реактивного сопротивления в индуктивности. Хотя правильней сказать реактивного сопротивления индуктивной емкости. Там частота нужна в пределах от 120 кГц до 6 мГц. И количество импульсов имеет значение в пакете. Дело в том что если будет их много то они уже зарядат внутреннюю емкость индуктивности и магнитный поток начнет двигаться от короткого импульса и соответственно пройдет свой путь по катушке, после чего прервется и начнется длинный импульс. А это не допустимо, потому что начнется новый переходной процесс (самоиндукция). А нужно поймать однонаправленный магнитный поток. Тесла должна сработать на определенном угле фазового сдвига магнитного потока. Если у Теслы имеется большое реактивное сопротивление, то понадобятся пакет с большим количеством импульсов, а если малое, то с малым. Частота Теслы тоже варируется как и пуш-пул ударами его в полувонну. Тоесть она работает в каждую полуволну верхнего и нижнего плеча. А от длительность импульсов в пакете в районе 900 кГц-1.6 Мгц.
dimax я просто хочу попробовать ардуино в этом деле. Хотя не уверен выживет ли она у меня вообще.
Для более полного понятия с чем я имею дело скину видео и можешь посмотреть мой канал.
Сдесь я показываю людям работу качера от аккумулятора. Обрати внимание на DC/DC конвертер. Он выдерживал и до сих пор в здравии, но вот с Ардуиной надо проверить.
https://www.youtube.com/watch?v=2qKkqzOuAOU
RuslanX, посмотрел, интересное у вас хобби :) По поводу частот от 120кГц -это уже за гранью возможностей арудин, тут нужно делать на ARM контроллерах, у них и скорость выше и возможностей у таймеров гораздо больше. В общем задача очень сложная.
Спасибо Дима что уделил мне время. Буду думать с что то логикой. Еще раз спасибо и удачи вам.
Begemot, правильно проскальзывают :) Если бы скважность была больше, то проскальзовали бы чаще, вы же не отслеживаете перед паузой в каком состоянии был выход, в единице или в ноле. Выходы из ситуации разные есть, начиная от вашего "счастливого" костыля до более логичных решений. Например вообще отказаться от практики несинхронного наступления паузы. Паузу можно сделать контролируемой, отсчитав нужное количество импульсов в прерывании. Например так:
А как для второго таймера сделать генератор мендра?