Signal compte tour moto arduino

Bonjour,

j'ai réalisé un indicateur de rapport engagé pour moto qui allume des leds adressables WS2812 en fonction de la vitesse enclanchée.
J'ai fait une carte electronique avec un ATMEGA328 smd et ca fonctionne impeccable
Je voudrais upgrader en faisant un shift light (clignotement des leds en fonction d'un certain régime moteur)
J'ai relevé à l'oscillo la forme du signal en fonction du régime et j'en ai déduit une équation.
Mon signal rentrerait dans un optocoupleur au travers une resistance pour ressortir dans l'entrée INT1=0 de l'arduino afin de créer une interuption pour un regime programmé. Cette interruption déclenchera une fonction me faisant clignoter les leds. Pour la programmation je pense pouvoir m'en sortir mais pour le coté électronique j'ai besoin d'un conseil
Ma question est la suivante pensez vous que le signal puisse être traité directement en sortie de l'opto. J'ai rajouté en sortie une résistance pour le pullup et un condo.
Je vous joint des photos de la partie du schémas et des relevés oscillo. Les relevés oscillo sont 35Hz pour 2000 trs/min et 50Hz pour 3000trs/min. Ca répond à l'équation f(Hz)=0.015*trm + 5
R29=1k
Merci



Optocoupleur

Nico

Bonjour Nico.

Pour le schéma de sortie de l'opto, je propose (ça se discute)
Screenshot_20240914-233428~2 (1)

Td et Tm définissent en partie les temps de descente et montée du signal envoyé à l'Arduino.

Ils sont dû au temp de charge de C à travers R31 et R32
Et au temp de décharge de C à travers R32.

En fait, il faut pour charger 1 condensateur un temps à peut prés = à 3xRC.

Pour ton montage, tu a des créneaux à l'état bas qui durent environ 5ms, il faut que le condensateur puisse se décharger complètement pendant ces 5ms

Donc il faut que 3xTd soit inférieur à 0,005s
OU
3xR32xC inférieur 0,005
OU
C inférieur 0,005/(3x2000)=833nF

J'ai mis 10nF car:
-le temps de charge est 2 fois plus long que le temps de décharge
-je pense que plus le front montant ou descendant est raide (rapide) mieux c'est pour gérer l'interruption sur front (RISING ou FALLING).

Mais effectivement, 100nF, ça peut marcher aussi.

PS:
J'ai fais une bourde dans ma commande attiny, j'ai reçut ça :face_with_monocle:


J'aurais les bons semaine prochaine pour enfin tester ton petit pcb et faire des petits montages

Tes conseils étants bons j'ai commandé à l'instant des 10nf car je n'en n'avais pas. Pour la nouvelle résistance en série entre R31 et C19 ça m'embête un peu mes pcb sont déja en commande. Je couperai une piste pour la mettre en volant pour essayer et si c'est ok je relancerai une commande de PCB.
J'attends mes composants et pcb et je fais un retour dès que tout est soudé.

Ps la prochaine fois je te mets un attiny dans le colis :rofl:
Ps2: je me suis aussi planté dans une de mes commandes attiny et je n'ai jamais pu programmer ceux que j'avais reçu.
Merci

Nico

Bonjour,

Cette résistance sert à limiter le courant de décharge du condensateur.
Mais je ne suis pas un expert de la connaissance intrinséque des composants pour te dire si oui ou non cette résistance est indispensable pour la "santé" du transistor de l'opto qui se prend la décharge de C dans les dents.

Donc le mieux, c'est de voir avec ton oscillo et aux niveaux des interruptions, ce qui se passe.

Il y a plusieurs paramétres à tester
-sans R31 avec 10n ou 100n
-avec R31 avec 10n ou 100n
-Interuotion sur fronts ou sur niveaux.

(Par exemple, j'ai remarqué, aec un BP et sans condensateur, que les interruptions sur FALLING marchaient mieux que sur RISSING)

Bonjour salocin90

Au vu de la qualité du signal, à quoi sert C10, il ne peut que t'apporter des déformation du signal qui est impeccable.
Garde R31 de 2k, c'est une bonne protection contre le "bruit" souvent présent dans ce genre d'environnement.
Du fait de l'inversion du signal dans l'optocoupleur, il faut déclencher l'interruption sur RISING.

A+
Cordialement
jpbbricole

Bonjour,

On ne peut pas dire que le signal soit parfaitement impeccable.
De plus, c'est sûr, si C ne "déformait" pas le signal initial, il ne servirait à rien.
Mais une "déformation", ça se controle par le choix d'une bonne valeur de C et des résistances.

R=2k Ohms, ce n'est pas pris au hasard parce que c'est bien pour se protéger du bruit.

C'est bien aussi pour saturer correctement le transistor selon les valeurs proposées dans le datasheet de l'opto TLP521.

Screenshot_20240915-100558~2

Toi tu as un courant If (côté diode) de l'ordre de 10mA.

Côté transistor, on voit bien que plus Ic est faible, plus le transistor est saturé et sa tension Vce faible quand il conduit.
C'est ce qu'on cherche

Ic=2,4mA est un bon compromis, on pourrait prendre Ic plus faible, mais il faudrait augmenter R31, et se serait mauvais pour le bruit comme l'indique @jpbbricole .

Avec R32=2k, quand le transistor conduit, tu as environ Ic=(5-0,4)/2=2,3mA.

C'est conforme au datasheet, à savoir
Screenshot_20240915-100558~2 (1)

Quand au FALLING ou RISING, quand un signal est périodique, il est alternativement
FALLING--RISING--FALLING--RISING.......
L'important c'est d'utiliser le front qui marche le mieux, on s'en fout que le signal soit inversé ou pas, non?

Pour ce que l'on veut en faire, oui, le condensateur ne sert à rien, c'est une complication inutile.

Merci pour vos réponses. J'ai la réponse à ma question initiale. Le signal peut être traité en sortie d'opto avec résistance en plus par rapport à mon schéma et avec ou sans condensateur (à tester). Ca me va très bien.
A la réception de mes composants je vous fait un retour de la meilleure solution.

@jef59 j'ai changé l'alim 5V3A que tu m'avais proposé. Ca fonctionne mais il arrive que quand un téléphone est en charge sur l'usb l'Atmega fasse n'importe quoi. Il y a du mieux en ajoutant une résistance entre le 5V et la ligne data des led WS2812 ainsi qu'une rsistance sur la ligne data. Je vais voir avec cette alim à base du NS6326 si ca fonctionne mieux en plus je gagne en encombrement.
Merci à vous

J'ai repréparé une nouvelle carte avec la résistance en série ( ca à router toute la nuit). Les numéro de résistance et condensateurs ont changés mais le schéma reste le même.




carte3

Nico

J'aime bien verifier mes petites élucubrations.
J'ai donc fais ce montage pour simuler d'un coté un signal 12V ayant la même allure que sur tes oscillogramme, avec Arduino1.
Et de l'autre côté, je récupére le signal sortie opto pour compter les fronts par interuptions sur Arduino2.

J'ai mis C=100nF


Sur Arduino1 qui génère le signal périodique, le code est


void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// 37Hz=>T=27ms 50Hz=>T=20ms
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(23);//t1
  digitalWrite(LED_BUILTIN, LOW);
  delay(4);// t2
  //T=t1+t2, t2 fixe et= 4ms
}

et sur Arduino2 qui recoit le signal périodique sur INT2, le code est

const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;
volatile int compt=0;
volatile int t=0;
volatile int t1=0;
volatile int t2=0;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), onEvent, FALLING);
  Serial.println(F("Système intialisé"));
}

void loop() {
  if (compt>9){
    //Serial.println(compt);
    
    compt=0;
    t2=millis();
    t=t2-t1;
    //Serial.print("Période du signal mesuré en ms= ");
    Serial.print(t/10);
    Serial.println("ms");
    t1=t2;
    
  }
} 

void onEvent() {
  compt=compt+1;
}

Je récupére la valeur de la période par

J'ai fais plusieurs tests jusqu'à 500Hz avec comme paramétres pour 500Hz t1=t2=1ms et C=10nF (avec 100nF, le signal n'a pas le temps de monter correctement) et je recupére, sur la liaison série, la valeurs T=2ms (f=1/T=500Hz)

Sans C, ca marche aussi, mais puisque tu a fais le routage de ta carte avec, c'est OK

PS:
Sûrement que les pro du code ne trouveront pas ma méthode élégante avec des delays, mais en tout cas ça génère bien un signal périodique 0-12V de rapport cyclique variable, CQFD

PS2:
Pour le test à 500Hz, je mesurer le temps sur 100 interuptions, et j'ai fais le test avec RISING ou FALLING, je trouve toujours T=2ms (500Hz).

Merci @jef59 pour tes tests.
Mon signal prendra pour valeur maxi 200Hz qui correspond à 13000 trs/min et mini 80Hz (5000 trs/min) donc ca va aller. Demain je vais également faire un petit montage avec 2 arduino (pas possible aujourd'hui) pour écrire mon code afin d'allumer mes leds à partir d'une fréquence paramétrée.
J'utiliserai une partie de ton code
Je ferai un petit retour.
Encore merci

Nico

Alors, à propos de mon code, les delays, c'est pour faire vite à coder, et mon temps de "loop" est assez court, donc à priori, en dessous du kHz c'est assez précis.
Mais un codeur pro te dira que ce n'est pas le top je crois et qu'il vaut mieux jouer avec les mesures de temps par les millis() ou micro() par exemple.

Tout dépend de ce que tu veut faire.

En plus, avec mon PC pas de course, 2 laisons série par USB sur le même PC (1 par Arduino) des fois ça cafouille un peu.

Bien sur, pense à relier les GND de tes arduinos ensemble.

Bon je vais profiter du soleil...
Bien que ça tiraille par ici, ça doit déjà être l'ouverture de la chasse, faut que je fasse gaffe à ma chienne qui en plus à peur des coups de feux.

1 Like

Bonjour salocin90

A "l'époque" j'ai fait ça:

Si ça t'intéresse :wink:

Si tu veux un générateur tout simple qui donne entre 80 et 200 Hz:
frequency = map(potValue, 0, 1023, 80, 200); // Convertir la valeur du potentiomètre en fréquence entre 80 et 200 Hz

const int outputPin = 13;  // Pin de sortie pour le signal carré
const int potPin = A0;     // Entrée analogique pour le potentiomètre (si utilisé)

unsigned long previousMillis = 0;
int frequency = 100;      // Fréquence de base en Hz
int period = 0;           // Durée d'une période (ms)
bool signalState = LOW;   // État du signal

void setup() {
  pinMode(outputPin, OUTPUT);  // Définit la broche de sortie en tant que sortie
}

void loop() {
  // Si on utilise un potentiomètre pour régler la fréquence
  int potValue = analogRead(potPin);  // Lire la valeur du potentiomètre
  frequency = map(potValue, 0, 1023, 80, 200);  // Convertir la valeur du potentiomètre en fréquence entre 80 et 200 Hz

  period = 1000 / frequency;  // Calcul de la période en millisecondes (1000 ms / fréquence)

  unsigned long currentMillis = millis();  // Obtenir le temps actuel

  // Inverser l'état du signal à chaque demi-période
  if (currentMillis - previousMillis >= period / 2) {
    previousMillis = currentMillis;  // Réinitialiser le compteur
    signalState = !signalState;      // Inverser l'état du signal
    digitalWrite(outputPin, signalState);  // Mettre à jour la sortie avec l'état du signal
  }
}

C'est généré par l'IA :wink:

1 Like

@jpbbricole
:thinking:
Parfois, j'ai l'impression que vous ne lisez pas les messages de tout le monde sur le sujet sur lequel vous répondez.
Par exemple j'ai proposé ici, pour une utilisation de test, un géne BF de rapport cyclique et période variable qui marche trés bien à ces fréquence, sauf qu'il n'y a pas de potentiométre, et comme sur la moto, il fournit un signal 12V.

C'est pas très grave ma foi!

1 Like

Bonsoir jef59

Non, en effet.

Cordialement
jpbbricole

J'ai fait 2 petits progs pour 2 arduino un qui simule les leds de mon compteur et l'autre qui simule ma fréquence.
Le récepteur allume les leds en blanc si la fréquence reçue est < 100Hz en violet clignotant si >100hz et en rouge si>150Hz.
L'émetteur envoie un signal variant de 10HZ tous les 5 secondes de 50 à 200Hz. Tout fonctionne impeccable.

@jpbbricole je ne voulais pas mettre de potentiomètre pour les essais je préfère que ca s'incrémente tout seul.

@jef59 J'ai déjà voulu faire le code avant d'essayer avec le vrai signal et j'attends mes composants.

La c'est branché directement d'arduino à arduino on verra avec mon vrai signal
L'IA m'a tout fait :rofl:

J'ai mis un clignotement rapide, j'arrête les essais pour aujourd'hui ou je vais finir épileptique

Générateur fréquence

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Pin de sortie pour le signal
const int outputPin = 9;

// Fréquence de départ et limites
float frequency = 50.0;  // Fréquence initiale (50 Hz)
const float minFrequency = 50.0;
const float maxFrequency = 200.0;
const float incrementStep = 10.0;  // Augmentation de 10 Hz toutes les 5 secondes
unsigned long previousMillis = 0;  // Pour la gestion du temps

void setup() {
  pinMode(outputPin, OUTPUT);
  
  // Initialisation de la communication série à 9600 bauds
  Serial.begin(9600);
}

void loop() {
  unsigned long currentMillis = millis();

  // Incrémentation de la fréquence toutes les 5 secondes (5000 ms)
  if (currentMillis - previousMillis >= 5000) {
    previousMillis = currentMillis;

    // Incrémenter la fréquence
    frequency += incrementStep;
    
    // Réinitialiser à 50 Hz si on dépasse 200 Hz
    if (frequency > maxFrequency) {
      frequency = minFrequency;
    }

    // Afficher la fréquence sur le moniteur série
    Serial.print("Fréquence actuelle : ");
    Serial.print(frequency);
    Serial.println(" Hz");
  }

  // Calcul de la période totale du signal en millisecondes
  float period = 1000.0 / frequency;  // Période en millisecondes
  
  // Proportion des 5V (80%) et 0V (20%) par rapport à la période totale
  float highTime = period * 0.8;  // Durée à 5V
  float lowTime = period * 0.2;   // Durée à 0V

  // Génération du signal
  digitalWrite(outputPin, HIGH);  // 5V
  delayMicroseconds(highTime * 1000);  // Conversion en microsecondes

  digitalWrite(outputPin, LOW);   // 0V
  delayMicroseconds(lowTime * 1000);   // Conversion en microsecondes
}

IMG_5503
IMG_5504
IMG_5508
IMG_5509

Récepteur

#include <FastLED.h>

#define LED_PIN     6      // Pin pour contrôler les LEDs WS2812
#define NUM_LEDS    5      // Nombre de LEDs WS2812
#define INTERRUPT_PIN 2    // Pin d'interruption (INT0) = Pin 2 sur Arduino Uno

CRGB leds[NUM_LEDS];

volatile unsigned long lastTime = 0;  // Temps du dernier front montant
volatile float frequency = 0;         // Fréquence calculée

bool sup100Hz = false;                // Indique si la fréquence est > 100 Hz
bool sup150Hz = false;                // Indique si la fréquence est > 150 Hz
unsigned long previousMillis = 0;     // Pour la gestion du clignotement
const unsigned long interval = 50;    // Intervalle de clignotement (50ms)

void setup() {
  // Initialisation des LEDs
  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.clear();
  FastLED.show();

  // Initialisation de l'interruption sur INT0 (pin 2)
  attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), calculateFrequency, FALLING);

  Serial.begin(9600);  // Pour le débogage
}

void loop() {
  unsigned long currentMillis = millis();

  // Si la fréquence est supérieure à 150 Hz, clignoter en rouge
  if (sup150Hz) {
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;

      // Inversion de l'état des LEDs (rouge ou éteintes)
      static bool ledState = false;
      if (ledState) {
        FastLED.clear();  // Éteindre les LEDs
      } else {
        for (int i = 0; i < NUM_LEDS; i++) {
          leds[i] = CRGB::Red;  // Allumer en rouge
        }
      }
      ledState = !ledState;
      FastLED.show();
    }
  }
  // Si la fréquence est supérieure à 100 Hz mais inférieure ou égale à 150 Hz, clignoter en violet
  else if (sup100Hz) {
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;

      // Inversion de l'état des LEDs (violet ou éteintes)
      static bool ledState = false;
      if (ledState) {
        FastLED.clear();  // Éteindre les LEDs
      } else {
        for (int i = 0; i < NUM_LEDS; i++) {
          leds[i] = CRGB::Purple;  // Allumer en violet
        }
      }
      ledState = !ledState;
      FastLED.show();
    }
  }
  // Si la fréquence est inférieure ou égale à 100 Hz, allumer en blanc
  else {
    for (int i = 0; i < NUM_LEDS; i++) {
      leds[i] = CRGB::White;  // Allumer en blanc
    }
    FastLED.show();
  }

  // Pour le débogage
  Serial.print("Frequency: ");
  Serial.println(frequency);
}

// Fonction d'interruption pour calculer la fréquence
void calculateFrequency() {
  unsigned long currentTime = micros();  // Temps actuel en microsecondes
  unsigned long period = currentTime - lastTime;  // Calculer la période en us
  lastTime = currentTime;  // Mise à jour du dernier temps

  // Calculer la fréquence en Hz
  frequency = 1000000.0 / period;

  // Vérifier si la fréquence est > 150 Hz
  if (frequency > 150.0) {
    sup150Hz = true;
    sup100Hz = false;  // Ne pas activer l'état > 100 Hz si on est au-dessus de 150 Hz
  }
  // Vérifier si la fréquence est > 100 Hz mais <= 150 Hz
  else if (frequency > 100.0) {
    sup150Hz = false;
    sup100Hz = true;
  }
  // Sinon, la fréquence est <= 100 Hz
  else {
    sup150Hz = false;
    sup100Hz = false;
  }
}

Bonsoir salocin90

Tu utilises laquelle?

J'ai utilisé ChatGPT

C'est mon préféré.
Si tu as fait ton générateur avec l'IA, spécifies:

sans delay() mais avec des millis()

ca t'évite d'avoir des delay()

En jettant 1 oeil sur ton schéma, je m'aperçois de coquilles de notre part.

Tu as fais une bourde en copiant min schéma.
Et moi, je me suis planté aussi.

J'aurais dû proposer

Ce qui chez toi donnerais

Bref, on a fais faux tous les 2.

Je crois avoir vu maintenant que tu le dis

Schémas ci dessous corrigé.