RTC Millisecondes

Bonjour à tous,

Je viens vers vous parce que je rencontre une difficulté sur mon petit projet. Une carte Arduino communicante en IEC104. En faite Je reçois une trame avec un Horodatage au format CP56Time2a sur les 7 derniers octets de la trame. Le décodage de cette trame se passe très bien pour après mettre à l'heure ma RTC. Je récupère les millisecondes de la trame et je divise par 1000 pour avoir les secondes et pouvoir mettre à l'heure ma RTC vu quelle ne gère pas les millisecondes. Ma question: est ce que c'est possible de garder à jour le résultat de cette division et l'incrémenter pour pouvoir après utiliser l'horodatage de la RTC en la rajoutant aux seconde pour renvoyer des trames en CP56Time2a avec les secondes et les millisecondes à jour. Je ne sais pas si j'étais claire. Merci d'avance

le reste de la division s'appelle le modulo qu'on obtient avec l'opérateur noté %

unsigned long chrono = 21758ul;                // votre temps ms
unsigned long secondes = chrono / 1000ul;      // ce sera 21
unsigned long millisecondes = chrono % 1000ul; // les ms, ce sera 758

on peut aussi l'obtenir par soustraction si on ne veut pas faire le modulo

unsigned long chrono = 21758;                            // votre temps ms
unsigned long secondes = chrono / 1000ul;                // ce sera 21
unsigned long millisecondes = chrono - secondes*1000ul ; // les ms, ce sera 758

Merci pour votre réponse. Je précise que le décodage et la récupération des millisecondes se font sans problème, ci-après ma démarche: `
J'ai créer une structure:

struct CP56Time2a {
  uint16_t milliseconds;
  uint8_t minute: 6;
  uint8_t hour: 5;
  uint8_t day: 5;
  uint8_t dow: 3;
  uint8_t month: 4;
  uint8_t year: 7;
};
CP56Time2a heureEtDate;<CODE/>

Je décode ma Date et heure reçu dans ma trame "data":

void decodeCP56Time2a(CP56Time2a& cp56Time, uint8_t* data, int length) {
    cp56Time.milliseconds = (data[16] << 8) | data[15];
    cp56Time.minute = (data[17] & 0x3F);
    cp56Time.hour = (data[18] & 0x1F);
    cp56Time.day = (data[19] & 0x1F);
    cp56Time.dow = (data[19] & 0xE0) >> 5;  // Lire les bits correspondants à dow
    cp56Time.month = (data[20] & 0x0F);
    cp56Time.year = (data[21] & 0x7F);
    heureEtDate.milliseconds = cp56Time.milliseconds;
} 

Après je met ma RTC à l'heure comme le suivant:

void mettreAjourDS1307(CP56Time2a& cp56Time) {
  // Vérifier si l'horloge RTC est disponible
  if (!rtc.begin()) {
    Serial.println("Erreur 03 : Défaut horloge RTC");
    while (1);
  }
  // Créer un objet DateTime avec les données décodées
  DateTime now(cp56Time.year, cp56Time.month, cp56Time.day, cp56Time.hour, cp56Time.minute, cp56Time.milliseconds / 1000);
  // Mettre à jour l'horloge DS1307
  rtc.adjust(now);
  Serial.println("Horloge mise à jour avec succès !");
}

Et ma question principale, c'est comment garder mes millisecondes à jour pour pouvoir après l'utiliser lorsque j'enverrai une trame contenant l'horodatage à jour avec les millisecondes ma trame IEC104 est la suivante:

void TSD1_SEND_TIME()
{
  DateTime rtcTime = rtc.now(); // Obtenir la date et l'heure actuelle de la RTC

  iec104SPI1[0] = 104; //Caractère de début 0x68
  iec104SPI1[1] = 21; //APDU length = APCI (4) + ASDU (10), M_DP_TB_1
  iec104SPI1[2] = (byte)(txcnt_NS << 1);
  iec104SPI1[3] = (byte)(txcnt_NS >> 7);
  iec104SPI1[4] = (byte)(rxcnt_NR << 1);
  iec104SPI1[5] = (byte)(rxcnt_NR >> 7);
  iec104SPI1[6] = 31; //type 4, M_DP_TB_1
  iec104SPI1[7] = 1; //no. of objects
  iec104SPI1[8] = cot; //CAUSE of TRansmission
  iec104SPI1[9] = ORG; //OA
  iec104SPI1[10] = (byte)(ca); // CA
  iec104SPI1[11] = (byte)(ca >> 8); // CA
  iec104SPI1[12] = (byte)(IOA_DP1); //IOA ADRESSE
  iec104SPI1[13] = (byte)(IOA_DP1 >> 8);//IOA ADRESSE
  iec104SPI1[14] = (byte)(IOA_DP1 >> 16); //IOA ADRESSE*/
  iec104SPI1[16] = ??????;
  iec104SPI1[17] = ??????; // Octet de poids faible pour les millisecondes
  iec104SPI1[18] = rtcTime.minute();
  iec104SPI1[19] = rtcTime.hour();
  // Utiliser l'octet pour stocker à la fois le jour et le DOW (Day of Week)
  iec104SPI1[20] = ((rtcTime.dayOfWeek() << 5) | rtcTime.day());
  iec104SPI1[21] = rtcTime.month();
  iec104SPI1[22] = rtcTime.year() % 100; // Utiliser les deux derniers chiffres de l'année
  authorizedClient.write(iec104SPI1, 23);
  trameIndex = iec104SPI1[1] + 2;
  afficherTrame_TX();
  Serial.print(">E I(NS:"); Serial.print(txcnt_NS); Serial.print(","); Serial.print("NR:"); Serial.print(rxcnt_NR); Serial.print(")");
  Serial.print(" Changement Etat Télécomande Daté (M_DP_TA_1)"); imprimer_cot (cot);
  if (digitalRead(entrees[6]) == HIGH && digitalRead(entrees[7]) == LOW) {
    Serial.print(ORGANE1); Serial.print(" : ETAT OUVERT  ");
  } else if (digitalRead(entrees[6]) == LOW && digitalRead(entrees[7]) == HIGH) {
    Serial.print(ORGANE1); Serial.print(" : ETAT FERME  ");
  } else {
    Serial.print(ORGANE1); Serial.print(" : ETAT INDEFINI ");
  }
  txcnt_NS++;
}

Et pour information, suivant la norme le format CP56Time2a est organisé comme cela:
TYPE T_CP56Time2a :
STRUCT
Milliseconds : WORD;
IVResMinute : BYTE;
SURes2Hour : BYTE;
DOWDay : BYTE;
Res3Month : BYTE;
Res4Year : BYTE;
END_STRUCT
END_TYPE

Milliseconds: Milliseconds := <0..59999>.
IVResMinute: Bit 7 = IV := <0=valid, 1=invalid time>, bit 6 = res (reserved) := <0>, bit 0..5 = minute := <0..59>.
SURes2Hour: Bit 7 = SU := <0=standard time, 1=summer time>, bits 5..6 = res2 (reserved) := <0>, bits 0..4 = hour := <0..23>.
DOWDay : Bits 5..7 = DOW (day of the week) := <0=not used, 1=Monday..7=Sunday>, bits 0..4 = day (day of the month) := <1..31>.
Res3Month: Bits 4..7 = res3 (reserved) := <0>, bits 0..3 = month := <1..12>.
Res4Year: Bit 7 = res4 (reserved) := <0>, bits 0..6 = year := <0..99>.

Merci beaucoup pour vos retour.

Lors de la réception mettez dans une variable globale uint16_t deltaMilliseconds; la valeur des ms

void mettreAjourDS1307(CP56Time2a& cp56Time) {
  // Vérifier si l'horloge RTC est disponible
  if (!rtc.begin()) {
    Serial.println("Erreur 03 : Défaut horloge RTC");
    while (1);
  }
  // Créer un objet DateTime avec les données décodées
  DateTime now(cp56Time.year, cp56Time.month, cp56Time.day, cp56Time.hour, cp56Time.minute, cp56Time.milliseconds / 1000);
  // mémoriser le delta manquant
  deltaMilliseconds  = cp56Time.milliseconds % 1000u; // les ms (reste de la division par 1000)
  // Mettre à jour l'horloge DS1307
  rtc.adjust(now);
  Serial.println("Horloge mise à jour avec succès !");
}

ensuite vous voulez remplir

il faut rebâtir la valeur secondes avec le delta sur 2 octets

uint16_t ms = rtcTime.second()*1000u + deltaMilliseconds;

et ensuite aller cherche l'octet de poids fort et faible

  iec104SPI1[16] = (ms >> 8) & 0xFF;   // l'octet de poids fort (le masque est facultatif)
  iec104SPI1[17] = (ms & 0xFF);        // Octet de poids faible pour les millisecondes  (le masque est facultatif)

Merci beaucoup pour votre aide. Le seul problème que je vais rencontrer, c'est que la trame de synchronisation n'est envoyée du SCADA qu'une seule fois à la connexion à la carte. du coup le deltaMilliseconds il gardera toujours la valeur initial.

Merci

Dans l'absolu ce n'est pas trop grave. si votre RTC ne dérive pas, le delta devrait rester constant

si vous n'êtes pas à la ms près stockez uniquement les secondes dans le champ de la trame

  uint16_t ms = rtcTime.second()*1000u ; // on laisse tomber les ms
  iec104SPI1[16] = (ms >> 8) & 0xFF;     // l'octet de poids fort (le masque est facultatif)
  iec104SPI1[17] = (ms & 0xFF);          // Octet de poids faible pour les millisecondes  (le masque est facultatif)