Добрый день.
Требуется, чтобы на цифровом выходе появился импульс с очень точной длительность.
Использую библиотеку TimerOne: сначала создаю прерывание на 249000 мкс, пишу в порт, запоминаю время. Потом меняю интервал на 1000 мкс, пишу в порт, и опять запоминаю время
Таким образом, получается 4 импульса в секунду, каждый импульс длиной 1000 мкс.
Вне прерывания, вывожу в порт рассчитанное время длительности.
Меня беспокоит то, что время случайно скачет в пределах 1000 - 1020 мкс.
Осциллографом пока еще не замерял.
Есть ли возможность исключить разброс?
04 | if (pulseActive == true ) |
09 | Timer1.setPeriod(timerPeriodDelay); |
15 | Timer1.setPeriod(pulseWidth); |
18 | pulseStart = micros(); |
Скачет из-за других прерываний, а именно, из-за прерывания TIMER0 - системное время тикает (мне так кажется). Чтобы не было таких артефактов, нужно жестко управлять всем самостоятельно, что приводит к уходу из ардуино-среды в чистый с
Других моих прерываний там проскочить не может, скорее всего это TIMER0.
Есть ли способы, чтобы в среде ардуины как-то учесть и компенсировать разброс?
Переписывать весь проект на си - задача вне моих умений.
Попробуй работать на прямую с таймерами. Отключи остальные если не требуются :-)
01
// Работает таймер 1
02
TCNT1=0;
//сброс счетчика
03
TCCR1A=0;
//запрет счетчика 1А
04
OCR1A=60000;
// если надо совпадение
05
TCCR1B=0b00001010;
// разрешение счетчика 1В.
06
// сброс счета в 0 при совпадении с OCR1A, 4-й разряд в 1
07
// делитель на 1024. 1-3-й разряд = 101
08
TIMSK1=0b00000010;
//разрешаем прерывание по совпадению
09
// Таймер 2 выключен
10
TCNT2=0;
11
TCCR2A=0;
12
TCCR2B=0;
13
TIMSK2=0;
14
ASSR=0;
С таймером 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, то уже точно перебираться в чистый С. А мне этого пока совсем не хочется.