Arduino timers

I have a project where I want to use Arduino timers interrupt.
I read the documentation for these timers and saw I can use them on CTC mode (compare).
The compare value is stored on the register OCRnA.
I would like to have multiple compare values.
For example: when the count reaches Value1, trigger output 0, keeps counting up, when it reaches value 2, trigger output 1, keeps counting and when it reaches value 3 trigger output 2 for example.
How to do this?
Thanks

The ISR needs to re-program the compare register on-the-fly. This is done all the time to create complex timing. I do it to drive stepper motors with programmed acceleration/deceleration curves.

abdelhmimas:
The compare value is stored on the register OCRnA.
I would like to have multiple compare values.
For example: when the count reaches Value1, trigger output 0, keeps counting up, when it reaches value 2, trigger output 1, keeps counting and when it reaches value 3 trigger output 2 for example.

Start by drawing a timing diagram. Show the state of each output pin and what time they change state.

What do you mean by "trigger output"? Do you mean 'turn a pin on'? If so, when does the pin turn off?

Is this pattern to be repeated at a fixed frequency? Does it require a specific frequency or will some fairly close frequency work?

Are there any timings that you need to change on the fly?

Depending on the complexity you may want to use an Arduino MEGA where the timers have three Output Compare Registers instead of just two like on the UNO.

Thank you,
Yes trigger the output is turn it on, it can be turned off some ms after or after a certain count.
I must use the external pin for pulses input to be counted, which actually is coming from a shaft incremental encoder. The frequency can change.
If you can post the code you made it would be great.
Here is an example:
Counter is set on CTC mode.
The counter starts counting the external pulses, when the value reaches the OCRn value (let’s say 200), output 1 is turned ON, but I don’t want the counter to be reset to 0. So let’s say at count 250, turn the output 1 OFF. at count 350 for example, turn the output 2 ON and at 400 turn it OFF. At count 500, do the same thing with output 3 and reset the count to start over.
Thanks

Ray, can you send some code sample you did?
Thanks

What I did was on the newer ATtiny processors, which have different timers, so it would not help much.

please see the attached diagram.
v1,v2 and v3 are the values to compare the counter to.
outputs 1 to 3 are the outputs ports.
Thanks

abdelhmimas:
The counter starts counting the external pulses, when the value reaches the OCRn value (let’s say 200), output 1 is turned ON, but I don’t want the counter to be reset to 0. So let’s say at count 250, turn the output 1 OFF. at count 350 for example, turn the output 2 ON and at 400 turn it OFF. At count 500, do the same thing with output 3 and reset the count to start over.

Unless your encoder is producing over a million pulses per second it is not at all necessary to use a hardware counter. I would use one of the two External Interrupt pins (2 or 3) and do everything in the Interrupt Service Routine.

const byte EncoderPin = 2;


const byte OutputAPin = 4;
const byte OutputBPin = 5;
const byte OutputCPin = 6;


unsigned EncoderCount = 0;


void setup()
{
  Serial.begin(115200);
  while (!Serial) {} // So it works on Leonardo/Micro


  pinMode(EncoderPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(EncoderPin), EncoderPulse, RISING);
}


void EncoderPulse()
{
  EncoderCount++;


  if (EncoderCount == 200)
  {
    digitalWrite(OutputAPin, HIGH);
  }
  else if (EncoderCount == 250)
  {
    digitalWrite(OutputAPin, LOW);
  }
  else if (EncoderCount == 350)
  {
    digitalWrite(OutputBPin, HIGH);
  }
  else if (EncoderCount == 400)
  {
    digitalWrite(OutputBPin, LOW);
  }
  else if (EncoderCount == 500)
  {
    digitalWrite(OutputCPin, HIGH);
    EncoderCount = 0;
  }
  else if (EncoderCount == 50)
  {
    digitalWrite(OutputCPin, LOW);
  }
}

void loop() {}

(I would actually use a “switch/case” statement instead of the string of “if/else” statements but many people aren’t familiar with it.)

Thank you very much for your advice.
made things clear to me. The only thing I need is to reset the counter somewhere.

abdelhmimas:
Thank you very much for your advice.
made things clear to me. The only thing I need is to reset the counter somewhere.

See:

  else if (EncoderCount == 500)
  {
    digitalWrite(OutputCPin, HIGH);
    EncoderCount = 0;
  }

You said: "At count 500, do the same thing with output 3 and reset the count to start over." By "do the same thing" I took it to mean "turn on the output pin and turn it off 50 counts later". Since the counter has been reset to zero, 50 counts later is 50:

  else if (EncoderCount == 50)
  {
    digitalWrite(OutputCPin, LOW);
  }

I tried the code you sent to me but it ended up to be more complicated than I thought.
Please see the attached picture.
P1 and P2 are products coming on a conveyor
PE is photo eye detector that detects these products connected to interrupt input on arduino
M1 to M3 are connected to the outputs we want to fire consecutively and different counts.
we also have an encoder that reads the conveyor movement.
the problem I have is that the distance between two products P1 and P2 for example are smaller than distance from the PE to M3.
one cycle is not finished before there is another product coming.
Any help?
Thank you

arduino_question.jpg

arduino_question.jpg

abdelhmimas:
P1 and P2 are products coming on a conveyor
PE is photo eye detector that detects these products connected to interrupt input on arduino

So it's a sortation application?

Yes, kind off.
Tried to read the timer counter registers in the main loop but it is missing counts.

What is the frequency of encoder pulses?

Once again,

as long as you the rotary-encoder does not create a frequency of 1 MHz (1 million 1.000.000) pulses per second
a software-interrupt solution will work.

Your timing diagram is not clear to me. What does the angled line mean?

Can you please draw a timing-diagram that has example-numbers showing the most difficult case that can occur.
add arrows with numbers on them that show how many pulses occur from step to step.

What I try to conclude is:

Product P1 is detected by PE product P1 is identified to fire M1
this means the program has to take a snapshot of a counter that represents the moving of "the line"

if (snapshot[index] != 0) // unequal to zero means array-element is in use
if (currentCounter- snapshot[index] is >= Distance_to_M1) then fire M1
if (currentCounter - snapshot[index] is >= Distance_to_M2) then fire M2
if (currentCounter - snapshot[index] is >= Distance_to_M3) then fire M3

if you use an array to store the snapshots you can loop through P1, P2, P3 etc. so each product P1, P2, P3 has its own snapshots you compare against currentCounter

Whenever a product is behind M3 the array-element is cleared to zero to indicate "job of this product is finished"
if array-index reaches max reset array-index back to 0

your array should have a number of elements that the first product P0 is "finished" before all array-elements are in use

This means the counter-snapshot of array-element zero is no longer neeeded if the job for P0 is "finished"

there still might be array-element 1, 2, and 3 "in use" because P1, P2, P3 are not yet "finsihed" but array-element 0 is "free again" so the array-element with index 0 can be used to store new snapshot of P4 passing PE

This is the same as working with the timer-fucntion millis() but for counts.

If you use an unsigend variable you don't even have to reset the counter because a rollover to zero is done correctly.

the calculation CurrentCounter - SnapShot >= DistanceTo_M1 is calculated correctly for unsigned int even if the values are

0001 - 64000

which means a rollover to zero has occurred. but the result when using unsigned int is positive because it is unsigned the result will be plus 63999 and this is the reason why it works even in case of a rollover

This is some kind of a circular buffer first in first out

best regards Stefan

thank you,
the arrow is there only to show the direction of the conveyor.
do you have code sample?
where in the code should I put the snapshot comparison?
if I put it in the main program loop, will it be accurate to catch the count at the exact snapshot?
because I only want to fire the outputs for a certain distance.
Thanks

arduino_question.jpg

arduino_question.jpg

the encoder frequency is about 10khz

I have a question How would you describe your programming-skills?
A rough estimation is enough

a) I know how to start the arduino-IDE and how to upload ready to use code
b) I understand the most basic things but I don’t have much programming experience
c) I’m a quite experienced programmer

You are asking for code. No I don’t have code-examples for this. I would have to write code-examples but I will not do this. If I would do it this would end up that I would do all the coding and your coding-skills would stay on a very low level. You would have to ask me again and again how to write this change and that change. You would depend on me.

I give only support that people become more and more independent.

10 kHz can be easily handeled by a interrupt-service-routine in short isr ).
The isr does just counting the pulses.

So it is up to you to write a first attempt how the rotary-encoder counts up a variable.
google for it. write the code and click the compile-button. It doesn’t matter if it does not compile.
Every journey starts with the first step. If any kind of concrete questions arises post the question.

I have some questions to gain a better understanding of your application:

How fast does the conveyor-belt move in meters per second?

How much accuracy do you need for firing M1, M2, M3?

How does the real machinery look like?

What happends if you don’t fire M1, M2, M3 at the exact middle of the product?

How much deviation is tolerable for reliable function?

best regards Stefan

Thanks Stefan,
The speed is 600ft per minute maximum (it varies the reason to have an encoder).
Must have a decent accuracy.

“decent accuracy” is a very unaccurate and unprecise description of the required accuracy.

600 feet / minute is equal to 3 m / second. That is quite fast.
If your real application is a secret keep it a secret. But then don’t expect further support on the forum.

It highly depends on

  • the required accuracy
  • the maximum and the minimum-speed of the conveyor-belt
  • the speed of the “pushers” M1, M2, M3,
  • the min and the max distance between “pushers” and P1, P2, P3

how much coding has to be done and how much adjusting has to be done in timing on the fly to make it work reliably

So I emphasise on posting a project-overview and a lot of pictures
that show the specs listed above.

If all this is a secret and you want it to stay secret you have to examine it yourself and then post much much more specific questions how to do this or that detail.

best regards Stefan