Help code read encoder

Hello,
So I have a problem I'm trying to read an encoder for a science project where I need to read the speed of my DC motor to calculate its torque constant.
I have tried several programs but it always sends incoherent values, here is the program:
int pinA = 2;
int pinB = 4;
volatile int pos = 0;
volatile unsigned long t = 0;

void setup() {
Serial.begin(9600);
Serial.println("Codeur incremental");
pinMode(pinA, INPUT);
attachInterrupt(0, front, CHANGE);
t = micros();

void loop() {
delay(1);
}

void front() {
pos++ ;
volatile float vit = pos/t ;
Serial.print(pos);
Serial.print("\t");
Serial.println(vit);

}

it just goes 1 then 2 and so on but really slowly, it changes number every 2 seconds .
I'm really new at arduino so i would really like some help thanks! :smiley:

Never, ever do Serial I/O in interrupt context, unless you REALLY know what you're doing.

Please remember to use code tags when posting code.

service-interrupt-routines should run through as fast as possible.
printing to the serial output slows down too much. especially at a slow baudrate of 9600 baud. But even if you would change the baudrate to 2.000.000 baud you should not do serial output in the interrupt-service-routine.

Some time ago I googled for a good example on how to use interrupts. I found 90% really bad example-codes because they did serial output inside of the interrupt-routine.

some basic information can be found here
https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/

https://learn.sparkfun.com/tutorials/processor-interrupts-with-arduino/all

a "professional" use of interrupts is:

increment a variable that is defined as "volatile" or set a boolean-flag
then do all the rest outside the interrupt-service-routine

For measuring rpm there are different libraries that can measure rpm.
depending on the rpm that shall be measured there are two different concepts

low rpm: measure time between two pulses
high rmp: count pulses within 1 second.

So what is the range of rpms that you want to measure?

addition:
You should post code by using code-tags
There is an automatic function for doing this in the Arduino-IDE
just three steps

  1. press Ctrl-T for autoformatting your code
  2. do a rightclick with the mouse and choose "copy for forum"
  3. paste clipboard into write-window of a posting

best regards Stefan

SO the problem comes from the Serial lines, but how can I have a display of the values without creating problems for the interrupt?

P.S I'm sorry i didn't know about the code tags but it sure is prettier.

Thanks a lot for the links!
In my case it should be high rpm since it's around the rpm of a drill.
P.S thanks for the tip for the code tags

Well, "pos" is an int, which means it consists of two bytes on the AVR platform, so it cannot be read atomically.

You need to disable interrupts, copy the value of "pos", reenable interrupts, then print the copy.
Do this in "loop".

I know it's the basics but i don't know if in "loop" i need to reenable the interrupt after disabling the interrupt and copying the value of "pos" or is the setup part read after every loop?

the basic concept just is increment a variable inside the isr
then disabling the interrupts
copying the value of the isr-incremented variable to another variable
and then use this seond variable to print outside the isr

disabling the interrupt is nescessary because copying more than one byte needs multiple processor-cycles and inbetween copying the two bytes of an integer-value the next interrupt could occur who would change your isr-variable in the middle of the copying-process and then the copied value would be wrong.

You can find a lot of material with googling "arduino" + your keywords of interest

This link shows the principle

best regards Stefan

Hello again,
So i've looked at the link you sent me and i thought i understood but it seems i haven't. Here's the code i've come to write:

int pinA = 2;
volatile int pos = 0;
unsigned long measureTime = 0;

void setup()  {
  Serial.begin(9600);
  Serial.println("Encoder");
  pinMode(pinA, INPUT);
  attachInterrupt(0, front, CHANGE);
}

void loop()   {
  delay(1000);

  noInterrupts();
  volatile int pos1 = pos ;
  volatile float spd = pos1 * 1000 / (16 * (millis() - measureTime)) ;
  pos = 0;
  measureTime = millis();
  interrupts();


  Serial.print("position");
  Serial.println(pos1);
  Serial.print("speed:");
  Serial.println(spd);

}

void front()   {
  pos++ ;
}

So in my encoder there's supposed to be 16 counts per revolution and the "pos" variable refers to those counts, it always sends out a minimum of a 100 for the pos even when i don't make the motor rotate, but the value when spinning the shaft looks good.
The speed value is also incoherent, when the motor is stopped it sends me a really high value (around 268000) and when it rotates sometimes it sends me 0 or 1 or around 268000.
So if you have the time could you look at my code and look if i have made any errors?
Thank you in advance!

These variables do not need to be qualified as volatile.

Try tacking on a ".0" to the "1000" - I think you're suffering from integer arithmetic overflow.

Thank you so much it solved it! You're saving me!

Hi Lydie,

there is another thing to improve:
he command delay() is blocking. Nothing else can be executed while a delay() is executed.

There is another non-blocking way to do timing and timed action which are based on the function millis().

There is a more or less "standard"-tutorial about millis() but it has a flaw.
this "standard"-tutorial has no everyday-example that would show the principle in detail.

here is the everyday example
as an everyday example with easy to follow numbers
delay() is blocking. As long as the delay is "delaying" nothing else of the code can be executed.
Now there is a technique of non-blocking timing.
The basic principle of non-blocking timing is fundamental different from using delay()

You have to understand the difference first and then look into the code.

otherwise you might try to "see" a "delay-analog-thing" in the millis()-code which it really isn't
Trying to see a "delay-analog-thing" in millis() makes it hard to understand millis()
Having understood the basic principle of non-blocking timing based on millis() makes it easy to understand.

imagine baking a frosted pizza
the cover says for preparation heat up oven to 200°C
then put pizza in.
Baking time 10 minutes

You are estimating heating up needs 3 minutes
You take a look onto your watch it is 13:02 (snapshot of time)
You start reading the newspaper and from time to time looking onto your watch
watch shows 13:02. 13:02 - 13:02 = 0 minutes passed by not yet time
watch shows 13:03. 13:03 - 13:02 = 1 minute passed by not yet time
watch shows 13:04. 13:04 - 13:02 = 2 minutes passed by not yet time

watch shows 13:05 when did I start 13:02? OK 13:05 - 13:02 = 3 minutes time to put pizza into the oven

New basetime 13:05 (the snapshot of time)
watch 13:06 not yet time
watch 13:07 not yet time
watch 13:08 not yet time (13:08 - 13:05 = 3 minutes is less than 10 minutes
watch 13:09 not yet time
watch 13:10 not yet time
watch 13:11 not yet time
watch 13:12 not yet time
watch 13:13 not yet time
watch 13:14 not yet time (13:14 - 13:05 = 9 minutes is less than 10 minutes
watch 13:15 when did I start 13:05 OK 13:15 - 13:05 = 10 minutes time to eat pizza (yum yum)

You did a repeated comparing how much time has passed by
This is what non-blocking timing does

In the code looking at "How much time has passed by" is done

currentTime - startTime >= bakingTime

bakingTime is 10 minutes

13:06 - 13:05 = 1 minute >= bakingTime is false
13:07 - 13:05 = 2 minutes >= bakingTime is false
...
13:14 - 13:05 = 9 minutes >= bakingTime is false
13:15 - 13:05 = 10 minutes >= bakingTime is TRUE time for timed action!!

So your loop() is doing

void loop()
// doing all kinds of stuff like reading the newspaper

if (currentTime - previousTime >= period) {
previousTime = currentTime; // first thing to do is updating the snapshot of time
// time for timed action
}

it has to be coded exactly this way because in this way it manages the rollover from Max back to zero
of the function millis() automatically

baldengineer.com has a very good tutorial about timing with function millis() too .

There is one paragraph that nails down the difference between function delay() and millis() down to the point:

The millis() function is one of the most powerful functions of the Arduino library. This function returns the number of milliseconds the current sketch has been running since the last reset. At first, you might be thinking, well that’s not every useful! But consider how you tell time during the day. Effectively, you look at how many minutes have elapsed since midnight. That’s the idea behind millis()!

Instead of “waiting a certain amount of time” like you do with delay(), you can use millis() to ask “how much time has passed”?

best regards Stefan

Apart from the interrupts.

Thanks guys you've really helped me it has been a pleasure getting help from you!