Как очень просто удвоить частоту импульсов
Перейти к содержимому

Как очень просто удвоить частоту импульсов

  • автор:

Arduino.ru

Очень быстрый умножитель импульсов (умножитель частоты)

  • Войдите на сайт для отправки комментариев

15 ответов [Последнее сообщение]
Чт, 05/06/2014 — 21:32
Зарегистрирован: 19.05.2014

Коллеги — требуется очень быстро (вход макс частота ~10кГц, ширина имульса ~5мкс) увеличить частоту импульсов на выходе, и посколько это импульсы шагов для ШД, то требуется произвести умножение очень пропорционально, при этом частота входящих импульсов категорически нелинейна.

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

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

#define LED 17 #define DIV 4 // Кол-во микроимпульсов #define INP PINC // Порт входящих импульсов #define OUT PORTF // Порт исходящих импульсов #define MAX 12000 // Максимальное время ожидания импульса void setup() < /* Инициализация портов */ DDRF = B11111111; PORTF = B11111111; DDRC = B10111111; /* Таймер1 для подсчета временных интервалов между входящими импульсами */ TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1B |= (1 void loop()< uint8_t inpValPre = 0b11111111; // Для хранения текущего состояние порта uint8_t inpValCur = 0b11111111; // Для хранения предыдущего состояние порта uint8_t inpRun = false; // Индикатор состояния серии импульсов uint8_t inpBufCnt = 0; // Входящий индекс буфера uint16_t inpBuf[256] = ; // Буфер для хранения временни импульсов uint8_t outRun = 0; // Индикатор состояния выхода uint8_t outDiv = 0; // Счетчик выполненных дроблений uint8_t outCnt = 0; // Исходящий индекс буфера uint8_t ovrCnt = 0; // Счетчик переполнения буфера /* Для ровного хода импульсов прерывания лучше выключить, однако теперь плата будет доступна только в момент загрузчика, сразу после загрузчика контроллер уйдетт в автономку и в этом состояниии его по юсб не прошить, т.е. придется ловить загрузчик */ //noInterrupts(); /* Лучше из loop не выходить, большие накладные расходы */ run: //PORTD = 0b00000000; // Для оценки времени исполнения по осцилу /* Считываем состояние входа, если пришел первый импульс - обнуляем таймер1 и продолжаем, если пришел следующий импульс - делим полученное время таймера1 и сохраняем значение в буфер Я пробовал реализовать этот кусок на прерываниях но это ничего по времени не дает */ inpValCur = INP; if(inpValCur == 0b00000000 && inpValPre == 0b01000000)< if(inpRun)< inpBuf[inpBufCnt++] = TCNT1 / DIV; // Используем переполнения для организации циклического буфера TCNT1 = 0; if(ovrCnt++ == 255) goto dbg; // Увеличим счетчик переполнения и если перепонение достигнуто - выпадем в дебаг // if(ovrCnt++ == 255) goto rst; // или сбросим счетчики и продолжим >else < TCNT1 = 0; inpRun = true; >> inpValPre = inpValCur; /* Проверяем закончилась ли серия импульсов, если время импульса превышено - записываем значение в буфер, если нет - продолжаем */ if(inpRun)< if(TCNT1 >= MAX) < inpBuf[inpBufCnt++] = MAX / DIV; if(ovrCnt++ == 255) goto dbg; // goto rst; inpBuf[inpBufCnt] = 0; // Обнуляем значение следующего элемента inpRun = false; >> /* Формируем начало импульса, если в буфере не нулевое значение - устанаваливаем уровень на выходе, обнуляем таймер и устанаваливаем признак импульса */ if(inpBuf[outCnt])< /* Если имеется признак импульса - устанавливаем уровень на выходе, и если время импульса истекло - формируем окончание импульса */ if(outRun)< //if(TCNT3 >= 2) OUT = 0b11111111; // Pulse width ~10us OUT = 0b11111111; if(TCNT3 >= inpBuf[outCnt])< if(outDiv == DIV)< outDiv = 0; outCnt++; ovrCnt--; // Уменьшаем счетчик переполнения >else < outDiv++; >outRun = false; > >else < OUT = 0b00000000; TCNT3 = 0; outRun = true; >> //PORTD = 0b11111111; goto run; rst: outCnt = inpBufCnt; outDiv = 0; goto run; dbg: Serial.println("DBG"); Serial.print("Inp count: "); Serial.println(inpBufCnt, DEC); Serial.print("Out count: "); Serial.println(outCnt, DEC); Serial.print("Ovr count: "); Serial.println(ovrCnt, DEC); for(byte b = 0; b < 255; b++)< Serial.print(b, DEC); Serial.print("\t"); Serial.println(inpBuf[b], DEC); >while(1)< digitalWrite(LED, HIGH); delay(250); digitalWrite(LED, LOW); delay(250); >; >
  • Войдите на сайт для отправки комментариев

Умножитель Импульса

Sunrise

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

Поделиться

Последние посетители 0 пользователей онлайн

  • Ни одного зарегистрированного пользователя не просматривает данную страницу

Сообщения

Предустанови отображаются в самом низу экрана, крупные цифры это текущие значения. Значения ток плывёт как будто при прогреве модуля, сейчас включил — 5 мА, через 10 минут 9мА, вчера до 20 доходило. вроде как похоже с прогревом ток увеличивается, включил5мА, прошло около 10 минут — 8мА. по калибровке никакой информации не нашёл, да и как калибровать если значение плывёт.

Владислав2

Я тоже. Правда иногда проверяю систему с внешнего загрузчика. Так, на всякий случай.

Alex-007

Теперь ещё надо научится компенсировать собственную АЧХ звуковой карты и правильно выбирать масштаб графика. Ждём. Хотя.

мир вам

Я работаю на базе Windows 11 PE Sergei Strelec но всёравно лезут вирусы.

Владислав2

Вот ведь, а ChePay дело говорит. Знаю такое.

Владислав2

Прошу прощения, но папы — они такие. Сначала липнут, потом сдуваются. Сорри. Прежде чем менять «маму на папу» о чём думал ? товарищ ..

Dr. West

Так ты у нас профессионал, который «лучше знает» или всё же, любитель, которому подавай » что попроще»?

Помогите со схемой удвоителя частоты импульсов

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

Поделиться

Последние посетители 0 пользователей онлайн

  • Ни одного зарегистрированного пользователя не просматривает данную страницу

Объявления

Сообщения

Предустанови отображаются в самом низу экрана, крупные цифры это текущие значения. Значения ток плывёт как будто при прогреве модуля, сейчас включил — 5 мА, через 10 минут 9мА, вчера до 20 доходило. вроде как похоже с прогревом ток увеличивается, включил5мА, прошло около 10 минут — 8мА. по калибровке никакой информации не нашёл, да и как калибровать если значение плывёт.

Владислав2

Я тоже. Правда иногда проверяю систему с внешнего загрузчика. Так, на всякий случай.

Alex-007

Теперь ещё надо научится компенсировать собственную АЧХ звуковой карты и правильно выбирать масштаб графика. Ждём. Хотя.

мир вам

Я работаю на базе Windows 11 PE Sergei Strelec но всёравно лезут вирусы.

Владислав2

Вот ведь, а ChePay дело говорит. Знаю такое.

Владислав2

Прошу прощения, но папы — они такие. Сначала липнут, потом сдуваются. Сорри. Прежде чем менять «маму на папу» о чём думал ? товарищ ..

Dr. West

Так ты у нас профессионал, который «лучше знает» или всё же, любитель, которому подавай » что попроще»?

Arduino.ru

Возникла задача, применение автомобильное. Есть датчик скорости, есть блок управления от более свежей акпп, подробнее тут: http://www.drive2.ru/l/7396416/ . Необходимо увеличение частоты входных импульсов в 2.6 раза. Сигнал естественно меандр. Мысль выдала вот такой скетч:

long time=0; void setup() < >void loop() < time=pulseIn(A2, HIGH,35000); if(time==0||time>30000) < noTone(13); >else if(time <20500) < tone(A3,735000/time); >>

Есть определенные недостатки, например функция tone выдает минимум 30Гц, мне необходимо от 16Гц, в выходном сигнале периодически встречаются провалы по частоте. Не часто, и не сильные, но есть. Значение 30000 вместе с цифрой 20500 образует гистерезис (частота датчика имеет некоторую неравномерность в начале. Из-за этого происходит чередование tone и noTone с большой скоростью). Прошу у Вас совета, как можно решить такую задачу? Приоретет отдается выходному сигналу, если несколько периодов входных импульсов будет припущено, это не принципиально.

  • Войдите на сайт для отправки комментариев

Вс, 16/08/2015 — 18:38
Зарегистрирован: 09.11.2012

Загляните в исходники tone(), разберитесь и сделайте на их базе свою функцию.

  • Войдите на сайт для отправки комментариев

Вс, 16/08/2015 — 18:54
Зарегистрирован: 25.01.2013
Araris пишет:

Загляните в исходники tone(), разберитесь и сделайте на их базе свою функцию.

мне пока соображалка не позволяет)

  • Войдите на сайт для отправки комментариев

Пнд, 17/08/2015 — 07:08
Зарегистрирован: 09.11.2012

  • Войдите на сайт для отправки комментариев

Пнд, 17/08/2015 — 11:31
Зарегистрирован: 05.08.2014

Я бы не стал с tone связыватся ни в каком виде. Делал бы дето так:

1. Считаем импульсы с входа по прерываниям. В обработчике прерывания инкрементим счетчик на 2.6. Подробней — ищи подсчет импульсов (фронтов) на входе по прерыванию и операции с фиксированной запятой

2. В лупе определяем полупериод выходных типа так если счетчик больше порога — полупериод сокращаем но не ниже некоторого допустимого минимального порога, если счетчик менше — полупериод увеличиваем, но не более максимального порога. Подробней — изучить основы АСУ.

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

А вобще задачка интересная очень, комплексная, решите сами — можете считать себя программистом 8)

  • Войдите на сайт для отправки комментариев

Пнд, 17/08/2015 — 20:06
Denis_1704
Зарегистрирован: 28.05.2014

я бы написал на микрос по прицепу:

время = сигнал(время смены сигнала в микросекундак) * 2.6

а дальше генериш сигнал по времени

  • Войдите на сайт для отправки комментариев

Втр, 18/08/2015 — 04:08
Зарегистрирован: 25.01.2013

Первая версия у меня и была с прерыванием по входу, но при этом была сильная неравномерность выходных импульсов, т.к. выходная частота может достигать нескольких кгц, и прерывания тормозят луп. Пойду посмотрю на tone изнутри. В первом посте есть опечатка в коде, вместо noTone(13), должно быть noTone(A3). Переносил код с uno на micro, не заметил.

  • Войдите на сайт для отправки комментариев

Втр, 18/08/2015 — 13:18
Зарегистрирован: 05.08.2014
steel780 пишет:

прерывания тормозят луп.

8о Это что же в них надо было писать?!

  • Войдите на сайт для отправки комментариев

Втр, 18/08/2015 — 16:10

trembo аватар

Зарегистрирован: 08.04.2011

I2C (TWI) 0- 12.5 MHz

  • Войдите на сайт для отправки комментариев

Втр, 18/08/2015 — 18:55

dimax аватар

Зарегистрирован: 25.12.2013

steel780, я бы сделал на 2-х таймерах. От расчётов частоты и измерения микросов лучше отказаться, у МК есть гораздо более удобный параметр -количество тактов процессора. Один таймер считает количество тактов между импульсами, и между циклами в своём прерывании программирует второй таймер, который уже выдаёт чистый сигнал. Функция loop() тут даже не потребуется.

  • Войдите на сайт для отправки комментариев

Втр, 18/08/2015 — 23:18
Зарегистрирован: 05.08.2014
dimax пишет:

steel780, я бы сделал на 2-х таймерах. От расчётов частоты и измерения микросов лучше отказаться, у МК есть гораздо более удобный параметр -количество тактов процессора. Один таймер считает количество тактов между импульсами, и между циклами в своём прерывании программирует второй таймер, который уже выдаёт чистый сигнал. Функция loop() тут даже не потребуется.

Не получится сделать стабильный меандр на выходе. Коэффициент умножения не целый. И на один входной импульс прийдется выдавать 2 или 3 выходных в заданом соотношении, на выходе частота будет плавать.

  • Войдите на сайт для отправки комментариев

Втр, 18/08/2015 — 23:42

dimax аватар

Зарегистрирован: 25.12.2013

Logik, почему? по моей задумке должно быть стабильно. Предположим насчитал счётчик 10000 тактов, вывалился в прерывание, сказал второму таймеру что-б тот досчитал до 10000/2.6 А второй таймер настроить на перечитку регистра OCR только в конце цикла (TOP). Таким образом пока не поменяется входная частота выходная будет стабильна, т.к. результат 10000/2.6 будет всё время одинаковым. А как только поменяется частота, то таймер сначала закончит старый период, потом перечитает регистр, и уже создаст новый, т.е. максимально корректно отреагирует с задержкой всего лишь в пол-такта входного сигнала.

  • Войдите на сайт для отправки комментариев

Ср, 19/08/2015 — 08:24
Зарегистрирован: 05.08.2014

Смотрим подробней. Пусть на входе стабильная частота и насчситали за импульс 10000 тактов, сказал формировать импульсы длительностью 10000/2.6 =3846 такта. За время следующего подсчета входного, т.е за 10000 тактов на выходе сформируются 2 выходных длительностью 3846+3846=7692. За оставшиеся 10000-7692=2308 на выходе будет еще 3846/2=1923 один уровень 3-го импульса и 2308-1923=385 второй уровен. Затем закончится 10000 тактов и все повторится. 3-й импульс — явно не меандр.

Гадит дробность коэффициента. Можна попробовать умножать на 26 (или 13), а затем выходной делить уже на 10 (или 5). Тоесть на оди входной генерировать таймером 13 выходных, за ним «ставить» делитель на 5 выдающий на выход результат.

  • Войдите на сайт для отправки комментариев

Ср, 19/08/2015 — 08:33

dimax аватар

Зарегистрирован: 25.12.2013

Logik, вы наверное не так меня поняли.. Или я что-то не понимаю, что то упускаю? Первый таймер в режиме счётчика только программирует длительность работы второго таймера-генератора, кроме как передать число 3846 он больше ничего не может. Второй таймер отсчитает 3846 тиков , инвертирует выход, и опять начнёт считать 3846 тиков. Сбить равномерность работы 2 таймера никак не возможно, он в независимости от чего бы то нибыло отсчитает положенное количество тактов. Я бы мог даже набрасать скетч, но вряд ли набор регистров таймера будет о чём-то наглядно свидетельствовать..

  • Войдите на сайт для отправки комментариев

Ср, 19/08/2015 — 08:43
Зарегистрирован: 05.08.2014

Сбивать работу второго таймера будет первый. Сбивать каждые 10000 тактов, устанавливая новую длительность. Возможно вы предполагаете не обнулять текущее состояние таймера при установку новой длительности?

  • Войдите на сайт для отправки комментариев

Ср, 19/08/2015 — 08:51

dimax аватар

Зарегистрирован: 25.12.2013

Logik, зачем обнулять? Второй таймер не будет сбиваться. Он отсчитает положенное, потом перечитает регистр OCR, и в следущий раз досчитает до нового значения, если оно изменилось.

  • Войдите на сайт для отправки комментариев

Ср, 19/08/2015 — 10:34
Зарегистрирован: 05.08.2014

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

Смотрим поведение при изменении длительности на входе. Там вообще печалька. Допусти первый импульс 10000 тиков, второй в десять раз больше- 100000, потом импульсов нет. Типа машина тормозила и стала. Во время измерения первого импульса ничего не выводится (наверно. или выводится?). за время измерения второго импульса выводится 26 импульсов по 3846 тиков, затем выводится некоторое количество импульсов, пока мы каким то образом не поймем что стоим. Т.е. мы стоим а на акпп идет сигнал что мы едем. За время двух импульсов на входе, т.е. 110000 тиков, на выходе было не менее 26 импульсов. Это явно не увеличение частотыв 2,6 раза.

Ещё думаю не лишнее.

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

  • Войдите на сайт для отправки комментариев

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *