Максимально точно задать интервал в микросекундах

Oyreke
Offline
Зарегистрирован: 15.08.2013

Добрый день.

Требуется, чтобы на цифровом выходе появился импульс с очень точной длительность.

Использую библиотеку 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--;
    }
}

 

 

AlexFisher
AlexFisher аватар
Offline
Зарегистрирован: 20.12.2011

Скачет из-за других прерываний, а именно, из-за прерывания TIMER0 - системное время тикает (мне так кажется). Чтобы не было таких артефактов, нужно жестко управлять всем самостоятельно, что приводит к уходу из ардуино-среды в чистый с

Oyreke
Offline
Зарегистрирован: 15.08.2013

Других моих прерываний там проскочить не может, скорее всего это TIMER0.

Есть ли способы, чтобы в среде ардуины как-то учесть и компенсировать разброс?

Переписывать весь проект на си - задача вне моих умений.

SpectrumGP
Offline
Зарегистрирован: 14.08.2013

Попробуй работать на прямую с таймерами. Отключи остальные если не требуются :-)

// Работает таймер 1
TCNT1=0; //сброс счетчика
TCCR1A=0; //запрет счетчика 1А
OCR1A=60000; // если надо совпадение
TCCR1B=0b00001010; // разрешение счетчика 1В.
                                           // сброс счета в 0 при совпадении с OCR1A, 4-й разряд в 1
                                           // делитель на 1024. 1-3-й разряд = 101
TIMSK1=0b00000010; //разрешаем прерывание по совпадению
// Таймер 2 выключен
TCNT2=0;
TCCR2A=0;
TCCR2B=0;
TIMSK2=0;
ASSR=0;

С таймером 0 аналогично обходишься.

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

Плюс метода нет зависимости от дополнительных библиотек. Можно добиться счета и генераций довольно точных :-)

Для вывода генерации на ножку процессора достаточно включить соответствующие биты в регистре TCCR1A. Главное чтобы ножка OC1A или OC1B не задествована была.

AlexFisher
AlexFisher аватар
Offline
Зарегистрирован: 20.12.2011

И учти, что при отключении таймера 0 нельзя пользоваться системным счетчиком времени (millis) - он будет стоять. Ну и tone, видимо, работать не будет. И ШИМ, подвязанный на этот таймер

Oyreke
Offline
Зарегистрирован: 15.08.2013

В том-то и проблема, что у меня вся логика работы программы построена как в примере blink without delay()

То есть в каждом цикле записывается текущее время и сравнивается с разными интервалами. В программе вообще не используется delay().

Есть идея, использовать ШИМ на первом таймере. Фактически, мне нужно всего лишь задать импульсы со скважностью S = T/t = 250000/1000 = 250

Тут есть сложности: 

1) Должна остаться возможность изменять скважность и частоту следования импульсов

2) Мне необходимо считать импульсы и прекращать их по достижении определенного количества.

----

В целом, программа поделена на две независимые части

В первой, я с матричной клавиатуры 4х4 задаю параметры: количество импульсов, длительность импульса, частота следования импульсов

Во второй, программа выдает заданные импульсы

SpectrumGP
Offline
Зарегистрирован: 14.08.2013

Работая напрямую с таймером все останется тоже... Этот вариант проще в реализации :-) Самое главное точнее, т.к. точность будет зависеть от установки делителя таймера (1/1, 1/8 и т.д.).

Oyreke
Offline
Зарегистрирован: 15.08.2013

Все-таки, мне необходимы функции millis() и micros().

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

Но в таком случае, непонятно, почему у меня разброс времени не +/- 4мкс, а больше.

Других моих прерываний, которые могли бы вклиниться - нет.

Может быть есть другие системные прерывания?

Или все-таки библиотека TimerOne вносит погрешность?

А если отключать системные прерывания по таймеру0, то уже точно перебираться в чистый С. А мне этого пока совсем не хочется.