Compteur vitesse (Hall, Lcd, Arduino)

Bonsoir tout le monde,

Dans la réalisation d'un projet personnel, je voudrais réaliser un compteur de vitesse pour vélo via mon arduino uno avec un écran lcd et un capteur à effet de hall :stuck_out_tongue:

Tout d'abord, je voulais vous montrer ce que j'ai fais: :confused:

#include <Adafruit_GFX.h>
#define PULSE_PIN 2
#define PULSE_TIMEOUT 1000000
#include <SPI.h>
#include <Adafruit_PCD8544.h>
#include <avr/sleep.h>
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);
unsigned long trm; 
const float pi = 3.14;



void setup()
{
  pinMode(PULSE_PIN, INPUT);
  display.begin();
  display.setContrast(50);
  digitalWrite(PULSE_PIN, HIGH);
}


void loop()
{
  trm = pulseIn(PULSE_PIN, LOW, PULSE_TIMEOUT);
  trm = (60 / (trm / 1000000.0)) * 1.2874; // trm=km/h et 1.2874 périmeter de ma roue
  display.clearDisplay();// efface le lcd
  display.println(trm, DEC);
  display.display();// affiche la lettre
  delay(500);

}

Mon soucis arrive là, mon écran Lcd m'affiche des valeurs énorme comme 20540 et ma valeur n'est pas fixe elle varie très souvent!

Je pense que mon équation est bonne et j'ai pensé à mon capteur à effet hall qui est le suivant:
Capteur à effet hall

Si vous aviez une idée de la ou je m**** je suis preneur, je débute :smiley:

Sinon si j'arrive à réaliser cela pour mon vélo, je voudrais l'implanter dans un longskate que je partagerais avec plaisir :grin:

Bonne soirée, merci d'avance!

Petit Max.

En calculant une moyenne de plusieurs mesures consécutives on stabilise la valeur affichée.

A mon avis l'utilisation de PulseIn pour mesurer le temps entre 2 passages à HIGH du pin sur lequel est branché ton capteur n'est pas la bonne solution.
Avec ton code, PulseIn déclanche le début de la mesure lorsque le pin 2 est à LOW mais par forcement au moment du passage à LOW du pin et arrête la mesure au moment du passage à HIGH du pin 2. Tu peux/as donc probablement un démarrage de la mesure du temps en cours de cycle. La durée mesurée est donc bien inférieure à la réalité et donc ta vitesse beaucoup plus importante.
ex :

| |____| |
| |
| fin de la mesure
début de la mesure

Tu devrais plutot utiliser les interruptions pour mesurer le temps entre 2 valeurs HIGH du pin 2.

Bonjour,

Merci de votre aide :slight_smile:

Bigben99, impossible de trouver de bon renseignements sur les interrupteurs avec mon projet! Je galère vachement avec les interrupteurs et ça complique énormement le code non ?

J'ai essayé de m'inspirer de ce code suivant mais je suis cuis, j'y arrive pas :s

//calculations
//tire radius ~ 13.5 inches
//circumference = pi*2*r =~85 inches
//max speed of 35mph =~ 616inches/second
//max rps =~7.25

#define reed 2//pin connected to read switch

//storage variables
int reedVal;
long timer;// time between one full rotation (in ms)
float mph;
float radius = 13.5;// tire radius (in inches)
float circumference;

int maxReedCounter = 100;//min time (in ms) of one rotation (for debouncing)
int reedCounter;


void setup(){
  
  reedCounter = maxReedCounter;
  circumference = 2*3.14*radius;
  pinMode(reed, INPUT);
  
  // TIMER SETUP- the timer interrupt allows precise timed measurements of the reed switch
  //for more info about configuration of arduino timers see http://arduino.cc/playground/Code/Timer1
  cli();//stop interrupts

  //set timer1 interrupt at 1kHz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;
  // set timer count for 1khz increments
  OCR1A = 1999;// = (1/1000) / ((1/(16*10^6))*8) - 1
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS11 bit for 8 prescaler
  TCCR1B |= (1 << CS11);   
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
  
  sei();//allow interrupts
  //END TIMER SETUP
  
  Serial.begin(9600);
}


ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz to measure reed switch
  reedVal = digitalRead(reed);//get val of A0
  if (reedVal){//if reed switch is closed
    if (reedCounter == 0){//min time between pulses has passed
      mph = (56.8*float(circumference))/float(timer);//calculate miles per hour
      timer = 0;//reset timer
      reedCounter = maxReedCounter;//reset reedCounter
    }
    else{
      if (reedCounter > 0){//don't let reedCounter go negative
        reedCounter -= 1;//decrement reedCounter
      }
    }
  }
  else{//if reed switch is open
    if (reedCounter > 0){//don't let reedCounter go negative
      reedCounter -= 1;//decrement reedCounter
    }
  }
  if (timer > 2000){
    mph = 0;//if no new pulses from reed switch- tire is still, set mph to 0
  }
  else{
    timer += 1;//increment timer
  } 
}

void displayMPH(){
  Serial.println(mph);
}

void loop(){
  //print mph once a second
  displayMPH();
  delay(1000);
}

Si vous pouviez me faire un petit boost, petit aide, ce serait super cool, merci beaucoup!

pulsuIn ne mesure pas la période complète du signal mais la période à l'état haut ou la période à l'état bas ce qui n'est pas adapté au besoin.

Il faudrait générer une interruption au passage de l'aimant devant le capteur et mémoriser la valeur de micro() au moment de l'interruption pour calculer le temps écoulé depuis l'interruption précédente.

J'edit ce message car j'ai peut être trouvé une solution mais ce n'est pas encore ça. En effet, comme vous me l'avez conseillé j'utilise maintenant des interruptions et voici le code:

//Mesure du nombre de tours avec capteur à effet Hall + aimant.
//Ce programme mesure le temps passé pour effectuer 1 tours ( 1 fronts montants du capteur) et l’envoi au PC. Premiere valeur faussée?
//Capteur sur pin 2 et pull up interne sur pin 2 activé.
//Capteur à effet Hall US5881LUA 22/09/2012
volatile byte cpttours;        		 // compage tours 
unsigned int tp_ms ;             	 	 // Temps en ms 
unsigned long tempsprec;   		 // Time précédent 
//unsigned long rpm; 


void setup()                      		 //Setup 
{ 
Serial.begin(9600);                   	 // Init liaison serie
attachInterrupt(0,Int0, RISING);      	 // Init interruption 0
digitalWrite(2, HIGH);                 	 // Pull up sur broche 2
cpttours = 0;                         	 	 // Raz cpttours 
tp_ms = 0;                             		 // Raz tp_ms 
tempsprec = 0;                         	 // Raz tempsprec 
}  
void loop()                           		// Boucle
{  
if (cpttours >= 1)               		// Si cpttours >= 2  
{                    			 
tp_ms = (millis() - tempsprec); 	// Temps écoulé
tempsprec = millis();                  	// Copie millis() dans tempsprec 
cpttours = 0;   
//tp_ms = (1/tp_ms)*60;	 
//Serial.write(2);			// Start of text
Serial.println(tp_ms, DEC);			// Envoi temps en ms 
//Serial.write(3);			// End of text
} 
}
void Int0 ()                          	 	// Interruption
{
cpttours++;                        	    	// Increment cpttours
}

Cela m'affiche le temps en ms (dans les 300ms pour faire un tour avec un aimant accroché sur un tournevis lui même accroché sur une visseuse électrique.
Sauf que quand je rentre la formule tp_ms = (1/tp_ms)*60; pour m'afficher les tr/min mais ca me met tous le temps 0!

Bigben, est-ce que je susi dans la bonne voie au moins :slight_smile: ?
Merci à vous en tout cas!!

Pour les interruptions, il faut regarder du coté de la fonction attachInterrupt(interrupt, ISR, mode).

// en branchant le capteur sur le pin 2

volatile long lastTime;
volatile long period = 0;

void setup() {
  attachInterrupt(0, highTime, RISING);
}

void loop() {
  if(period > 0) {
    // calcul de la vitesse par rapport à la valeur de la variable period
  }
}

void highTime() {
  long time;

  time = millis();
  period = lastTime - time
  lastTime = time
}

A chaque passage de LOW à HIGH (RISING), l'interruption sur le pin 2 sera activée et la méthode highTime sera exécutée. La méthode effectue une prise de temps et le calcul du temps écoulé depuis la dernière prise de temps. Tu n'as plus qu'à utiliser la variable period (en ms) pour calculer ta vitesse.

[Edit] Oui, tu es dans la bonne voie

Je commence un peu à comprendre ce qu'il se passe avec les interruptions, c'est juste une histoire d'enregistrer le temps entre deux RISING c'est ça!

Du coup je suis repartis de ton code (merci) et tu as tout fais en fait?

//Mesure du nombre de tours avec capteur à effet Hall + aimant.
//Ce programme mesure le temps passé pour effectuer 1 tours ( 1 fronts montants du capteur) et l’envoi au PC. Premiere valeur faussée?
//Capteur sur pin 2 et pull up interne sur pin 2 activé.


      		
unsigned int tp_ms ;             	 	
volatile long lastTime;
volatile long period = 0;		

void setup()                      		
{ 
  Serial.begin(9600);    
  attachInterrupt(0,highTime, RISING);      	 // Init interruption 0
  digitalWrite(2, HIGH);                 	 // Pull up sur broche 2
  tp_ms = 0; 
}  


void loop()                           		
{  
  if (period > 0)               		
  {   
    tp_ms = (1/period)*60; 
    Serial.println(tp_ms, DEC);			
  } 
}


void highTime ()                          	 	
{
  long time;
  time = millis();
  period = lastTime - time;
  lastTime = time ;                      	    	
}

Bon cela ne m'affiche rien mais normalement c'est ça ?

hum... je ne comprends pas le calcul que tu fais pour alimenter tp_ms. A quoi correspond cette variable ? Si cela correspond au temps en milliseconde d'une période, tu as déjà cette information dans période.

Quoi qu'il en soit, tes variables sont déclarées en int et tu commences ton calcul par 1 / period donc un réel inférieur à 1 donc c'est normal que tu ne vois pas grand chose. En toute logique tu ne devrais avoir que des 0.

Le calcul c'est pour avoir la fréquence donc 1/périod et si je multiplie ça par 60 je l'ai en tour/ minutes.

Oui oui j'ai corrigé la déclaration de tp_ms en regardant dans mes cours en double mais ça ne m'affiche rien à par si je change les déclarations de volatile long...

Pfiou, ca marche pas d'un coté, ça marche pas de l'autre muarf, je suis un boulet, désolé et merci de ton aide en tout cas!

pourquoi calcules-tu une fréquence ? Je croyais que tu voulais une vitesse ? Or tu as un temps (period) et une distance (le périmétre de ta roue) donc tu n'as rien d'autre à faire que le rapport de ta distance au temps pour avoir ta vitesse, non ?

Sinon, essaies d'y aller par étape, vérifie que tu as bien une valeur dans time à chaque fois que tu passes l'aimant devant ton capteur. Puis vérifie la différence et la valeur de périod.

Je crois bien que ça marche :smiley: :smiley: :smiley:

float tp_ms ;             	 	
volatile long lastTime;
volatile long period = 0;		

void setup()                      		
{ 
  Serial.begin(9600);    
  attachInterrupt(0,highTime, RISING);      	 
  digitalWrite(2, HIGH);                 	 
  tp_ms = 0; 

}  


void loop()                           		
{  
  if (period >= 0)               		
  {   
   tp_ms = ((2 * 3.14 * 0.193) / period) * 3600;
   Serial.println(tp_ms, DEC);	
   delay(1000);	
   
  } 
}


void highTime ()                          	 	
{
  long time;
  time = millis();
  period = (time - lastTime);
  lastTime = time ;    	    	
  
}

J'ai inversé period = (lastTime - time); en period = (time - lastTime); pour avoir une période positive!

Ensuite, j'ai period en ms donc pour avoir des km:h j'ai multiplié par 3600!

Pour mon montage tournevis aimant + visseuse je suis a 11km/h je pense que c'est l'ordre de grandeur :slight_smile:

Si tu y vois pas d'erreur, je te remercie énormément (même si tu trouves que c'est pas ça ahah )

Bonne soirée et je vous ferais un post, le projet finit :slight_smile:

Petit max!

En effet, c'est mieux d'avoir une période positive :slight_smile:

Bonjour à tous les arduineurs en ligne sur ce post que je me permets de déterrer après quelques mois de repos.
j'ai effectué le montage et injecté le code, mais j'obtiens des données erronées. Pire, lorsque je retire le capteur du breadboard, j'ai toujours les même valeurs et lorsque je "stimule" le capteur avec un aimant, sa led s'allume, mais l'affichage ne varie pas...
A votre avis, d'où peut venir le problème ?
merci à vous d'avance

Bonjour,

Si tu nous montrais ton montage et ton code exact, on serait sans doute plus à même de t'aider.