Необходимо отмерять секунды

А я про корректировку не говорил. Не нужне она мне.

а разве не так считается ?

OCR1A = 16000000 / 1024 * секунды - 1 

Так я и сам спросил. Может и правильно. Зачем -1? Ведь 64мкс теряются вроде бы…

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

Да, я к таким себя не отношу, “плаваю” во многих вопросах.
Но вариант отсчёта секунд таймером1 тоже считаю лучшим(ИМХО)

Калькулятор говорит, что будет:

@dimax, рассуди нас плиз!

Озадачили…придётся разбираться))
Первым частенько пользуюсь, второй только нашёл…

Спойлер

Спойлер

поделитесь…

https://trolsoft.ru/ru/calc#AvrTimer16

1 лайк

Это неравнозначные варианты:
первый - “в среднем через секунду”, а второй - “не менее чем через секунду”.

Ну да, OCR -1, то есть 15624. Потому что в OCR счёт с ноля. Т.е. деление на 1 получается при значении в регистре “0” Соответсвенно при записанном значении в регистре OCR 15624 мы получаем деление на 15625.

4 лайка

Понимаю, что именно так и правильно, но до конца пока ещё не осознаю почему…
Казалось бы, что проще - таймер стоит - в регистре 0. Прошёл один такт - в регистре 1. Прошёл другой - в регистре 2.
Видимо, чего-то ещё недопонимаю.

Сделал грубую проверку, добавив к коду от xDriver параллельно счётчик на micros()
Слова dimax полностью подтверждаются, при OCR = 15625 ошибка значительно больше

Спойлер
#include <avr/io.h>
#include <avr/interrupt.h>

volatile bool Print = false;
volatile uint32_t stsec = 0;
volatile uint32_t microsSum = 0;
volatile uint32_t lastMicros = 0;

void setup()
{
  Serial.begin(9600);

  // инициализация Timer1
  cli();  // отключить глобальные прерывания
  TCCR1A = 0;   // установить регистры в 0
  TCCR1B = 0;

  OCR1A = 15625; // установка регистра совпадения

  TCCR1B |= (1 << WGM12);  // включить CTC режим
  TCCR1B |= (1 << CS10); // Установить биты на коэффициент деления 1024
  TCCR1B |= (1 << CS12);

  TIMSK1 |= (1 << OCIE1A);  // включить прерывание по совпадению таймера
  sei(); // включить глобальные прерывания
}

void loop()
{
  if(Print)
  {
    Serial.print("stsec = ");
    Serial.println(stsec);
    Serial.print("microsSum = ");
    Serial.println(microsSum);
    Print = false;
  }
}

ISR(TIMER1_COMPA_vect)
{
  stsec++;
  microsSum += (micros() - lastMicros);
  lastMicros = micros();
  Print = true;
}  

OCR1A = 15624

Спойлер

OCR1A = 15625

Спойлер

Эх, хожу во тьме!)))

Димакс, а я тебя вспоминал давеча.) В хорошем смысле.
Человеку нужен частотомер 10-125 000 гц. Нашрайбал. Но, его то чем то нужно проверить.
Написал генератор на таймере1 от кнопок. А после этого и вспомнил, что у тебя был похожий.)
Нашел, подшаманил. Смех и грех.) Всё класс. Благодарю!

2 лайка

Да, всё так и было бы, если бы таймер досчитал до 2 и встал) Но у нас цикл. А таймер обнуляется после достижения OCR только на следующий такт: К примеру что происходит при OCR=2 - Наш счётный регистр начинает по кругу совершать 3 счётных цикла
0->1
1->2
2->0
Вот почему при OCR=2 будет цикл из 3 тактов, и соответссно получаем деление на 3

2 лайка

Большое спасибо за разъяснение!

1 лайк

По следам скетча из #1.

В строке 17 ЭТОГО скетча добавлено разовое выполнение delay(20000).

Нагонит ли stsec 20 секунд после выполнения этого delay?

long stsec = 0; // счетчик секунд;
unsigned long t2 = 0; // момент увеличения счетчика секунд
bool flag = true;
void setup()
{
}

void loop()
{
  if (millis() - t2 >= 1000)
  {
    stsec++;
    t2 = t2 + 1000;
  }
  if (flag)
  {
    delay(20000);
    flag = false;
  }
}

Нет, не нагонит

Следующие 20 циклов stsec будет увеличиваться на 1. А затем уже каждую сек.

1 лайк

нагонит