FORUMAMONTRES › Forums › Forum de discussions sur les montres vintages et sujets techniques › Projet Arduino pour Horloger (amateur et peu fortuné)
- Ce sujet contient 80 réponses, 7 participants et a été mis à jour pour la dernière fois par
Torzio, le il y a 1 année et 10 mois.
-
AuteurMessages
-
17 décembre 2024 à 11h04 #420004805978
Torzio
MembreLorsque je rends une pendule à un client, le réglage est dégrossi. c’est à lui de le peaufiner.
La gravité « g », influe sur la période et n’est pas la même partout. Elle varie beaucoup en fonction de l’altitude du lieu. En théorie, la même pendule au rez-de-chaussée ne va pas régler de la même façon au 15 è étage.
La période varie aussi avec la pression atmosphérique et la température. Tout ceci en plus de l’isochronisme fragile du pendule, perturbé par les frottements constants de l’échappement, plus ou moins accentués en fonction de l’armage du ressort et de la qualité du rouage et ou de l’état d’usure, qui transmet la force irrégulièrement.
Je dis à mes client que ce n’est pas une pendule à quartz et qu’une variation d’environ 2 minutes par semaine est acceptable.Je reste persuadé que la solution la plus simple est de mesurer une trentaine d’oscillations du balancier, de faire la moyenne. De faire un petit tableur Excel, comme le mien, mais adapté aux nombres d’alternances/heures.
J’ai réalisé un tel montage, qui fonctionne parfaitement, mais il attend dans un carton que je trouve le temps et le courage de faire un capteur en fourche où le balancier va couper un rayon laser.
@+
JC17 décembre 2024 à 12h26 #420004805979Cadrature
Membre- Torzio a écrit:
- J’ai réalisé un tel montage, qui fonctionne parfaitement, mais il attend dans un carton que je trouve le temps et le courage de faire un capteur en fourche où le balancier va couper un rayon laser.
@+
JC
Pour ce montage, je peux aider.
C’est assez simple et le quartz monté sur l’Arduino suffit car il ne s’agit pas de relever des temps longs.Le capteur existe tout fait: LM393 Module de détection de vitesse
sinon, on peut monter une led laser et une photorésistance à distance l’une de l’autre.
Montage:
Arduino Uno
Alimentation Arduino
Capteur LM393
Affichage LCD 20×4 (branché en communication série, c’est-à-dire en A4 et A5)
Led + résistance 220homs à 1kOn peut brancher tout ça avec des fils en l’air, c’est assez simple.
Le programme en C++ doit ressembler à ça:
Bon, je ne vois pas le moyen de mettre du code ici…Cadrature
17 décembre 2024 à 16h40 #420004805980Torzio
Membre- Cadrature a écrit:
- Pour ce montage, je peux aider.
C’est assez simple et le quartz monté sur l’Arduino suffit car il ne s’agit pas de relever des temps longs.Le capteur existe tout fait: LM393 Module de détection de vitesse
sinon, on peut monter une led laser et une photorésistance à distance l’une de l’autre.
Je veux bien un schéma avec les composants qui vont bien. Je préfère le laser à l’infra rouge. J’ai eu des problème d’interférences avec ce dernier. Je ne veux pas d’un rayon pulsé, cela fausse la mesure.
Je ne suis pas d’accord avec le quartz Arduino. Il est très loin d’avoir une précision horlogère. Sa fréquence peut varier de quelques PPM. Lorsque l’on fait une mesure sur une courte durée, il faut une base de temps très précise. Il suffit de mesurer un signal précis et de déterminer une variable d’ajustement pour corriger l’écart de fréquence de l’Arduino.
Voici une photo de mon périodemètre :
Le problème est que le capteur a l’émetteur et le récepteur cote à cote. Le signal doit donc être réfléchi. ce qui fausse les mesures si le balancier n’est pas parfaitement plat. Il faut donc que je fasse un capteur en fourche, avec un rayon laser non pulsé. J’ai acheté, sur Aly Express, des émetteurs et capteurs laser. Mais aucune doc avec. J’ai fait des essais en 5 V, cela a un peu fumé. Il faut que je tente en 3,5 V.
@+
JC17 décembre 2024 à 19h04 #420004805981Cadrature
MembreOK
Pour les composants:
Une plaque à essai
Des fils pour plaque à essais
1 Arduino Uno
1 LED
1 Résistance (entre 720 et 1000 ohm)
1 DS3231
1 LCD2004
1 LMS393 2010Montage:
a)
Brancher GND et 5V sur les lignes d’alimentation de la plaque
LED avec la résistance en série (- petite broche et + grande broche)B)
Brancher LCD et DS3231
sur la ligne d’alimentation Vcc et GND
sur deux lignes de la plaque: SDA et SCL
Relier SDA à la broche SDA de l’Arduino
Relier SCL à la broche SCL de l’Arduino
C’est une communication série avec 2 appareilsC)
Brancher le détecteur IR sur la ligne d’alimentation et sur 2 de l’ArduinoCadrature
17 décembre 2024 à 19h07 #420004805982Cadrature
MembreLa suite: le code
Parfaitement d’accord à propos du quartz de l’Arduino qui n’est pas très fiable pour chronométrer.
Encore moins sur vous utilisez directement le microcontrôleur sans quartz.Le composant DS3231 permet de produire une horloge sur Arduino.
Le composant que j’utilise (LMS393 2010) est simplement un système de coupure IR. Je n’ai jamais eu de pb d’interférence avec.
Il me sert en général à détecter des événements rapides (moins d’une milliseconde)Je fais un petit code avec ce montage et vous montre (si j’arrive à mettre du code dans
les pages du forum)Cadrature
17 décembre 2024 à 19h35 #420004805983Cadrature
MembreBon, du code à adapter en fonction de vos besoins.
Les formules mathématiques sont faciles à ajouter.
L’affichage se fait avec rtc.print()Pour cet exemple, je n’ai fait que la moyenne des alternances (je crois qu’on dit dans ce cas oscillation, mais ne suis plus si sûr).
Je tente encore de mettre du code
Cadrature
/*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* Cadrature 2024
*/#include <Arduino.h>
// Constants
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include « RTClib.h »#define IR_PENDULUM_PIN 2 // IR sensor for the pendulum
#define GREEN_LED 8// LCD setup
LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C address 0x27, 20×4 display// RTC setup
RTC_DS3231 rtc;// Time synchronization
unsigned long lastSyncMillis = 0;
DateTime rtcAtLastSync;
unsigned long SYNC_INTERVAL_MS = 6000; // Synchronization interval with RTCunsigned long pendulumOscillations = 0;
unsigned long pendulumMs = 0;
unsigned long lastPendulumMs = 0;
unsigned long PENDULUM_DEBOUNCE_MS = 700; // Debounce time for pendulum detection
unsigned long sumPendulumMs = 0; // Accumulates the durations of pendulum oscillations
bool pendulumDetected = false;bool greenState = false;
unsigned long greenStartMs = 0;
const unsigned long GREEN_DURATION = 20;// Display update timing
unsigned long lastDisplayUpdateMs = 0;
const unsigned long DISPLAY_UPDATE_INTERVAL_MS = 1009;unsigned long currentTimeMs;
//////////////////////////////
// Synchronize current millis with RTC
//////////////////////////////
unsigned long getCurrentMillis()
{
unsigned long currentMillis = millis();if (currentMillis – lastSyncMillis >= SYNC_INTERVAL_MS)
{
rtcAtLastSync = rtc.now();
lastSyncMillis = currentMillis;
}unsigned long elapsedMillis = currentMillis – lastSyncMillis;
DateTime currentTime = rtcAtLastSync + TimeSpan(elapsedMillis / 1000);
return (currentTime.unixtime() * 1000) + (elapsedMillis % 1000);
}/////////////////////////
// Interrupt for counting pendulum oscillations
/////////////////////////
void IRPendulumISR()
{
if (currentTimeMs – pendulumMs > PENDULUM_DEBOUNCE_MS)
{
greenState = true;
digitalWrite(GREEN_LED, HIGH);
greenStartMs = currentTimeMs;
lastPendulumMs = pendulumMs;
pendulumMs = currentTimeMs;
pendulumDetected = true;
}
}/////////////////////////
// Initialization routine
/////////////////////////
void setup()
{
// Démarre la communication série pour le débogage
Serial.begin(9600);
Serial.println(« Initialisation en cours… »);// Démarre le bus I2C
Wire.begin();
delay(1000);
Serial.println(« I2C démarré »);// Démarre le module RTC
if (!rtc.begin())
{
Serial.println(« Erreur : Impossible de trouver le module RTC. »);
exit(0);
}
Serial.println(« RTC initialisé »);// Initialisation de l’écran LCD
lcd.init();
lcd.backlight(); // Active le rétroéclairage de l’écran
Serial.println(« LCD initialisé »);// Setup RTC
lastSyncMillis = millis();
rtcAtLastSync = rtc.now();pinMode(GREEN_LED, OUTPUT);
attachInterrupt(digitalPinToInterrupt(IR_PENDULUM_PIN), IRPendulumISR, FALLING);// LCD init
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);if (!rtc.begin())
{
lcd.print(« Couldn’t find RTC »);
exit(0);
}if (rtc.lostPower())
{
lcd.print(« RTC lost power, »);
lcd.setCursor(0, 1);
lcd.print(« let’s set the time! »);
// Réglage automatique de l’heure à partir de l’heure de compilation
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
delay(2000);
}currentTimeMs = pendulumMs = getCurrentMillis();
}/////////////////////////
// Main loop
/////////////////////////
void loop()
{currentTimeMs = getCurrentMillis();
if (greenState && currentTimeMs – greenStartMs >= GREEN_DURATION)
{
greenState = false;
digitalWrite(GREEN_LED, LOW);
}if (pendulumDetected)
{
pendulumDetected = false;
sumPendulumMs += pendulumMs – lastPendulumMs;
pendulumOscillations++;
}// Display timing
if (currentTimeMs – lastDisplayUpdateMs >= DISPLAY_UPDATE_INTERVAL_MS)
{
lastDisplayUpdateMs = currentTimeMs;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(sumPendulumMs / pendulumOscillations);
lcd.print(« ms »);
}
}18 décembre 2024 à 8h57 #420004805984Torzio
MembreBonjour Cadrature,
Pour info, Une oscillation = deux alternances. En horlogerie, depuis l’origine, on parle d’alternances/heure pour compter les balanciers. Chaque alternance correspond à un tic ou un tac. Avec l’arrivée du quartz, certains wokistes avant l’heure, ont tenté de désigner la période des balanciers en Hertz. Cette mauvaise habitude semble être passée.
Merci pour votre code, je vais essayer de le comprendre. Je ne suis qu’un amateur dans ce domaine.
Je l’ai vérifié avec l’IDE et il semble y avoir un problème à la ligne 82.Voici mon code :
- Code:
-
/*
**********************************************************************
* Periodemetre.
* Mesure la periode d’un balancier pendulaire
* et de la convertit en alternances/heure
* Jean-Claude Sulka avril 2017
* ********************************************************************
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>int CAPTEUR = 11; // Capteur optique connecte à la broche 11.
int AH; // Alternances pas heure.
int Compteur = 0; // Compte le nombre de mesure.
int Moyenne = 0; // Moyenne des mesures effectuees.
unsigned long Duree; // Duree d’une oscillation.
unsigned long Heure = 3579981002; // nombre de millisecondes dans 1 heure
unsigned long Total = 0; // Total des Alternances/Heure mesurees.LiquidCrystal_I2C lcd(0x27, 16, 2);
//LiquidCrystal_I2C lcd(0x3F, 16, 2);void setup()
{
Serial.begin (115200);
Serial.println (" sulka.fr");
pinMode (CAPTEUR,INPUT);
lcd.init();
lcd.backlight();
lcd.setCursor(2, 0);
lcd.print("PERIODEMETRE");
lcd.setCursor(4, 1);
lcd.print("J-C SULKA ");delay(500);
}void loop()
{
Duree = pulseIn(CAPTEUR,HIGH,50000000);
Duree = Duree / 2;
AH = Heure / Duree;Compteur = Compteur + 1;
Total = Total + AH;
Moyenne = Total / Compteur;// ——————–Affichage LCD—–
lcd.clear();
lcd.setCursor(3,0);
lcd.print(AH);
lcd.setCursor(9,0);
lcd.print ( "A/H");lcd.setCursor(0,1);
lcd.print("M = ");
lcd.setCursor(5,1);
lcd.print(Moyenne);
lcd.setCursor(13,1);
lcd.print (Compteur);Serial.println (AH,Compteur);
delay (50);
}
@+
JC18 décembre 2024 à 9h43 #420004805985Cadrature
Membre- Torzio a écrit:
- Bonjour Cadrature,
Merci pour votre code, je vais essayer de le comprendre. Je ne suis qu’un amateur dans ce domaine.
Je l’ai vérifié avec l’IDE et il semble y avoir un problème à la ligne 82.Voici mon code :
@+
JC
Merci pour votre code. En effet l’approche est différente.
C’est quoi la ligne 82 et le message d’erreur ? Je vais regarder.Concernant votre code:
Je ne connaissais pas pulseIn()
Vous mesurez la durée pendant laquelle le signal n’est pas interrompu. C’est-à-dire entre la fin de la coupure laser
et le début d’une autre coupure laser sur une oscillation complète. Avec 50s au pire des cas, je crois que vous couvrez
tous les besoins en pendules de clocher 🙂Mais même en mettant le détecteur à l’extrême limite, cela va anéantir la mesure du temps passé lors de la coupure.
Je m’explique: on peut décomposer l’oscillation en deux phases: la phase où le laser n’est pas coupé (un grand aller-retour) et la phase où il est
coupé.
Vous pourriez cumuler ce pulseIn() par un autre: pulseIn(CAPTEUR,LOW,1000000)
Je me trompe ?Un autre problème vient: pulseIn va provoquer une attente qui empêche une autre mesure. Comme vous en avez qu’une seule, ce n’est pas un problème. Mais si vous voulez, comme je fais, mesurer le temps réel sur une horloge de référence, cela va poser problème.
C’est pourquoi j’ai plutôt opter pour une interruption.
Une interruption en informatique, c’est un truc qui arrête votre ordinateur quoi qu’il fasse et qui prend la main.
Dans mon code, à chaque fois que le faisceau est coupé, c’est-à-dire que la broche « IR_PENDULUM_PIN » passe de 5v à 0v le code de « IRPendulumISR » est lancé.
Ce qui s’écrit attachInterrupt(digitalPinToInterrupt(IR_PENDULUM_PIN), IRPendulumISR, FALLING);Et si vous regardez le code « IRPendulumISR »:
- Code:
-
void IRPendulumISR()
{
if (currentTimeMs – pendulumMs > PENDULUM_DEBOUNCE_MS)
{
greenState = true;
digitalWrite(GREEN_LED, HIGH);
greenStartMs = currentTimeMs;
lastPendulumMs = pendulumMs;
pendulumMs = currentTimeMs;
pendulumDetected = true;
}
}
On attend un certain temps (PENDULUM_DEBOUNCE_MS) depuis la dernière fois qu’on a détecté cette interruption pour éviter un effet de clignotement à l’approche du balancier.
Puis on fait ce qu’on a à faire:
– Allumer la LED verte
– dire que la dernière détection du pendule c’était pendulumMs
– dire ensuite que pendulumMs c’est maintenant
– dire qu’on a détecté le pendule.Cadrature
18 décembre 2024 à 9h53 #420004805986Cadrature
MembreJ’ai enfin compris comment un met du code ici.
Mon code avec version coupure laser pour balancier et sonnerie
Ce code est à améliorer et à adapter !- Code:
-
/*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* Cadrature 2024
*/#include <Arduino.h>
// Constants
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include « RTClib.h »#define IR_PENDULUM_PIN 2 // IR sensor for the pendulum
#define IR_CHIME_PIN 3 // IR sensor for the chime strikes
#define GREEN_LED 8
#define RED_LED 9
#define BLUE_LED 10
#define BUTTON_PIN 4// LCD setup
LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C address 0x27, 20×4 display// RTC setup
RTC_DS3231 rtc;// Time synchronization
unsigned long lastSyncMillis = 0;
DateTime rtcAtLastSync;
unsigned long SYNC_INTERVAL_MS = 6000; // Synchronization interval with RTCunsigned long pendulumOscillations = 0;
unsigned long pendulumMs = 0;
unsigned long lastPendulumMs = 0;
unsigned long PENDULUM_DEBOUNCE_MS = 700; // Debounce time for pendulum detectionunsigned long CHIME_DELAY_MS = 1 * 3600000 – 10 * 60000; // 24 hours – 10 minutes
unsigned long measuredChimeIntervalMs = 0;
unsigned long REFERENCE_CHIME_INTERVAL_MS = 1 * 3600000; // Reference time for 24 hoursbool greenState = false;
unsigned long greenStartMs = 0;
const unsigned long GREEN_DURATION = 20;bool redState = false;
unsigned long redStartMs = 0;
const unsigned long red_DURATION = 60;bool blueState = false;
unsigned long blueStartMs = 0;
const unsigned long blue_DURATION = 60;// Display update timing
unsigned long lastDisplayUpdateMs = 0;
const unsigned long DISPLAY_UPDATE_INTERVAL_MS = 1009;// IR detection
bool chimeDetected = false;
bool pendulumDetected = false;unsigned long currentTimeMs;
unsigned long t0;unsigned long lastChimeMs;
// Frequency and timing calculations
unsigned long deltaFirstPendulum; // Time between the first chime and the first pendulum oscillation
unsigned long deltaLastPendulum; // Time between the last pendulum oscillation and the second chimeunsigned long sum = 0; // Accumulates the durations of pendulum oscillations
double targetFrequency; // Desired frequencyenum State
{
STATE_INIT,
STATE_WAITING_FIRST_CHIME,
STATE_MEASURING,
STATE_CALIBRATING
};enum State state;
//////////////////////////////
// Synchronize current millis with RTC
//////////////////////////////
unsigned long getCurrentMillis()
{
unsigned long currentMillis = millis();if (currentMillis – lastSyncMillis >= SYNC_INTERVAL_MS)
{
rtcAtLastSync = rtc.now();
lastSyncMillis = currentMillis;
}unsigned long elapsedMillis = currentMillis – lastSyncMillis;
DateTime currentTime = rtcAtLastSync + TimeSpan(elapsedMillis / 1000);
return (currentTime.unixtime() * 1000) + (elapsedMillis % 1000);
}/////////////////////////
// Interrupt for counting pendulum oscillations
/////////////////////////
void IRPendulumISR()
{
if (currentTimeMs – pendulumMs > PENDULUM_DEBOUNCE_MS)
{
greenState = true;
digitalWrite(GREEN_LED, HIGH);
greenStartMs = currentTimeMs;
lastPendulumMs = pendulumMs;
pendulumMs = currentTimeMs;
pendulumDetected = true;
}
}/////////////////////////
// Detection of chime strikes
/////////////////////////
void IRChimeISR()
{
redState = true;
digitalWrite(RED_LED, HIGH); // Turn on the red LED
redStartMs = currentTimeMs;
if (state == STATE_WAITING_FIRST_CHIME || currentTimeMs – lastChimeMs >= CHIME_DELAY_MS)
{
blueState = true;
digitalWrite(BLUE_LED, HIGH); // Turn on the blue LED
blueStartMs = currentTimeMs;
chimeDetected = true;
}
}/////////////////////////
// Initialization routine
/////////////////////////
void setup()
{
// Start the serial port
Serial.begin(57600);// Setup RTC
lastSyncMillis = millis();
rtcAtLastSync = rtc.now();// Start the I2C interface
Wire.begin();pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(GREEN_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
pinMode(BLUE_LED, OUTPUT);
attachInterrupt(digitalPinToInterrupt(IR_PENDULUM_PIN), IRPendulumISR, FALLING);
attachInterrupt(digitalPinToInterrupt(IR_CHIME_PIN), IRChimeISR, FALLING);// LCD init
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);if (!rtc.begin())
{
lcd.print(« Couldn’t find RTC »);
exit(0);
}if (rtc.lostPower())
{
lcd.print(« RTC lost power, »);
lcd.setCursor(0, 1);
lcd.print(« let’s set the time! »);
rtc.adjust(DateTime(1970, 1, 1, 0, 0, 0));
delay(2000);
}lcd.print(« Waiting start button »);
state = STATE_INIT;
}/////////////////////////
// Main loop
/////////////////////////
void loop()
{
currentTimeMs = getCurrentMillis();if (greenState && currentTimeMs – greenStartMs >= GREEN_DURATION)
{
greenState = false;
digitalWrite(GREEN_LED, LOW);
}if (redState && currentTimeMs – redStartMs >= red_DURATION)
{
redState = false;
digitalWrite(RED_LED, LOW);
}if (blueState && currentTimeMs – blueStartMs >= blue_DURATION)
{
blueState = false;
digitalWrite(BLUE_LED, LOW);
}switch (state)
{
case STATE_INIT:
if (pendulumDetected)
{
pendulumDetected = false;
pendulumOscillations++;if (pendulumOscillations == 20)
{
lcd.setCursor(0, 0);
lcd.print(« time for 20 osc.: »);
lcd.setCursor(0, 1);
lcd.print(currentTimeMs – t0);
lcd.print( » « );
t0 = currentTimeMs;
pendulumOscillations = 0;
}
}if (digitalRead(BUTTON_PIN) == LOW)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(« Waiting first chime »);
state = STATE_WAITING_FIRST_CHIME;
delay(1000);
}break;
case STATE_WAITING_FIRST_CHIME:
if (digitalRead(BUTTON_PIN) == LOW)
{
state = STATE_CALIBRATING;
}
if (chimeDetected)
{
chimeDetected = false;
lastChimeMs = currentTimeMs;
pendulumOscillations = 0;
state = STATE_MEASURING;
}
break;case STATE_MEASURING:
if (pendulumDetected)
{
pendulumDetected = false;
pendulumOscillations++;if (deltaFirstPendulum == 0)
{
deltaFirstPendulum = currentTimeMs – lastChimeMs;
}
}if (chimeDetected)
{
chimeDetected = false;deltaLastPendulum = currentTimeMs – lastPendulumMs;
// Calculate the measured delay between two chimes
measuredChimeIntervalMs = currentTimeMs – lastChimeMs;targetFrequency = (REFERENCE_CHIME_INTERVAL_MS – deltaFirstPendulum – deltaLastPendulum) / (pendulumOscillations – 1);
// Update the time of the last chime
lastChimeMs = currentTimeMs;
pendulumOscillations = 0;
state = STATE_CALIBRATING;
}// Display timing
if (currentTimeMs – lastDisplayUpdateMs >= DISPLAY_UPDATE_INTERVAL_MS)
{
lastDisplayUpdateMs = currentTimeMs;
lcd.clear();
lcd.setCursor(0, 0);
if ((currentTimeMs – lastChimeMs >= CHIME_DELAY_MS))
{
lcd.print(« Waiting second chime »);
}
else
{
lcd.setCursor(0, 0);
lcd.print((currentTimeMs – lastChimeMs < CHIME_DELAY_MS) ? (CHIME_DELAY_MS – (currentTimeMs – lastChimeMs)) / 1000 : 0);
lcd.print(« s »);
lcd.setCursor(0, 1);
lcd.print(« Before second chime »);
}
}
break;case STATE_CALIBRATING:
if (digitalRead(BUTTON_PIN) == LOW)
{
sum = 0;
pendulumOscillations = 0;
}if (pendulumDetected)
{
pendulumDetected = false;
sum += pendulumMs – lastPendulumMs;
pendulumOscillations++;
}// Display timing
if (currentTimeMs – lastDisplayUpdateMs >= DISPLAY_UPDATE_INTERVAL_MS)
{lastDisplayUpdateMs = currentTimeMs;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(« Osc: »);
lcd.print(pendulumMs – lastPendulumMs);
lcd.setCursor(0, 1);
lcd.print(« avrg osc: »);
if (pendulumOscillations > 0)
{
lcd.print(sum / pendulumOscillations);
}
else
{
lcd.print(« N/A »); // Évite une division par zéro
}
lcd.setCursor(0, 2);
lcd.print(« delta chime: »);
lcd.print(measuredChimeIntervalMs);
lcd.setCursor(0, 3);
lcd.print(« target frq: « );
lcd.print(targetFrequency);
}
break;
}
}
Code pour montage montré plus haut:
- Code:
-
/*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* Cadrature 2024
*/#include <Arduino.h>
// Constants
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include « RTClib.h »#define IR_PENDULUM_PIN 2 // IR sensor for the pendulum
#define GREEN_LED 8// LCD setup
LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C address 0x27, 20×4 display// RTC setup
RTC_DS3231 rtc;// Time synchronization
unsigned long lastSyncMillis = 0;
DateTime rtcAtLastSync;
unsigned long SYNC_INTERVAL_MS = 6000; // Synchronization interval with RTCunsigned long pendulumOscillations = 0;
unsigned long pendulumMs = 0;
unsigned long lastPendulumMs = 0;
unsigned long PENDULUM_DEBOUNCE_MS = 700; // Debounce time for pendulum detection
unsigned long sumPendulumMs = 0; // Accumulates the durations of pendulum oscillations
bool pendulumDetected = false;bool greenState = false;
unsigned long greenStartMs = 0;
const unsigned long GREEN_DURATION = 20;// Display update timing
unsigned long lastDisplayUpdateMs = 0;
const unsigned long DISPLAY_UPDATE_INTERVAL_MS = 1009;unsigned long currentTimeMs;
//////////////////////////////
// Synchronize current millis with RTC
//////////////////////////////
unsigned long getCurrentMillis()
{
unsigned long currentMillis = millis();if (currentMillis – lastSyncMillis >= SYNC_INTERVAL_MS)
{
rtcAtLastSync = rtc.now();
lastSyncMillis = currentMillis;
}unsigned long elapsedMillis = currentMillis – lastSyncMillis;
DateTime currentTime = rtcAtLastSync + TimeSpan(elapsedMillis / 1000);
return (currentTime.unixtime() * 1000) + (elapsedMillis % 1000);
}/////////////////////////
// Interrupt for counting pendulum oscillations
/////////////////////////
void IRPendulumISR()
{
if (currentTimeMs – pendulumMs > PENDULUM_DEBOUNCE_MS)
{
greenState = true;
digitalWrite(GREEN_LED, HIGH);
greenStartMs = currentTimeMs;
lastPendulumMs = pendulumMs;
pendulumMs = currentTimeMs;
pendulumDetected = true;
}
}/////////////////////////
// Initialization routine
/////////////////////////
void setup()
{
// Démarre la communication série pour le débogage
Serial.begin(9600);
Serial.println(« Initialisation en cours… »);// Démarre le bus I2C
Wire.begin();
delay(1000);
Serial.println(« I2C démarré »);// Démarre le module RTC
if (!rtc.begin())
{
Serial.println(« Erreur : Impossible de trouver le module RTC. »);
exit(0);
}
Serial.println(« RTC initialisé »);// Initialisation de l’écran LCD
lcd.init();
lcd.backlight(); // Active le rétroéclairage de l’écran
Serial.println(« LCD initialisé »);// Setup RTC
lastSyncMillis = millis();
rtcAtLastSync = rtc.now();pinMode(GREEN_LED, OUTPUT);
attachInterrupt(digitalPinToInterrupt(IR_PENDULUM_PIN), IRPendulumISR, FALLING);// LCD init
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);if (!rtc.begin())
{
lcd.print(« Couldn’t find RTC »);
exit(0);
}if (rtc.lostPower())
{
lcd.print(« RTC lost power, »);
lcd.setCursor(0, 1);
lcd.print(« let’s set the time! »);
// Réglage automatique de l’heure à partir de l’heure de compilation
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
delay(2000);
}currentTimeMs = pendulumMs = getCurrentMillis();
}/////////////////////////
// Main loop
/////////////////////////
void loop()
{currentTimeMs = getCurrentMillis();
if (greenState && currentTimeMs – greenStartMs >= GREEN_DURATION)
{
greenState = false;
digitalWrite(GREEN_LED, LOW);
}if (pendulumDetected)
{
pendulumDetected = false;
sumPendulumMs += pendulumMs – lastPendulumMs;
pendulumOscillations++;
}// Display timing
if (currentTimeMs – lastDisplayUpdateMs >= DISPLAY_UPDATE_INTERVAL_MS)
{
lastDisplayUpdateMs = currentTimeMs;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(sumPendulumMs / pendulumOscillations);
lcd.print(« ms »);
}
}
Cadrature
18 décembre 2024 à 11h37 #420004805987Torzio
Membre{
Cadrature a dit :
Mais même en mettant le détecteur à l’extrême limite, cela va anéantir la mesure du temps passé lors de la coupure.
Je m’explique: on peut décomposer l’oscillation en deux phases: la phase où le laser n’est pas coupé (un grand aller-retour) et la phase où il est
coupé.
Vous pourriez cumuler ce pulseIn() par un autre: pulseIn(CAPTEUR,LOW,1000000)
Je me trompe ?
Un autre problème vient: pulseIn va provoquer une attente qui empêche une autre mesure. Comme vous en avez qu’une seule, ce n’est pas un problème. Mais si vous voulez, comme je fais, mesurer le temps réel sur une horloge de référence, cela va poser problème.
}Je ne vois pas où est le problème. Mon code fonctionne parfaitement bien, mais, comme je l’ai déjà dit, j’ai des problème avec des balanciers aux lentilles sculptées, la réflexion du rayon ne se fait pas toujours au bon moment, pour peu que le balancier n’ait pas un déplacement parfaitement régulier, d’avant en arrière. Comme je l’ai dit, cela provient du capteur qui fonctionne par réflexion. Il faut que j’équipe mon montage d’un capteur avec un faisceau laser qui sera coupé par la lentille du balancier.
Le fait d’utiliser Pulsein() permet à l’Arduino de se consacrer uniquement à la mesure d’une oscillation., qui ne sera pas polluée pas du « temps machine ». Une seule oscillation sur deux sera mesurée. Les calculs et l’affichage sont effectuées pendant l’oscillation « muette », pour ne pas polluer la mesure.
Il faut bien sûr positionner le capteur afin de prendre la mesure sur la partie la plus large du balancier. et laisser de la marge, pour ne pas avoir un faux déclenchement.@+
JC18 décembre 2024 à 17h11 #420004805988Cadrature
Membre- Torzio a écrit:
- {
Cadrature a dit :
Mais même en mettant le détecteur à l’extrême limite, cela va anéantir la mesure du temps passé lors de la coupure.
Je m’explique: on peut décomposer l’oscillation en deux phases: la phase où le laser n’est pas coupé (un grand aller-retour) et la phase où il est
coupé.
Vous pourriez cumuler ce pulseIn() par un autre: pulseIn(CAPTEUR,LOW,1000000)
Je me trompe ?
Un autre problème vient: pulseIn va provoquer une attente qui empêche une autre mesure. Comme vous en avez qu’une seule, ce n’est pas un problème. Mais si vous voulez, comme je fais, mesurer le temps réel sur une horloge de référence, cela va poser problème.
}Je ne vois pas où est le problème. Mon code fonctionne parfaitement bien, mais, comme je l’ai déjà dit, j’ai des problème avec des balanciers aux lentilles sculptées, la réflexion du rayon ne se fait pas toujours au bon moment, pour peu que le balancier n’ait pas un déplacement parfaitement régulier, d’avant en arrière. Comme je l’ai dit, cela provient du capteur qui fonctionne par réflexion. Il faut que j’équipe mon montage d’un capteur avec un faisceau laser qui sera coupé par la lentille du balancier.
Le fait d’utiliser Pulsein() permet à l’Arduino de se consacrer uniquement à la mesure d’une oscillation., qui ne sera pas polluée pas du « temps machine ». Une seule oscillation sur deux sera mesurée. Les calculs et l’affichage sont effectuées pendant l’oscillation « muette », pour ne pas polluer la mesure.
Il faut bien sûr positionner le capteur afin de prendre la mesure sur la partie la plus large du balancier. et laisser de la marge, pour ne pas avoir un faux déclenchement.@+
JC
Le code fonctionne, mais il mesure seulement un temps où la cellule reçoit la lumière, pas l’autre temps qui ne me semble pas négligeable. Mais
je n’ai peut-être pas compris le montage. Ou alors je n’ai pas compris pulseIn().pulseIn() calcule bien les temps, mais empêchera d’autres évènements.
S’il est tout seul ça va, mais si vous mesurez d’autres choses en parallèle, les problèmes viendront.
C’est l’avantage des interruptions qui captent un signal haut ou un signal bas avec un anti-rebond.
Cela fonctionnerait bien avec votre montage à réflexion, même avec des lentilles
compliquées.Pour le montage avec un laser. Il me semble que le plus simple est la coupure d’un faisceau en effet. La réflexion (à choisir pour une montre par exemple) est plus délicate.
Un système à collimation et miroir irait certainement, mais c’est bien compliqué à mettre en oeuvre.Pour un montage où le capteur est distant de l’émetteur, on peut monter un laser à point rouge par exemple avec une photorésistance.
Les composants existent tout faits à prix modiques.
Un faisceau infra-rouge ou un détecteur de distance optique, à laser, à induction n’est pas recommandé s’il est à impulsions.
Vous l’aviez justement souligné.Cadrature
18 décembre 2024 à 17h34 #420004805989Torzio
MembreVous avez mis le doute dans mon esprit !
Ce qui est étonnant, c’est que les valeurs lues me semblaient parfaitement cohérentes.J’avais même ajusté le nombre de micro secondes en 1 heure pour corriger l’erreur du quartz de l’Arduino utilisé :
unsigned long Heure = 3579135248; // nombre de microsecondes dans 1 heureJ’ai fait ce montage il y a bien longtemps, je vais m’y replonger dès que possible.
J’ai trouvé une autre façon de faire, qu’en pensez-vous ?
- Code:
-
// mesure temps courts
const int buttonPin = 2;
unsigned long startTime;
unsigned long endTime;void setup() {
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
}void loop() {
if (digitalRead(buttonPin) == LOW) {
startTime = millis();
while (digitalRead(buttonPin) == LOW) {
// Attendre que le bouton soit relâché
}
endTime = millis();unsigned long duration = endTime – startTime;
Serial.print("Durée du bouton enfoncé : ");
Serial.print(duration);
Serial.println(" ms");
}
}
Mon objectif est de mesurer une oscillation (deux alternances) et de ne faire que ça, pour ne pas fausser la mesure par du temps machine. Pendant l’alternance suivante, l’Arduino s’occupe des calculs et de l’affichage.
@+
JC18 décembre 2024 à 20h58 #420004805990Cadrature
MembreBonsoir
Dans l’esprit ce code est bon. Il pose un petit problème avec un bouton et même avec une coupure lumière.
Au moment précis de l’événement, il peut se passer un phénomène imperceptible: celui du « rebond ».
Quand le faisceau passe à peine, ou que le bouton touche à peine, il s’allume et s’éteint plusieurs fois en quelques microsecondes, voire millisecondes.
Donc la boucle while risque d’être interrompue au tout début.Pour résoudre ce problème on utilise un délai après la détection, mais cela fausse le résultat. Il faudra alors corriger ce délai.
L’astuce est d’utiliser un temps de « rebond », par exemple de 20ms et plus de délai.
- Code:
-
unsigned long startTime;
unsigned long endTime;
int buttonPin = 2;const unsigned long debounceDelay = 20; // temps de rebond de 20ms
unsigned long lastDebounceTime = 0;int lastState = LOW;
int state;void setup()
{
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
}void loop()
{state = digitalRead(buttonPin);
if (state != lastState)
{unsigned long now = millis();
if (now – lastDebounceTime > debounceDelay)
{
lastDebounceTime = now;
if (state == LOW)
{
startTime = now;
}
if (state == HIGH)
{
endTime = now;
unsigned long duration = endTime – startTime;
Serial.print("Durée du bouton enfoncé : ");
Serial.print(duration);
Serial.println(" ms");
}
}
}lastState = state;
}
Cadrature
18 décembre 2024 à 22h41 #420004805991Torzio
MembreMerci Cadrature pour ces précieuses infos que je vais essayer de mettre en pratique/
En attendant, une petite vidéo de mon périodemètre, que j’ai remis en action. Les résultats sont cohérents, sauf quelques fois des résultats bizarres. Peut-être un problème de rebond ?
Est ce qu’un condensateur de 100 nf pourrait résoudre le problème ?https://sulka.fr/videos/periodemetre.mp4
@+
JC18 décembre 2024 à 23h11 #420004805992Cadrature
MembreCela dépasse mes compétences, je n’y connais pas grand chose en électronique. Mon niveau bac scientifique bien ancien…
Mais oui une capacité branchée en parallèle de la photorésistance va permettre de provoquer un délai de latence et filtrer les pics.
Il faudrait essayer.
Le calcul est donné par t = R . C où R est la résistance de la photocell (10k en général)100nF . 10k = une milliseconde
Je ne sais pas pour le reste et si le montage est fiable.
Cadrature
-
AuteurMessages
- Vous devez être connecté pour répondre à ce sujet.





