Bonjour à tous;
J’ai demandé à ChatGPT d’analyser la solution (message précédent). L’idée n’est pas de te mettre en défaut, mais de soumettre son approche à votre avis ?
Points à corriger / préciser
TCNT0 = 0; n’isole pas la fenêtre de mesure.
Remettre Timer0 à zéro ne coupe aucune interruption (UART, overflow Timer0…). Des ISR peuvent donc encore se produire pendant la mesure.
TCCR1A = 0; indispensable (tu l’as ajouté ensuite).
Sans cette remise à zéro, Timer1 peut rester en mode PWM/compare → mesures incohérentes.
t = TCNT1 - 2; = ajustement arbitraire.
Cela peut masquer un léger décalage (“off-by-one”). Il vaut mieux lire directement t = TCNT1;.
Pas de barrière de compilation.
Même avec volatile, le compilateur peut réordonner des calculs.
Une barrière (asm volatile("" ::: "memory")) garantit que l’expression mesurée reste bien entre la RAZ et la lecture du timer.
Interférences série entre blocs.
Sans Serial.flush() (et/ou cli()/sei()), l’UART peut encore émettre au début du bloc suivant → risque d’interruptions pendant la mesure.
Voie 16 bits : risque de promotion signée / overflow.
Sur AVR, int = 16 bits signé.
55 * w (avec w≈1000) donne 55 000 > 32767 → dépassement.
Forcer l’arithmétique non signée : 2327u, 55u, 4654u et caster en uint16_t.
Affichage en “ns”.
Plus lisible d’afficher :
ns = cycles * 62.5 ou us = cycles / 16.0 (pour une horloge à 16 MHz).
volatile utile mais insuffisant seul.
Il garantit l’accès mémoire, pas l’ordre d’exécution. D’où l’intérêt de la barrière mémoire.
⸻
Code proposé
(même principe :random() avant, on mesure seulement l’expression)
Fenêtre propre : TCCR1A = 0, prescaler = 1, cli()/sei(), barrière mémoire, voie 16 bits non signée.
#include <Arduino.h>
#include <avr/interrupt.h>
volatile uint8_t b; // effet observable
uint16_t t; // cycles mesurés
__attribute__((noinline))
uint8_t calc_float(float x) {
return (uint8_t)((2327.0f + 55.0f * x) / (4654.0f - x));
}
__attribute__((noinline))
uint8_t calc_ulong(uint32_t x) {
return (uint8_t)((2327ul + 55ul * x) / (4654ul - x));
}
__attribute__((noinline))
uint8_t calc_word(uint16_t x) {
return (uint8_t)((uint16_t)(2327u + 55u * x) / (uint16_t)(4654u - x));
}
template<typename F>
uint16_t measure_expr(F&& expr) {
TCCR1A = 0; // Timer1 en mode normal
TCCR1B = _BV(CS10); // clk/1 → 1 tick = 1 cycle
//TCNT1 = 0;
cli(); // coupe les ISR pendant la fenêtre
TCNT1 = 0; // départ
asm volatile("" ::: "memory"); // barrière: empêche tout réordonnancement
b = expr(); // *** expression mesurée ***
//expr() est par exemple la lambda [&]{ return calc_float(wf); }
// exemple : b = calc_float(wf);
asm volatile("" ::: "memory");
uint16_t cycles = TCNT1; // arrêt
sei(); // réactive les ISR
return cycles;
}
void setup() {
Serial.begin(115200);
while(!Serial) {}
// FLOAT
volatile float wf = 1000.0f + (float)random(10); // random AVANT
Serial.flush();
t = measure_expr([&]{ return calc_float(wf); });
Serial.print(F("Code avec float: "));
Serial.print(t); Serial.print(F(" cycles "));
Serial.print(t * 62.5);
Serial.print(F(" ns (")); Serial.print(t / 16.0, 3);
Serial.print(F(" us) b=")); Serial.println(b);
Serial.flush();
// UNSIGNED LONG
volatile unsigned long wl = 1000ul + (unsigned long)random(10);
Serial.flush();
t = measure_expr([&]{ return calc_ulong(wl); });
Serial.print(F("Code avec unsigned long: "));
Serial.print(t); Serial.print(F(" cycles "));
Serial.print(t * 62.5);
Serial.print(F(" ns (")); Serial.print(t / 16.0, 3);
Serial.print(F(" us) b=")); Serial.println(b);
Serial.flush();
// WORD (16 bits)
volatile uint16_t ww = 1000u + (uint16_t)random(10);
Serial.flush();
t = measure_expr([&]{ return calc_word(ww); });
Serial.print(F("Code avec word: "));
Serial.print(t); Serial.print(F(" cycles "));
Serial.print(t * 62.5);
Serial.print(F(" ns (")); Serial.print(t / 16.0, 3);
Serial.print(F(" us) b=")); Serial.println(b);
}
void loop() {}
Mesures obtenues (UNO @ 16 MHz)
Code avec float: ~975 cycles ≈ 60.94 µs b=15
Code avec unsigned long: ~684 cycles ≈ 42.75 µs b=15
Code avec word: ~233 cycles ≈ 14.56 µs b=15
Interprétation
• Plus les opérandes sont larges (16 < 32 < float), plus les routines de division sont longues → word < ulong < float**.**
Commentaire final :
Cette méthode n’invalide pas celle de l’auteur, mais la rend simplement plus “hermétique” et reproductible en neutralisant les effets du compilateur et des interruptions.
Bonne journée.