Прерывание по таймеру в СТС режиме ATMEGA328 кварц 16 мгц (UNO)

привет всем , попытался сделать таймер с точностью 1 мкс в режиме СТС , то есть на таймере1 (65535 тактов заполнения таймера , для точности 1 мкс нужно 16 тактов + вкл выключение , но точности менее 5 мкс получить не удалось таким способом , меняя количество тактов для прерывания СТС режима , значение счетчика меняется только при значениях выше 200-500 тактов или даже выше ( проверял на 2600 там меняется ) т. е. что 20 тактов что 5 , все равно получаю такую погрешность , код прикрепляю ниже

#include <Wire.h >
#include <LiquidCrystal_I2C.h >
#include <avr/io.h>
#include <avr/interrupt.h>

LiquidCrystal_I2C lcd(0x27 ,16,2);
volatile unsigned long T, myTimer, time_old ;
volatile boolean flag = 0 ;
int n = 0;
void setup() {
  lcd.init(); 
  lcd.backlight(); // подсветка 
  lcd.clear();
  pinMode(3,INPUT_PULLUP);
  attachInterrupt(1 , myinterrupt, RISING );// включаем режим аппаратного прерывания
  cli(); // выключения прерываний 
  TCCR1A = 0 ;
  TCCR1B = 0;
  TCNT1 = 0;
  OCR1A = 14;
  TCCR1B |= (1 << WGM12); // режим СТС
  TCCR1B |= (1 << CS10); // без подделителя
  TIMSK1 |= (1 << OCIE1A); // настройка прерывания режима СТС
  sei();// включение прерываний 
}

void loop() {
  if (flag) {
    float f = 1000000/T;
    lcd.clear();
    lcd.setCursor(4,0);
    lcd.print(T);
    delay(100);             // выводы на дисплей нужных значений 
    cli();
    flag = 0;
    TCCR1B |= (1 << WGM12);
    TCCR1B |= (1 << CS10); // включение прерываний после их отключения в самом прерывании ( чтобы таймер не мешал выполнению loop )
    TIMSK1 |= (1 << OCIE1A);
    sei();
  }

}
void myinterrupt(){
  if(!flag){  
    n++; // счетчик фронта , 1 или 2 

  }
  if (n > 3){
    n = 0;
  }
}

ISR(TIMER_COMPA_vect){

  myTimer++
  if ( n == 1){
    time_old = myTimer; // время первого фронта 
    n = 2;
  }
  else if (n == 3){
    T= myTimer - time_old ; // время второго фронта 
    flag = 1 ;
    n = 0;
    TCCR1B = 0;
  }
}

А точность чего?
Длительность импульсов можно настраивать с дискретностью 62.5 нс, а получить прерывание с частотой 1 МГц, очевидно, не получится.

Вы забываете что аппаратные прерывания обрабатываются функциями,вызов которых занимает достаточно много времени.
Пока обрабатывается myinterrupt(),уже наступает прерывание по сравнению ISR(TIMER_COMPA_vect).
Сами флаги прерываний,и,если соответствующим образом настроены выходы OCRx, наступают с точностью до такта.

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

  1. Переработать архитектуру
  2. Взять МК помощней(например stm32)(хотя спорно,т.к. там тоже есть нюансы)
  3. Изменить концепцию с МК на “железную” логику или ПЛИС.

Точность таймера , предполагается за 16 тактов проходит 1 мкс, но на самом деле прерывание срабатывает не в 1 мкс а в 5 мкс , хочу узнать можно ли сделать счетчик времени с такой точности и как

ТС, Дорогой, если тебе нужно измерить величину периода сигнала, то есть время между двумя фронтами, то нужно просто разместить заказ в “Ищу исполнителя”. Как раз недавно такое писал, поэтому за пару тысяч рублей “отдам в хорошие руки”. :wink:
Точность порядка микросекунды. Если писать очень аккуратно и входить в прерывание одинаково всегда - то точность два такта- вполне достижима. То есть задержка при входе в прерывание - порядка 50 тактов, но она одинаковая, значит можно считать только разницу, понимаешь?
И да, писать так как ты написал - не стоит. Зачем тебе КомпА вектор? Для каких целей? Чтобы время считать не мучь таймер, пусть крутится, только его счетчик забирай по прерыванию от входа и считай разницу.

Так если считать время надо,тогда режим захвата по входу ICR нужен. Даташит в помощь. Там разжевано до немогу.

Не путайте таймер и прерывание. Таймер можно запрограммировать на 8 МГц, а вызывать прерывание с частотой выше 150-200 кГц вряд ли получится.

Так надо всё таки выдавать точный сигнал или измерять его?
Если выдавать,то я бы за основу взял ассемблерные вставки файла delay.h в стандартном комплекте в avr-gcc. Там точные циклы здержки релизованы.

Владдракула правильно расписал задачу ,
На вход 3 приходит сигнал определенной частоты , нужно измерять период этого сигнала по 1 волне , с точностью до 1 мкс
А таймер нужен чтобы отчитывать время фронтов этого сигнала , надеюсь правильно расписал

Не выйдет. Вернее, мошт выйдет, но на другом контроллере

На PIC-контроллерах полно схем частотомеров до 50МГц…1ГГц.
Честно говоря никогда не задумывался как это там реализовано - или микроконтроллеры “заточены” под это дели или алгоритмы какие “хитрые”…

С прерываниями где то 2 мкс, меньше не получится. И то нужно изгаляться с обработчиком.
Без прерываний - 1 мкс на асм вполне реально. Dimax расписывал на старом форуме. Только ограничение на длину измеряемого импульса было.
Только речь о длительности импульса, а не о периоде. С этим ещё повозиться нужно.

А частотомеры в ПИКах работают на высоких частотах за счёт высокоскоростного предделителя таймера, значение которого вычисляется слегка по хитрому.

на аттини тоже высокоскоростной, не пытал, но уверен 100 мегагерц пролезет

Да вы чего? Замер времени производится аппаратно таймером в режиме ICR.

  1. Первый фронт,по прерыванию запоминаем регистр ICR
  2. По второму смотрим разницу значений регистра ICR.
    Всё!

Какие пределы измеряемой частоты, от и до?

очень интересно, как вы это себе представляете?
осциллограмму сигнала покажете?

От 1 до 750 Гц

c точностью 1 мкс?

С точностью 1 ppm?

Тогда метод с Input Capture Register (ICR1) подходит.
(Нужна ли такая точность - это другой вопрос)