Multiple encoder

I want to use 2 rotary encoder to logging 2 axles which supporse to spinning in different speed.
Is it possible on my Arduino uno board?

I wanba use "attachInterrupt" function for this.

Yes.

How?
could you tell me detail?

Detail depends on details, as per:

What encoders? What interrupts do you want to attach? How fast will things turn? What will your program do with the information?

Try writing your ideas in code, as per:

I don't know about specific information or datasheet for my encoder because I took it from junk optical mouse, but it worked when I use one.
In theory, both my axles will turn at roughly 3000 rpm at maximum, but I think it won't reach such speed in real life.

and here is my code for twin encoder setup. sorry for random Japanese function name.

#include <SPI.h>

#include <SD.h>

#include <STDIO.h>


const int A_pin = 2;
const int B_pin = 3;
int count = 0;
int count_B = 0;
const int chipselect = 4;
String zikoku;
float zikan;
String Timestamp="Timestamp";
String value = "Value";
String dataString="";
const int Light_Red = 9;
const int Light_Green = 8;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(Light_Red, OUTPUT);
  pinMode(Light_Green, OUTPUT);
  digitalWrite(Light_Green, LOW);



  digitalWrite(Light_Red, HIGH);
  Serial.print("Initializing SD");
  // see if the card is present and can be initialized:
  if (!SD.begin( chipselect )) {
  
    Serial.print("Card failed,");
    
    Serial.print("or not present");
    // don't do anything more:
    while (1);
  }
  
  Serial.print("card initialized.");


  dataString+="Timestamp";
  dataString+=",";
  dataString+="value";
  dataString+=",";

  File dataFile = SD.open("DATALOG.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
  }
  dataString="";
  digitalWrite(Light_Red, LOW);

  //ć‚Øćƒ³ć‚³ćƒ¼ćƒ€ć®å‰²ć‚Šč¾¼ćæ処ē†
  pinMode(A_pin,INPUT);
  pinMode(B_pin,INPUT);
   attachInterrupt(digitalPinToInterrupt(A_pin), pulse_counter , CHANGE);
 

}

void loop() {
  // put your main code here, to run repeatedly:


   
 zikan = millis();
 zikoku = String(zikan);

 dataString += zikoku;
  dataString += ",";
  dataString += String(count);
  dataString +=",";
  dataString += String(count_B);
  dataString +=",";
  
   File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
  }
  else{
    Serial.println("Data is not ready!");
  }


  delay( 200 );
  dataString="";
}

void pulse_counter() {
  digitalWrite(Light_Green, HIGH);

    count++;
    attachInterrupt(digitalPinToInterrupt(B_pin), pulse_counter_B , CHANGE);

   Serial.println(count);
   digitalWrite(Light_Green, LOW);
}

void pulse_counter_B() {
  count_B++
}

How are the dual encoders attached to the Uno? I only see two encoder pin inputs in that code. Are they both attached to the same encoder?

This suggest detailing the connections with a schematic:

From the code it looks like the counting is only counting up. Is that good enough for speed? If you don't need actually direction information counting up is simpler and quicker.

Does the code compile? I see that a semicolon is missing within the pulse_counter_B() routine.

I'd move this line out of the pulse_counter() function and into setup() because it doesn't actually change anything after the first invocation:

You also should not print within the interrupt service routine, since it can cause problems.

Alse, since count and count_B are set within interrupt service routines, when they are used elsewhere, you should make a safe copy that won't be corrupted if it happens to be changed while it is being used:

   noInterrupts();
   int safe_count = count;
   int safe_count_B = count_B;
   interrupts;

And with speeds like 3000 RPM and an encoder with 10 slots (20 CHANGES/rev) it would overflow an int in 32767/(3000*10*2)=0.27 minutes. You should probably use "long" or "unsigned long" declarations for your counters.

How are the dual encoders attached to the Uno?
From the code it looks like the counting is only counting up. Is that good enough for speed?

Yes. I want to masure speed, so I only need 1 input per encoder and count up.

Does the code compile? I see that a semicolon is missing within the pulse_counter_B() routine.

Thanks to note that. I've added it.

I'd move this line out of the pulse_counter() function and into setup() because it doesn't actually change anything after the first invocation:
You should probably use "long" or "unsigned long" declarations for your counters.

I'll do that.

you should make a safe copy that won't be corrupted if it happens to be changed while it is being used:

Alright. but where to add this?

noInterrupts();
   int safe_count = count;
   int safe_count_B = count_B;
   interrupts;

You would use that before you needed the counts. For example:

void loop() {
  zikan = millis();
  zikoku = String(zikan);
  noInterrupts();
  int safe_count = count;
  int safe_count_B = count_B;
  interrupts;

  dataString += zikoku;
  dataString += ",";
  dataString += String(safe_count);
  dataString += ",";
  dataString += String(safe_count_B);
  dataString += ",";

  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
  }
  else {
    Serial.println("Data is not ready!");
  }
  delay( 200 );
  dataString = "";
}

I've built both hardware and software, and here's some issue.

1.interrupts; in your code causes error. message reads: 'interrupts' was not declared in this scope

2.Run the program and turn axles, results in csv file is static number for all Timestamp and both values (as screenshot attached).

what is wrong with me? (loging dulation (delay()) is shorten for 10ms.)

Iā€™m sorry. Interrupts is a function and I should have typed

   interrupts();

as in

void loop() {
  zikan = millis();
  zikoku = String(zikan);
  noInterrupts();
  int safe_count = count;
  int safe_count_B = count_B;
  interrupts();

  dataString += zikoku;
  dataString += ",";
  dataString += String(safe_count);
  dataString += ",";
  dataString += String(safe_count_B);
  dataString += ",";

  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
  }
  else {
    Serial.println("Data is not ready!");
  }
  delay( 200 );
  dataString = "";
}

Are you still printing in the interrupt?

What is your current code that's giving you the problematic output?

1 Like

After some experiment, all error is gone.
Huge thank you, Dave!

1 Like