ограничить длину сгенерированной временной метки из ESP32 с DS3231 до 13

Я использую ESP-WROOM-32 (Olimex ESP32-PoE) с DS3231. Я использовал патч из PR для RTClib, чтобы избежать переноса с DS3231.

Поскольку DS3231 RTC предоставляет временные метки эпохи Unix с точностью до нескольких секунд, я хочу объединить millis() с вышеупомянутыми временными метками, чтобы обеспечить точность в миллисекундах.

Это очень важно, поскольку я хочу хранить в InfluxDB информацию из узлов с точностью до мс. Для этого временные метки всегда должны состоять из 13 цифр.

код

#include <RTClib.h>
#include <Wire.h>

// Настройка PoE для платы Olimex PoE

#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT
#define ETH_PHY_POWER 12

// Контакты для I2C на плате Olimex PoE
#define I2C_SDA 13
#define I2C_SCL 16


RTC_DS3231 rtc;
RTC_Millis software_time;

void setup() {
  // поместите сюда свой код установки для однократного запуска:
  Wire.begin(I2C_SDA, I2C_SCL, 400000);
  Serial.begin(9600);
  if (!rtc.begin()) {
    Serial.println("No RTC Detected");
  }
  // корректируем время RTC
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  // настройка программного таймера
  software_time.adjust(rtc.now());

}

void loop() {
  // поместите сюда свой основной код для повторного запуска:
  DateTime rtc_now_time = rtc.now();
  DateTime software_now_time = software_time.now();
  Serial.println();
  Serial.print("RTC now: "); Serial.print(rtc_now_time.unixtime());
  Serial.println();
  Serial.print("millis: "); Serial.print(millis());
  delay(100);

}

Вывод

RTC now: 1538502183
millis: 28
RTC now: 1538502183
millis: 128
RTC now: 1538502183
millis: 228
RTC now: 1538502183
millis: 328
RTC now: 1538502183
millis: 428
RTC now: 1538502183
millis: 528
RTC now: 1538502183
millis: 628
RTC now: 1538502183
millis: 728
RTC now: 1538502183
millis: 828
RTC now: 1538502183
millis: 928
RTC now: 1538502184
millis: 1028

Я буду хранить временные метки в String, поэтому я подумал об объединении .unixtime() с millis(). Однако, поскольку я хочу, чтобы все мои временные метки имели фиксированную длину (13) с возрастающим значением миллис, это кажется трудным, потому что, как только число превышает 999, цифра увеличивается, увеличивая длину строки до 14.

Побочный эффект

если временные метки для мс не соответствуют длине 13, InfluxDB отклоняет передаваемые данные

Эпоха

Выходные данные, представленные выше, состоят из 10 цифр, что соответствует эпохе, начиная с 1970 года. Точность приведенных выше временных меток составляет секунды. Если кто-то хочет добавить к нему миллисекунды, нужно добавить после него еще 3 цифры. Если точность должна составлять микросекунды, она должна содержать 6 цифр и т. д. Вы можете проверить временные метки выше на [https://epochconverter.com]

Есть какие-нибудь предложения по решению этой проблемы?

, 👍0

Обсуждение

Объясните пожалуйста 13 цифр или дайте ссылку на формат. Это формат «1234567890123»? Как читаем текст с десятичным числом? Должно ли это быть количество миллисекунд с 1970 года? Эпоха = 1538498157, что составляет 10 цифр, это означает три дополнительные цифры для миллисекунд? Будет ли это работать, если вы сделаете три цифры миллисекунд нулевыми? Этот номер: https://currentmillis.com/?, @Jot

Да. это может работать, даже если миллисекунды равны нулю. к сожалению, rtc не обеспечивает точность в мс, поэтому я добавляю «миллис», который равен мс от начала контроллера., @Shan-Desai

Значит, обнуление их решит все проблемы? Это аналогичный вопрос: https://stackoverflow.com/questions/44644383/how-to-get-milliсекунд-разрешение-from-ds3231-rtc Вы можете выполнить millis() % 1000., @Jot

Я видел пост. Я просто не уверен, полностью ли я понял, как это обойти. Я могу попробовать millis() %1000, отправить информацию в influxdb и сообщить вам, работает ли она., @Shan-Desai

@Jot, ваше предложение millis() % 1000 работает. Influx анализирует временную метку в удобочитаемом RFC3339., @Shan-Desai

но он может за одну секунду выдать две временные метки в неправильном порядке, @Juraj

@Юрай, какое решение? Как добиться какой-то синхронизации? Возможно, установите частоту выходного сигнала sqw на 1 Гц и привяжите ее к прерыванию. В прерывании устанавливается предыдущий Миллис. Шан-Десаи, можешь ли ты подключить сигнал sqw к входу прерывания?, @Jot

@Jot Итак, я подключил вывод SQW RTC к выводу GPIO и, следуя [этому руководству](https://techtutorialsx.com/2017/09/30/esp32-arduino-external-interrupts/), установил SQW до настроек 1 кГц. Проблема в последовательном порте, i2c и прерывании все портят. значения временных меток не обновляются соответствующим образом, и последовательная печать обеспечивает одни и те же значения в течение длительного времени. Редко я вижу какие-либо изменения в значениях временных меток., @Shan-Desai


2 ответа


Лучший ответ:

1

Для получения миллисекундного разрешения от RTC, я думаю, единственный способ Жизнеспособным решением является синхронизация с выходным сигналом прямоугольной формы частотой 1 Гц, поскольку предложено Джотом в комментарии. Обратите внимание: поскольку вы считаете только секунды и миллисекунды, вас, вероятно, не волнуют часы, минуты, дни, месяцы и т. д. Таким образом, вы не будете использовать RTC для измерения времени: только для обеспечивая опорный сигнал частотой 1 Гц и, возможно, начальный временная метка при запуске программы.

Подключите вывод SQW DS3231 к входу вашего устройства с поддержкой прерываний. МКУ. Добавьте следующее в ваш setup():

pinMode(SQW_PIN, INPUT_PULLUP);
rtc.writeSqwPinMode(DS3231_SquareWave1Hz);
attachInterrupt(digitalPinToInterrupt(SQW_PIN), tick, FALLING);

Используйте процедуру прерывания, чтобы отслеживать общее количество секунд. (секунд, прошедших с эпохи Unix) и запишите значение micros() последнего тика:

volatile uint32_t seconds_since_epoch;
volatile uint32_t micros_on_tick;

void tick() {
    seconds_since_epoch++;
    micros_on_tick = micros();
}

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

uint64_t millis_since_epoch() {
    noInterrupts();
    uint32_t seconds = seconds_since_epoch;
    uint32_t microseconds = micros_on_tick;
    interrupts();
    uint32_t extra_micros = micros() - microseconds;
    uint16_t extra_millis = extra_micros / 1000;
    if (extra_millis > 999)
        extra_millis = 999;
    return (uint64_t) seconds * 1000 + extra_millis;
}

Значение, возвращаемое этой функцией, представляет собой желаемое 13-значное число, при условии, что Seconds_since_epoch был правильно инициализирован.

,

разве мне не понадобится RTC, чтобы предоставить мне начальное время эпохи в секундах?, @Shan-Desai

@Shan-Desai: Да, это самый простой способ инициализировать Seconds_since_epoch., @Edgar Bonet

Вы, сэр, легенда! Спасибо за это решение. Отлично работает. Понадобилась небольшая функция для преобразования uint64_t в String, но в остальном все работает как шарм., @Shan-Desai


0

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

unsigned long thisNowMillis;
uint32_t thisNow;

-

 uint32_t now = rtc_now_time.unixtime();
 if (now != thisNow) {
   thisNow = now;
   thisNowMillis = millis();
 }
 Serial.print("millis: "); Serial.print(millis() - thisNowMillis);

не проверено и не будет работать для подсчета интервалов между метками времени.

,

проверю это и свяжусь с вами, @Shan-Desai