Как разделить высокую входную частоту на 1,25, как в старой TTL-логике Arduino?

В современном хронометрировании существует опорная частота 10 МГц (или любая степень 10). Цифровые часы принимают только частоту 32768 Гц (или другую возможную степень двойки).

Проблема в том, как правильно преобразовать степень 10 в степень 2. Это делается серией делителей 1,25 (каждые 5 входов выводят 4) и 2,5 (каждые 5 входов выводят 2).

Мне интересно, как это можно сделать с помощью Arduino. У меня высокая входная частота, скажем, 1 МГц, поэтому мне приходится использовать регистры напрямую. Тогда у меня есть выходная частота 1/2 (счетчик 2) входной и 1/4 входной частоты, и я хотел бы иметь выходную частоту 4/5 входной (деление на счетчик 1,25). Итак, нужны ли мне 3 выходных контакта: 1 для счета двоек, один для четверок и один для пятерок? Или это можно как-то сделать, используя 1 входной контакт и 1 выходной контакт с входной частотой 4/5?

Я пытался изменить код, но не могу сказать, как пропустить каждый пятый цикл. Допустим, в цепочке этих счетчиков я могу получить частоту от 1 000 000 Гц: 1000000 Гц - 800000 Гц - 640000 Гц - 512000 Гц - 409600 Гц - 327680 Гц - 2262144 Гц поэтому вход = степень десяти, затем выход = степень двойки Мой вопрос: насколько высокой может быть максимальная входная частота для этого кода? и можете ли вы помочь мне изменить этот код?

/*
 * From one square wave generate 3 waves 1/2, 1/4 and 4/5 of the original frequency.
 *
 * Original sketch tried to be modified from here:
 *
 * https://arduino.stackexchange.com/questions/63202
 *                               _   _   _   _   _   _   _   _   _   _
 *  input:  digital 13 = PB7    / \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/  1 000 000 Hz
 *                              R1F0R1F0R1F0R1F0R1F0R1F0R1F0R1F0R1F0R1F0R
 *                               ___     ___     ___     ___     ___
 *  output: digital 10 = PB4    /   \___/   \___/   \___/   \___/   \___/    500 000 Hz
 *                              R 1 F 0 R 1 F 0 R 1 F 0 R 1 F 0 R 1 F 0 R  
 *                               _______         _______         _______
 *  output: digital 11 = PB5    /       \_______/       \_______/       \    250 000 Hz
 *                              R   1   F   0   R   1   F   0   R   1   F
 *                               _   _   _   _       _   _   _   _   
 *  output: digital 12 = PB6    / \_/ \_/ \_/ \_____/ \_/ \_/ \_/ \_____/    800 000 Hz
 *                              R1F0R1F0R1F0R1F00000R1F0R1F0R1F0R1F00000R
 */

int main(void)
{
    DDRB = _BV(PB4) | _BV(PB5) | _BV(PB6) | ~_BV(PB7);  // PB4 PB5 PB6 как выходы и PB7 как вход
    for (;;) {
        loop_until_bit_is_clear(PINB, PB7);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB7);
        PORTB |= _BV(PB4);                              // поднимаем PB4

        loop_until_bit_is_clear(PINB, PB4);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB4);
        PORTB |= _BV(PB5);                              // повышение PB5

        loop_until_bit_is_clear(PINB, PB5);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB5);
        PORTB |= _BV(PB6);                              // повышение PB6

        loop_until_bit_is_clear(PINB, PB7);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB7);
        PORTB &= ~_BV(PB4);                             // падение PB4

        loop_until_bit_is_clear(PINB, PB7);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB7);
        PORTB |= _BV(PB4);                              // поднимаем PB4

        loop_until_bit_is_clear(PINB, PB4);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB4);
        PORTB |= ~_BV(PB5);                             // падение PB5

        loop_until_bit_is_clear(PINB, PB7);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB7);
        PORTB &= ~_BV(PB4);                             // падение PB4

        loop_until_bit_is_clear(PINB, PB7);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB7);
        PORTB |= _BV(PB4);                              // поднимаем PB4

        loop_until_bit_is_clear(PINB, PB4);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB4);
        PORTB |= _BV(PB5);                              // повышение PB5

        loop_until_bit_is_clear(PINB, PB5);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB5);
        PORTB |= ~_BV(PB6);                             // падение PB6

        loop_until_bit_is_clear(PINB, PB7);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB7);
        PORTB &= ~_BV(PB4);                             // падение PB4

        loop_until_bit_is_clear(PINB, PB7);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB7);
        PORTB |= _BV(PB4);                              // поднимаем PB4

        loop_until_bit_is_clear(PINB, PB4);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB4);
        PORTB |= ~_BV(PB5);                             // падение PB5

        loop_until_bit_is_clear(PINB, PB7);             // ждем увеличения входных данных
        loop_until_bit_is_set(PINB, PB7);
        PORTB &= ~_BV(PB4);                             // падение PB4
    }
}

Лично Ник Гамон: Я видел тебя здесь много раз. какая честь. Мне нужны исходные часы для многопланетных часов, без дробей. Наименьшее общее кратное для периодов секунды для: Земли, Марса, Титана.

Если я буду точно сохранять соотношение между планетами, то даже если земные часы, использующие резонатор Arduino, будут смещаться на несколько десятков секунд в день, часы Марса и часы Титана будут смещаться на такое же количество времени.

Для меня это не имеет значения, потому что, если я остановлю часы и подожду, все три планеты снова выровняются. Но если бы я не сохранял точное соотношение между планетами, например, Земля будет дрейфовать 30 секунд в день, Марс будет дрейфовать 31 секунду в день, а Титан будет дрейфовать 29 секунд в день - это зависит от того, насколько точное приближение я возьму. Таким образом, если остановить часы на 30 секунд, чтобы установить их правильно, Земля вернется к 0 секундам, но Титан будет отставать на 1 секунду, а Марс будет на 1 секунду раньше. Я бы не стал исправлять все три, просто остановив часы. Мне пришлось бы останавливать часы 3 раза индивидуально (по одному разу для каждой планеты, иначе ошибка для 2-х оставшихся планет со временем накопилась бы, даже если поправить Землю) И поверьте мне, вычислить марсианское время непросто (хорошо, потому что приложение НАСА уже существует), но время Титана у меня есть только в Excel, и его мне приходится пересчитывать при установке часов.

Периоды для Земли: 1 с, Марса 1,027 491 251 7 с, Титана 0,998 068 437 5 с,

Очевидно, что математика Arduino не точна максимум до 10 десятичных знаков. 32 байта, что составляет 0,000 000 000 2 и что-то... это от 2 до -32-й степени.

Параметры наименьшего общего кратного:
Земля:Марс = 291/299, Земля:Титан = 3624/3617
Земля:Марс:Титан = целое число:целое:1 054 584 (то есть 291 x 3624)

Итак, первый вариант - генерировать 1 054 584 Гц (я называю это золотым мегагерцем), что немного больше, чем 15 тактовых циклов Arduino =, если быть точным, 15 и 16 циклов должны чередоваться с некоторым правилом скачкообразного цикла (аналогично наше правило високосного года), чтобы получить эту частоту.

Найдите другую десятичную частоту, немного отличающуюся.

Вариант 1:
Земля:Марс = 812993/800000, а Титан может быть на 1/4 цикла меньше, поэтому 800 кГц

Вариант 2:
Земля:Марс:Титан = целое число:целое:3200000, поэтому 3,2 МГц (5 тактовых циклов) и Марс, Титан и Земля лучше совмещены,

Вариант 3: Частота 9600000 Гц (точно 5 тактов на Arduino Zero 48 МГц или 10 циклов на разогнанном Arduino Due 96 МГц) и идеальное выравнивание планет.

Эти параметры должны иметь 24-битный счетчик, до 16777216, а не только 16 байт. Если я не буду точно соблюдать соотношение, часы будут двигаться с разной скоростью, и поправить часы, чтобы остановить все три часа одновременно, будет недостаточно.

Каждый из них придется исправлять индивидуально (хотя на Земле будет самая большая ошибка из-за резонатора Arduino, некоторые остаточные ошибки из-за неточных соотношений будут накапливаться с течением времени, и время от времени придется останавливать дополнительные 2 тактовых генератора). и устанавливается индивидуально)


Кроме того, мне хотелось бы иметь что-то вроде календаря для каждой планеты. Какой самый быстрый и короткий способ его настроить? Земля: 365,2425 дней, Марс 668,592 дней и Титан 673,54388 дней. Для Земли у нас есть 365 плюс каждый 4-й прыжок, но не каждый 100-й прыжок, а каждый 400-й прыжок. Дни в месяце 31,28/29,31,30,31,30,31,31,30,31,30,31. Для Марса мы бы имели: 56,56,55,56,56,55,56,56,55,56,56,55/56, а также каждый нечетный и каждый 10-й прыжок (это 0,6), но не каждые 100 (это 0,59), но каждые 500 прыжков (это 0,592). Високосным месяцем будет 12-й месяц. Для Титана у нас будет 56,56,56,56,56,57,56,56,56,56,56,56/57, а также каждый нечетный и каждый 20-й прыжок (это 0,55), но не каждый 160-й прыжок ( это 0,54388). Кроме того, упомянутая продолжительность составляет не 1 день Титана, а 1/16 дня Титана, да, день Титана длится почти 16 дней. Итак, я хотел бы иметь что-то вроде «дней в сутках»; = 8-дневная неделя из 24 часов 60 минут 60 секунд из 0,98 вышеупомянутых земных секунд, а также неделя до полудня и после полудня. Восьмой день будет называться «День Земли и будет проходить между воскресеньем и понедельником». На Марсе у нас было бы 7 дней в неделе, как на Земле, и аналогичным образом: понедельник 1-го, вторник 2-го.... Но для Титана у нас было бы 16 раз 1-го числа: утро понедельника 1-го, утро вторника 1-го... утра. 1-го воскресенья, 1-го дня Земли, 1-го дня понедельника, 1-го понедельника, 1-го вечера вторника, ... 1-го вечера воскресенья, 1-го дня Земли, а затем 16 раз 2-го, ... снова с утра понедельника до полудня земного дня. Так мы можем разделить ужасно длинные 16-дневные сутки на недели и дни. есть ли у нас какая-нибудь разумная функция, такая как RTC, где я ввожу/вывожу (год, месяц, день, неделю, день недели, час, минуту, секунду), когда я ввожу/вывожу "unix-время" для Земли, Марса и Титана на основе разной длины секунд? У нас будут Unix Earth, Unix Mars и Unix Titan. Очевидно, что для Земли и Марса день недели и дата будут меняться одновременно, и нам не нужна «неделя». для Земли и Марса (это было бы отключено), а для Титана есть 8 дней недели, затем 2 недели, а затем 1 титановый день (длиной 2 недели), так что да, 16 дней в день и 673,54 из них, это почти 30 лет в году. формулы между Землей, Марсом и Титаном Unix-времени еще должны быть готовы, но как разбить это беззнаковое длинное Unix-время для каждой планеты на компоненты и еще один (недельный) компонент для Титана, день титана ужасно длинный, сделайте будний день (и неделя) здесь время, не день, а день в дне, и неделя в дне.


Ник Гамон, не хочу показаться неуважительным, это мой самый первый вопрос после нескольких лет чтения этих форумов.

В Arduino Uno r4 действительно существует возможность напрямую генерировать прерывания длительностью 1/256 секунды, поскольку для этого существует специальная библиотека, использующая встроенные часы RTC, которые уже являются частью этого Arduino.

К сожалению, хороший круглый кратный для Земли, Марса и Титана будет равен 3,2 миллиона Гц. Поскольку Arduino 4 представляет собой 32-битный процессор с частотой 48 МГц, он выполняет математические операции до 32 бит за один или два тактовых цикла. и 3,2 миллиона Гц будут ровно 15 тактовыми циклами, однако для прерывания это не так уж много циклов. Но 256 Гц — это вполне достаточно для 32-битного процессора с частотой 48 МГц, верно? Я не уверен, насколько точны эти часы RTC, нужно выяснить, как только я их получу. Этот Arduino uno R4 появился в магазине всего несколько дней назад и он совершенно новый и необычный. (32 бит, 48 МГц)

1/256 секунды — это 12500/3200000 секунды. так что, слава богу, 3,2 миллиона делятся на 256 без дроби.

Прилагаю пример документации Arduino r4:

https://docs.arduino.cc/tutorials/uno-r4-wifi/rtc #unix

#include "RTC.h"

const int LED_ON_INTERRUPT  = 22;

void setup(){
  RTC.begin();
  if (!RTC.setPeriodicCallback(periodic_cbk, Period::ONCE_EVERY_2_SEC)) {
    Serial.println("ERROR: periodic callback not set");
  }
}

void loop() {
}

void periodic_cbk() {
  static bool clb_st = false;
  if(clb_st) {
    digitalWrite(LED_ON_INTERRUPT,HIGH);
  }
  else {
    digitalWrite(LED_ON_INTERRUPT,LOW);
  }
  clb_st = !clb_st;
 
  Serial.println("PERIODIC INTERRUPT");
}

Период можно указать с помощью следующих перечислений:

ONCE_EVERY_2_SEC
ONCE_EVERY_1_SEC
N2_TIMES_EVERY_SEC
N4_TIMES_EVERY_SEC
N8_TIMES_EVERY_SEC
N16_TIMES_EVERY_SEC
N32_TIMES_EVERY_SEC
N64_TIMES_EVERY_SEC
N128_TIMES_EVERY_SEC
N256_TIMES_EVERY_SEC

Сейчас я также бьюсь над тем, как включить этот календарь из времени Unix, чтобы разбить его на отдельные компоненты для Земли, Марса и Титана. Время un ix началось 01.01.1970 00:00:00, unix Mars началось 01.01.192 00:00:00, а Titan Unix началось 01.01.13 в понедельник 00:00:00, но я бы хотел, чтобы первые годы можно было регулировать, потому что. В конечном итоге он выйдет за пределы диапазона через 136 земных лет, 72 марсианских года и примерно 4,6 лет Титана, поэтому мы могли бы повторно использовать его, сдвинув начальный год, и, кроме того, я хотел бы, чтобы он был действительным по крайней мере до 2323 года, поэтому только с разрешением 4 секунды, поскольку 300 лет имеют менее 2-х 32-х 4-секундных интервалов. Но от этого календаря у меня болит голова. Я видел библиотеку RTC, но не могу просто изменить числа, чтобы получить календарь Марса и Титана.

Причина, по которой я хотел бы это сделать, заключается в том, что в какой-то момент в будущем начнется человеческая колонизация Марса, а в более отдаленном будущем начнется человеческая колонизация Титана (спутника Сатурна) (уже есть Вертолет с ядерным двигателем, который будет работать в атмосфере Титана с высокой плотностью, низкой гравитацией и очень холодной средой, в 2034 году (дата уже одобрена НАСА, он взлетит в 2027 году, но, как вы можете предположить, полет займет 7 лет, чтобы охватить один миллиард миль, или 1,6 миллиарда километров до Сатурна), и план атомной подводной лодки, которая будет плавать в морях жидкого метана, не знаю когда, но концепция уже существует, ее температура близка к температуре жидкого азота, жидкий метан имеет температуру минус 180 градусов по Цельсию или около минус 300 градусов по Фаренгейту, поэтому отопление и изоляция должны быть идеальными) и для каждой планеты нам нужен другой календарь


Если бы мне нужно было построить ФАПЧ (фазовую автоподстройку частоты), то мне нужно было бы перейти от 32768 Гц ровно до 3,2 МГц (точно так же, как и кристалл с частотой 32768 Гц), на 5 раз умножив его на 2,5 то есть (умножить на 5 и разделить на 2). Лол, я не мог 5 раз умножить на пять, потому что я получил бы 102,4 МГц (а затем разделил бы их 5 раз на 2), и даже Arduino не была достаточно быстрой, чтобы поймать это прерывание. Но чистая логика TTL способна это сделать (при условии, что она может умножать на дроби, то есть 2,5 в 5-й степени)


Привет, ребята, ЖК-клавиатура Shield 1602 A совместима с какой библиотекой и какой Arduino? как должны быть установлены пины? Я просто не могу заставить это работать

, 👍0

Обсуждение

1. Какой Arduino вы используете? 2. Вы можете с помощью аппаратного таймера преобразовать 1 МГц в 64 Гц (т.е. разделить на 15625). Будет ли для вас такая частота приемлемой?, @Edgar Bonet

Непонятно, что вы пытаетесь сделать. Вы пытаетесь создать часы, которые тикают каждую секунду, учитывая тактовую частоту 1 МГц? Или вы пытаетесь измерить какой-то неизвестный входной сигнал и сообщить о его частоте?, @Nick Gammon

Если бы мне пришлось пойти этим путем, я бы, вероятно, начал считать дроби и иногда увеличивал период на единицу (когда он превышает десятичную точку). Например. 16 МГц/488,28125 = 32768 -> дробь += 28125; если (фракт > 100000) {фракт -= 100000ul; период = 489; } Еще {период = 488; }, @KIIV

@Питер Спасибо за комплимент. Ваш «ответ» на самом деле является вспомогательным материалом для вашего вопроса, поэтому я с уважением добавил его к вашему вопросу в качестве дополнительной информации., @Nick Gammon

Спасибо, Ник... Ну, я здесь много лет... и никогда не разговаривал с тобой лично. Знаете ли вы, где на Github я могу увидеть библиотеку RTC для Arduino Uno R4, которая способна генерировать прерывания 1/256 с? Я хотел бы посмотреть, смогу ли я каким-то образом получить оттуда прерывания 1/32768 с, если это возможно, поэтому я хотел бы увидеть ту конкретную библиотеку RTC для Arduino Uno R4, которая встроена там, поэтому ее не нужно устанавливать. Но прежде чем я получу это, я хотел бы увидеть эту библиотеку, @Peter

Почему вам особенно нужно прерывание 1/32768? Есть ли у какой-либо из планет период, кратный этому периоду?, @Nick Gammon

К сожалению, нет, хорошее приближение — 1/3,2 миллионной секунды., @Peter

Я до сих пор не совсем понимаю, что вы пытаетесь сделать. Вы что-то строите, это очевидно. Расскажи мне о части X. Забудьте о фазовой автоподстройке частоты, логике TTL, умножении на 5 и делении на 2, 48 МГц, 32 бита — все это Y-часть проблемы. Давайте представим, что вы создали этот гаджет, и друг, не разбирающийся в технических вопросах, спрашивает: «Что он делает?». Что ты им скажешь? Сообщает ли он вам положение всех планет в данный момент? Или, может быть, и луны? Предсказывает ли оно приливы? Я вам говорю, когда на Юпитере восходит солнце? Вот что я хочу знать., @Nick Gammon

Сосредоточение внимания на «точных» числах (32768 Гц, 2,5^5...), вероятно, не принесет пользы. Отношение земной секунды к секунде другой планеты не совсем рациональное (отношение двух точных целых чисел). Вот почему я предлагаю вам вместо этого рассуждать в терминах _рациональных приближений_., @Edgar Bonet

что я пытаюсь сделать: в общем, запускаю 3 разных часа и 3 разных календаря (с использованием 3 разных правил длины месяцев и 3 разных правил високосного года), используя 3 разные длины секунд), не усложняя логику. Итак, в будущем, когда несколько других планет будут колонизированы, я могу просто добавить еще один календарь-часы. Например, Венера. Да, он показывает время, дату и год на Земле, Марсе и Титане (крупнейшем спутнике Сатурна)., @Peter

@Эдгар Боне Мне нравится число 3200 в коде, действительно, 3,2 миллиона — это наименьшее общее кратное всех из них, то есть 3200 тактов в миллисекунду., @Peter

*3 разных календаря... с использованием 3-х разной длины секунд* - «Секунда» имеет [формальное определение](https://en.wikipedia.org/wiki/Second). «Второй [...] определяется путем принятия фиксированного числового значения частоты цезия, ΔνCs, невозмущенной частоты сверхтонкого перехода в основное состояние атома цезия 133, равной 9192631770, если выразить d в единицах Гц, что равен s−1». Однако я уверен, что вы можете преобразовать одну секунду в другую (что бы это ни значило) простым умножением., @Nick Gammon

Второе может иметь определение, но оно будет бесполезным на Марсе или Титане. В противном случае нам пришлось бы иметь часы, которые могли бы сбрасываться в разное время: на Марсе: 24:39:35.244147 и на Титане 23:57:13.113. Хотели бы они иметь такие часы? я так не думаю. К сожалению, с календарем мы ничего сделать не можем, так как количество дней в году — это факт, и его нельзя изменить., @Peter


2 ответа


0

То, что вы предлагаете, слишком сложно. Используйте внутренние таймеры, скажем, таймер 0, 1 или 2 на Atmega328P (Arduino Uno) с прескалером 64 (что дает вам 4 мкс на такт таймера), а затем досчитайте до 250, что даст вам период 1 мс.< /п>

Таймер можно настроить на переключение выходного контакта, предоставляя вам эту частоту в качестве выходного сигнала. Если вы выполняете переключение, возможно, вы захотите уменьшить вдвое то, что вы считаете (один счет для переднего края и второй счет для заднего края). Или используйте режим ШИМ с коэффициентом заполнения 50 %.


Из комментария к другому ответу:

Я планирую приобрести Arduino Uno R4, которая способна генерировать самые быстрые прерывания 1/256 с, используя встроенные часы RTC

Вовсе нет. Таймеры Uno можно настроить на прерывание практически с любой скоростью (ограничением является скорость выполнения процедуры прерывания).

Программное обеспечение IDE настраивает таймер 0 на прерывание каждые 1,024 мс, что намного чаще, чем 1/256 с. Однако вы можете перенастроить его, как и другие таймеры, на прерывание практически с любым интервалом в пределах разумного.

Дополнительную информацию см. на моей странице о таймерах.

Я мог бы легко дать вам код, который будет генерировать прерывание каждые 1/256 с или даже 1/32768 с, но я не понимаю, как эти довольно необычные с точки зрения планет числа могли бы вам помочь.

р>

На самом деле, с вашей точки зрения, возможно, лучше просто отслеживать прошедшее время и производить на его основе расчеты. Например, millis() сообщает вам время, прошедшее с момента запуска, в миллисекундах и будет повторяться каждые 49,710 дней. Или micros(), который сообщает вам прошедшее время в микросекундах и будет повторяться каждые 71,58 минуты.

Теперь вам в любом случае придется обрабатывать перенос, так что в этом нет ничего страшного.

Мне кажется, что ваши расчеты положения планет будут заключаться в том, чтобы просто взять текущее время (например, с помощью millis()), а затем применить некоторую арифметику для каждой планеты, чтобы определить, где так и должно быть.

Ваше желание получать прерывания и ваше внимание к 32768 как к интервалу прерываний кажутся мне проблемой XY. Знаете, как говорят: «Если единственный инструмент, который у тебя есть, — это молоток, все будет выглядеть как гвоздь». Что ж, здесь у вас больше инструментов, чем молоток.

,

4

Ваш вопрос — прекрасный пример проблемы XY: вы спрашиваете что-то, что имеет мало общего с вашей реальной проблемой, а скорее о вашем ошибочном представлении о решении. Считаем секунды Марса или Титана секунды — это простая проблема. Деление частоты 1 МГц сигнал последовательными степенями 1,25 представляет собой сложную проблему. Есть немного ценность в превращении простой проблемы в сложную.

Я предлагаю решение, основанное на алгоритме Брезенхэма для рисование наклонных линий:

  • настройте таймер для периодического прерывания вашей программы, с периодом короче вашей самой короткой соответствующей секунды.
  • вычислите отношение секунды вашей любимой планеты к прерыванию период
  • приблизить это соотношение рациональным числом p/q

В процедуре обслуживания прерываний:

  • увеличить счетчик на q
  • когда счетчик достигнет p, уменьшите его на p и заметьте, что один секунда прошла.

Ленивый способ получения периодического прерывания — просто включить Прерывание TIMER0_COMPA. Таймер 0 уже настроен Ядро Arduino отсчитывает полный цикл каждые 1024 мкс. Возможно, вы захотите установите OCR0A примерно на 128, чтобы предотвратить переполнение прерывание (используется Arduino для синхронизации) и ваше прерывание от получения слишком близко.

Для Земли это соотношение

1 с / 1024 мкс = 1 000 000 / 1024 = 976,5625 = 15 625 / 16

Для Марса и Титана их можно аппроксимировать 22 075/22 и 33 139/34. соответственно, с точностью до долей ppm.

Вот процедура обработки прерывания:

// Подсчет секунд, прошедших на каждой планете.
volatile uint32_t earth_secs, mars_secs, titan_secs;

// Выполняется каждые 1024 мкс по прерыванию таймера.
ISR(TIMER0_COMPA_vect) {
    static uint16_t earth_ticks, mars_ticks, titan_ticks;
    earth_ticks += 16;
    if (earth_ticks >= 15625) {
        earth_ticks -= 15625;
        earth_secs++;
    }
    mars_ticks += 22;
    if (mars_ticks >= 22075) {
        mars_ticks -= 22075;
        mars_secs++;
    }
    titan_ticks += 34;
    if (titan_ticks >= 33139) {
        titan_ticks -= 33139;
        titan_secs++;
    }
}

Обратите внимание, что вы можете получить более точное приближение секунд Марса и Титана. используя рациональные числа с большими p и q, но тогда вы бы придется выполнять 32-битную арифметику в ISR. Вы также можете настроить другой таймер для доставки прерывания с более длительным периодом: вы бы тогда вы сможете добиться большей точности с помощью 16-битной арифметики, цена повышенного джиттера.


Дополнение: вот вариант этой идеи, в котором вместо этого используется millis(). прерываний. Конечно, Ник Гэммон прав: вам не нужно прерывания для часов, которые обновляют свое отображение несколько раз в секунду. Было немного проще написать код, основанный на прерываниях, поскольку время между последовательными вызовами функции — известная константа.

Учитывая, что вы собираетесь использовать 32-битный процессор, я написал это с помощью 32-битная арифметика. Соотношения должны быть немного точнее.

uint32_t earth_seconds, mars_seconds, titan_seconds;

void update_planet_times() {
    // Вычисляем количество миллисекунд, прошедших с момента последнего обновления.
    static uint32_t last_update;
    uint32_t now = millis();
    uint32_t elapsed_millis = now - last_update;
    last_update = now;

    // Обновляем земное время. 1 земная секунда = 1000/1 мс.
    static uint32_t earth_ticks;
    earth_ticks += elapsed_millis * 1;
    uint32_t elapsed_earth_seconds = elapsed_earth_ticks / 1000;
    earth_ticks -= elapsed_earth_seconds * 1000;
    earth_seconds += elapsed_earth_seconds;

    // Обновляем марсианское время. 1 марсианская секунда = 763426/743 мс.
    static uint32_t mars_ticks;
    mars_ticks += elapsed_millis * 743;
    uint32_t elapsed_mars_seconds = elapsed_mars_ticks / 763426;
    mars_ticks -= elapsed_mars_seconds * 763426;
    mars_seconds += elapsed_mars_seconds;

    // Обновляем время Титана. 1 Титановая секунда = 3193819/3200 мс.
    static uint32_t titan_ticks;
    titan_ticks += elapsed_millis * 3200;
    uint32_t elapsed_titan_seconds = elapsed_titan_ticks / 3193819;
    titan_ticks -= elapsed_titan_seconds * 3193819;
    titan_seconds += elapsed_titan_seconds;
}

Обратите внимание, что использование этого метода для Земли может показаться излишним: один может считать секунды, просто вычисляя millis()/1000. Это, однако, произойдет сбой, если millis() перейдет через 49,7 дней. Код выше невосприимчив к этому перевороту и должен надежно отсчитывать земные секунды для следующие 136,1 года.

,

Да, спасибо, и я планирую приобрести Arduino Uno R4, которая способна генерировать самые быстрые прерывания 1/256 с, используя встроенные часы RTC, так что это тоже, вероятно, поможет. просто цифры P,Q будут другими, верно?, @Peter

@Питер: Верно. Как указано в моем ответе, вам нужно вычислить отношение секунды планеты к периоду прерывания, а затем аппроксимировать его рациональным числом. В этом разделе Википедии [Наилучшие рациональные приближения](https://en.wikipedia.org/wiki/Continued_fraction#Best_rational_approximations) представлена техника вычисления рационального числа p/q., @Edgar Bonet

@Peter Что касается комментария 1/256 с, пожалуйста, смотрите мой расширенный ответ., @Nick Gammon

@Ник, я видел ответ, однако, если у Uno R4 есть часы RTC, эти часы будут намного точнее, чем миллис, который, вероятно, берет часы из резонатора (или чего-то еще, подключенного к микропроцессору Uno R4), не уверен, это мое предполагать., @Peter

@Эдгар, поскольку Uno R4 имеет встроенные часы RTC, я думаю, мне следует использовать преимущество, чтобы использовать прерывание 1/256 с от более точных часов RTC. Я не думаю, что миллисы подключены к этим часам RTC, они просто подключены к часам 48 МГц, используя менее точный резонатор или что-то еще, прикрепленное к этому чипу в качестве часов., @Peter

Я не знаком с Uno R4, поэтому не могу посоветовать, как его использовать. Возможно, у Эдгара он есть., @Nick Gammon

Конечно, я готов попробовать оба подхода, возможно, у резонатора будет меньший допуск, чем у предыдущих Arduino, которые у меня были. посмотрим, @Peter