Encodeur rotatif

Bonjour,
Je souhaite utiliser un encodeur rotatif avec une plage choisi (de 0 à 200 par ex.) avec des incréments qui peuvent varier. Je suis tombé sur un exemple de la librairie de Matthias Hertel (RotaryEncoder-LimitedRotator) que je souhaiterai upgrader en changeant l'incrément à partir d'une certaine valeur, seulement je n'y arrive pas.
Par exemple je souhaite que ma valeur s'incrémente de 0.1 entre 0 et 10, puis de 0.5 de 10 à 20 puis de 1 de 20 à 200
Avez-vous des solutions à me proposer?

Ci-dessous le code que je souhaite upgrader.

// LimitedRotator.ino - Example for the RotaryEncoder library.
// This class is implemented for use with the Arduino environment.
//
// Copyright (c) by Matthias Hertel, http://www.mathertel.de
// This work is licensed under a BSD 3-Clause License. See http://www.mathertel.de/License.aspx
// More information on: http://www.mathertel.de/Arduino
// -----
// 26.03.2017 created by Matthias Hertel
// 06.02.2021 conditions and settings added for ESP8266
// -----

// This example checks the state of the rotary encoder in the loop() function.
// The current position is printed on output when changed.
// In addition to the SimplePollRotator example here the range of the rotator is limited to the range 0 - 16 and only incremental steps of 2 are realized.
// To implement this limit the boundaries are checked and eventually the current position is adjusted.
// The internal (physical) position of the rotary encoder library remains by stepping with the increment 1
// so the the logical position is calculated by applying the ROTARYSTEPS factor.

// Hardware setup:
// Attach a rotary encoder with output pins to A2 and A3.
// The common contact should be attached to ground.

#include <Arduino.h>
#include <RotaryEncoder.h>


// Example for Arduino UNO with input signals on pin 2 and 3
#define PIN_IN1 4
#define PIN_IN2 3


#define ROTARYSTEPS 0.1
#define ROTARYMIN 0
#define ROTARYMAX 200

// Setup a RotaryEncoder with 4 steps per latch for the 2 signal input pins:
// RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::FOUR3);

// Setup a RotaryEncoder with 2 steps per latch for the 2 signal input pins:
RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);

// Last known rotary position.
float lastPos = -1;

void setup()
{
 Serial.begin(115200);
 while (! Serial);
 Serial.println("LimitedRotator example for the RotaryEncoder library.");
 encoder.setPosition(10 / ROTARYSTEPS); // start with the value of 10.
} // setup()


// Read the current position of the encoder and print out when changed.
void loop()
{
 encoder.tick();

 // get the current physical position and calc the logical position
 float newPos = encoder.getPosition() * ROTARYSTEPS;
 
 if (newPos < ROTARYMIN) {
   encoder.setPosition(ROTARYMIN / ROTARYSTEPS);
   newPos = ROTARYMIN;

 } else if (newPos > ROTARYMAX) {
   encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
   newPos = ROTARYMAX;
 } // if

 if (lastPos != newPos) {
   Serial.print(newPos);
   Serial.println();
   lastPos = newPos;
 } // if
} // loop ()

// The End 

D'avance merci :slight_smile:

Bonjour azothys

Oui :wink:

Tu changes :

#define ROTARYSTEPS 0.1
en
float ROTARYSTEPS = 0.1;

et dans loop() tu ajoutes:

	if (newPos <= 10)
	{
		ROTARYSTEPS = 0.1;
	} 
	else if (newPos <= 20)
	{
		ROTARYSTEPS = 0.5;
	}
	else
	{
		ROTARYSTEPS = 1.0;
	}

Cordialement
jpbbricole

J'ai récemment décidé d'utiliser un encodeur rotatif.
J'en avais un au fond d'un tiroir, modèle marqué KY-40.
J'avais lu que c'était de piètre qualité : après essais, je confirme, c'est une vraie bouse avec un jeu mécanique effroyable.

Mise au point : on parle de KY-40 et d'EC11 ou EC12.
Cela ne veut rien dire.

  • KY-40 n'est que la référence du circuit imprimé, on ne connait pas la référence de l'encodeur qui y est monté.
  • EC 11 n'a pas plus de signification que NEMA 17. Le chiffre 11 représente la dimension d'un côté du carré. En fait c'est 11,8 mm.
    De même il existe des EC12 (12,8 mm), EC14 (14,8 mm), EC16 (16,8 mm)..

Ce qui compte, c'est le nom du fabricant. A des prix abordables, il n'y a pas beaucoup de chance de trouver des produits ALPS ou BOURNS (j'ai un doute sur l'orthographe).

J'ai approvisionné d'autres encodeurs sur Aliexpress. Aucun soucis, très peu de jeu et des crans bien marqués.

Je n'ai pas utilisé de bibliothèques, j'ai fait un tour d'horizon et j'ai surtout bien analysé les chronogrammes trouvés dans la documentation ALPS.
Je n'ai aucune confiance dans les bonimenteurs youtube et je sais que les fabricants professionnels de composants fournissent tous une documentation sérieuse.

Bien évidement j'ai regardé les codes publiés sur internet et pour certains, je m'en suis en partie inspiré.

J'ai développé un programme pour nano (je recherchais la tension 5 V) et utilisé platform IO.
J'utilise une interruption directe sur pin.
J'utilise aussi digitaWriteFast.h, le temps passé dans une interruption devant être le plus court possible.

Que fait le code de l'exemple qui suit :
Quand on tourne l'axe de l'encodeur, on augmente ou on diminue la valeur d'un compteur.
J'utilise ce compteur pour modifier le rapport cyclique d'une sortie PWM (MLI en français).
Un circuit RC sur cette sortie et je mesure la valeur de la tension filtrée que j'affiche dans un moniteur série, celui de l'IDE ou un utilitaire comme "cutecom".

Le code :

#include<Arduino.h>
#include"digitalWriteFast.h"

#define A 2
#define B 3
#define p_mli 11

#define pwmWrite analogWrite

//volatile uint8_t A_actuel ;
volatile uint8_t A_actuel ;  
volatile uint8_t A_prec   ;
volatile uint8_t B_actuel ;  //mesuré dans l'interuption
  
volatile bool A_drapeau ;
volatile bool A_verrou  ;

int16_t compteur ;

uint16_t lecture = 0;
float v ;


void mli()    ;
void ISR_A()  ;   // actif sur FALLING

void setup()
{
   Serial.begin(115200);
   pinMode(A, INPUT) ;
   pinMode(B, INPUT) ;
   pinMode(p_mli, OUTPUT);

   A_prec = digitalReadFast(A) ;
   A_drapeau = false ;
   compteur  = 0 ;
   mli();
   Serial.print("Compteur = ");Serial.print(compteur); Serial.print("\tC.A.N. = ");Serial.println(analogRead(A0));
   
   attachInterrupt(digitalPinToInterrupt(A), ISR_A, FALLING)  ;
}

void loop()
{
   if (A_drapeau)
   {  
      if(B_actuel==1) compteur += 10 ;
      else compteur -= 10 ;
      //*******************************************************************
      mli();
      delay(200); // Charge du condensateur sur mli

      lecture = analogRead(A0);
      v = 4.74 * lecture/1023.0;
      
      Serial.print("Compteur = ");Serial.print(compteur); Serial.print("\tC.A.N. = ");Serial.print(lecture);
      Serial.print(" V= ") ; Serial.println(v) ;
      //********************************************************************
      A_drapeau = false ;
      A_verrou  = false ; 
   }
}

void mli()
{
   if (compteur <= 0) compteur   = 0;          // contraint l'int16_t à rester dans les limites
   if (compteur >= 254) compteur = 255 ;       // de la PWM
   pwmWrite(p_mli, (uint8_t)compteur) ;
}

void ISR_A()
{    
   if (!A_verrou)
   {
      B_actuel = digitalReadFast(B); 
      A_drapeau = true ;
      A_verrou = true ;
   }  
}

Le verrou est pour empêcher que si on va trop vite, on détecte un passage de cran alors que le traitement du passage du cran précédent n'est pas terminé en cas de loop() trop complexe ou trop lente.
Le verrou activé fait que l'interruption ne fait rien.

Note :

v = 4.74 * lecture/1023.0;

Avec une nano alimenté par l'USB la tension Vcc n'est pas égale à 5 V mais à 5V diminués de la tension de la diode shottky de protection. Les 4,74 V sont une valeur mesurée dans les conditions d'utilisation. Attention, chaque cas d'utilisation est un cas particulier.

Conclusion :
Je ne garantis pas qu'il n'y a pas d'erreur, tout ce que je peux affirmer c'est que je n'ai jamais pu mettre ce code en défaut dans l'application indiquée.

Il existe des encodeurs sans "crans", c'est-à-dire sans position stable, leur gestion est plus complexe.

J'adore !!! :+1:

Tu devrais en faire une bibliothèque, il doit y avoir des amateurs.

Je suis incapable de faire une bibliothèque qui couvre tous les cas possibles, toutes les plateformes possibles.
Et je suis conscient de mes lacunes.

Programmer reste un plaisir pour moi, en aucune façon un pensum.

Merci pour ton message ! J'ai eu un bref espoir...mais ça ne marche pas comme je voudrais. :frowning:
Voila ce que j'obtiens.
image

Ce qui est surligné en bleu et le passage d'un seul cran :confused:

J'avoue que je n'ai pas tout lu, peut tu expliquer a quoi tu veux arriver ?
Le code de @jpbbricole fait ce que tu lui a demandé, il me semble.

En fait, je souhaiterais qu'a chaque cran de mon encodeur une valeur s'incrémente (un valeur qui sera ensuite récuperée plus tard dans un calcul), mais avec quelques specificités.
Que de 0 à 10 la valeur s'incrémente de 0.1 pour un cran, de 10 à 20 de 0.5 pour un cran, et de 20 à 200 de 1 pour un cran.
A savoir que je ne veux pas aller en dessous de 0 ni au dessus de 200.
J'étais parti sur un librairie qui semblait avoir ce dont j'avais besoin (incrément qu'on pouvait modifier avec des valeurs min-max) mais au fur et à mesure du projet j'essaye d'optimiser la chose !

Bonjour azothys

J'ai appliqué ce que je t'indiquais dans le post#2
Essaies ça:


#include <Arduino.h>
#include <RotaryEncoder.h>


#define PIN_IN1 4
#define PIN_IN2 3


float ROTARYSTEPS = 0.1;
//#define ROTARYSTEPS 0.1
#define ROTARYMIN 0
#define ROTARYMAX 200

RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);

// Last known rotary position.
//float lastPos = -1;
float newPos = 0;

void setup()
{
	Serial.begin(115200);
	while (! Serial);
}


void loop()
{
	encoder.tick();

	int encPosition = encoder.getPosition() / 2;     // Chaque cran du codeur = 4 ticks

	if (encPosition != 0)     // Si bouton tourné
	{
		newPos += encPosition * ROTARYSTEPS;     // Chaque cran du codeur = 2 ticks
		encoder.setPosition(0);

		if (newPos < ROTARYMIN) 
		{
		encoder.setPosition(ROTARYMIN / ROTARYSTEPS);
		newPos = ROTARYMIN;
	
		} 
		else if (newPos > ROTARYMAX) 
		{
		encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
		newPos = ROTARYMAX;
		}

		if (newPos <= 10)
		{
			ROTARYSTEPS = 0.1;
		}
		else if (newPos <= 20)
		{
			ROTARYSTEPS = 0.5;
		}
		else
		{
			ROTARYSTEPS = 1.0;
		}		
		
		Serial.println(newPos);
	}
}

N'hésites pas à poser des questions :wink:

A+
Cordialement
jpbbricole

Ok du coup que vient faire la multiplication directe par ta variable ROTARYSTEP.
De même pourquoi tu change le nombre d'incrémentation de ton encoder(setPosition) ?

Peut tu redonner ton code ?
Pourquoi tu ne fais pas simplement la différence entre ta nouvelle position(nombre de cran) et l'ancienne position, que tu multiplie par ton indice d'incrémentation, pour stocker le tout dans un tableau ou un historique de valeur ?

Peux tu aussi afficher plus d'information sur le moniteur série.
Plus il y a d'information, plus tu aura un retour sur ce que tu demande réellement de faire à ton programme.

Ah yes top ! Ca fonctionne comme demandé ! Par contre arrivé à 200 j'ai le moniteur serie qui s'affole et impossible de revenir en arrière. Merci en tout cas ! Ca prend forme :slight_smile:

En fait mes connaissances en programmation sont très très limités :smile: . Du coup j'essaye de faire avec avec des exemples que je peux trouver par ci par la en essayant de l'adapter à mes besoins :smiley:

Très bonne méthode, c'est ainsi que j'ai débuté dans le monde Arduino :wink:

Supprime cette ligne:

		else if (newPos > ROTARYMAX)
		{
			//encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
			newPos = ROTARYMAX;
		}

Oui, j'avais bien compris, c'est pour ça que j'essaye de t'aider à avancer et changer cet état de fait, en te posant des questions sur le fonctionnement de ton programme, pour enlever l'effet magique.
Cela ne serait pas plus sympa que tu arrive a faire ce genre de code seul, que d'être tributaire des autres ? :laughing:

Impeccable ! Que du bonheur ! :smiley:
Merci beaucoup !

Ah si si completement d'accord ! :slight_smile:
J'espère ça viendra avec le temps :smiley:
Merci en tout cas :wink:

Il n'y a pas de raison, à partir du moment que tu t'investi :+1:
SI tu veux que ça ne prenne pas trop de temps, enfin façon de parler, ne te contente pas de prendre du code, en espérant que cela infuse par magie du savoir.
Essaye de faire par toi même et lorsque tu ne trouve pas, viens nous voir, il y aura surement quelqu'un pour te guider :slight_smile:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.