Максимально точно задать интервал в микросекундах
- Войдите на сайт для отправки комментариев
Чт, 15/08/2013 - 09:01
Добрый день.
Требуется, чтобы на цифровом выходе появился импульс с очень точной длительность.
Использую библиотеку TimerOne: сначала создаю прерывание на 249000 мкс, пишу в порт, запоминаю время. Потом меняю интервал на 1000 мкс, пишу в порт, и опять запоминаю время
Таким образом, получается 4 импульса в секунду, каждый импульс длиной 1000 мкс.
Вне прерывания, вывожу в порт рассчитанное время длительности.
Меня беспокоит то, что время случайно скачет в пределах 1000 - 1020 мкс.
Осциллографом пока еще не замерял.
Есть ли возможность исключить разброс?
// Отработка прерывания по таймеру void timerIsr() { if (pulseActive == true) { //digitalWrite(13, LOW); PORTB = 0b00000000; pulseEnd = micros(); Timer1.setPeriod(timerPeriodDelay); pulseActive = false; pulseFinished = true; } else { Timer1.setPeriod(pulseWidth); //digitalWrite(13, HIGH); PORTB = 0b00100000; pulseStart = micros(); pulseActive = true; pulseCounter--; } }
Скачет из-за других прерываний, а именно, из-за прерывания TIMER0 - системное время тикает (мне так кажется). Чтобы не было таких артефактов, нужно жестко управлять всем самостоятельно, что приводит к уходу из ардуино-среды в чистый с
Других моих прерываний там проскочить не может, скорее всего это TIMER0.
Есть ли способы, чтобы в среде ардуины как-то учесть и компенсировать разброс?
Переписывать весь проект на си - задача вне моих умений.
Попробуй работать на прямую с таймерами. Отключи остальные если не требуются :-)
С таймером 0 аналогично обходишься.
Данное обращение не очень удобно, т.к. требует чтения толмута по использоемому процессору, а именно установок регистров таймера. но ничего сложного нет.
Плюс метода нет зависимости от дополнительных библиотек. Можно добиться счета и генераций довольно точных :-)
Для вывода генерации на ножку процессора достаточно включить соответствующие биты в регистре TCCR1A. Главное чтобы ножка OC1A или OC1B не задествована была.
И учти, что при отключении таймера 0 нельзя пользоваться системным счетчиком времени (millis) - он будет стоять. Ну и tone, видимо, работать не будет. И ШИМ, подвязанный на этот таймер
В том-то и проблема, что у меня вся логика работы программы построена как в примере blink without delay()
То есть в каждом цикле записывается текущее время и сравнивается с разными интервалами. В программе вообще не используется delay().
Есть идея, использовать ШИМ на первом таймере. Фактически, мне нужно всего лишь задать импульсы со скважностью S = T/t = 250000/1000 = 250
Тут есть сложности:
1) Должна остаться возможность изменять скважность и частоту следования импульсов
2) Мне необходимо считать импульсы и прекращать их по достижении определенного количества.
----
В целом, программа поделена на две независимые части
В первой, я с матричной клавиатуры 4х4 задаю параметры: количество импульсов, длительность импульса, частота следования импульсов
Во второй, программа выдает заданные импульсы
Работая напрямую с таймером все останется тоже... Этот вариант проще в реализации :-) Самое главное точнее, т.к. точность будет зависеть от установки делителя таймера (1/1, 1/8 и т.д.).
Все-таки, мне необходимы функции millis() и micros().
Получается, что разброс времени у меня из-за срабатывания системного прерывания по таймеру0. Если я правильно понял, то оно вызывается каждые 4 мкс.
Но в таком случае, непонятно, почему у меня разброс времени не +/- 4мкс, а больше.
Других моих прерываний, которые могли бы вклиниться - нет.
Может быть есть другие системные прерывания?
Или все-таки библиотека TimerOne вносит погрешность?
А если отключать системные прерывания по таймеру0, то уже точно перебираться в чистый С. А мне этого пока совсем не хочется.