0

Im trying to understand how the Arduino ISR keeps track of timing between pulses stored in a variable, if that variable is latter used.

Say, for example, you have a magnet mounted on a circular object, that passes a reed switch. Using this to trigger the ISR that calls a function that would have something like counts++ in it, then storing that value in a variable.

If that varible is used latter to turn on a motor, for example, according to the count capture, how does the arduino MCU know the freq or timing to output the count or pulses of the magnet passing the reed switch, at the same frequency that the counts were received? For example, a magnet mounted on a 2 inch dia shaft would turn slower past a reed switch than one mounted on a .5 inch shaft, or one could vary the speed of the magnet past the reed as they wish. So how does counter++ keep track of this freq? is it reading the attachinterupt pin (or is the function that is being called, keeping track) or does the ISR time stamp each pulse it receives and store that interval in the declared variable? so when the variable is used again, it has this interval stored in it?

To be more clear, if it takes one second for the magnet to complete one revolution, how does the MCU know it took one second and store this, along with the counts of the revolutions?

Thanks for any help

Jim
  • 31
  • 2
  • 2
  • 9
  • 3
    It doesn't know that. You'd have to code that yourself. You could indeed have the ISR store the millis() value. Even better would be to have the ISR (locally) store the millis() value of the last time the ISR was called. Then when the ISR is called the next time, it could calculate the time that has passed since the last ISR call. If the motor is running faster, this method can get a bit less accurate. In that case you could have the main loop measure the time it takes for the counter to increase by e.g. 20 (i.e. 20 revolutions). The it can calculate the average RPM. – Gerben Jan 08 '18 at 10:45
  • so when people use for ex. the interupt, to call a function, for ex. void Revolutions(){ rev++; }; and then have an if statement with varibles like if { revA = rev; rev=0; to store revolutions, and use that again in another if statement like if revA>rev, analogWrite(motor) the duration of the value stored in revA is not stored? if not, then what is stored? – Jim Jan 08 '18 at 10:51
  • @Jim When people just count revolutions like that they introduce the concept of time at a later stage. For instance, they will look at (and reset) that count once a second, giving the number of revolutions in that one second window, and hence the number of revolutions per second. – Majenko Jan 08 '18 at 10:55
  • "they will look at (and reset) that count once a second, giving the number of revolutions in that one second window, and hence the number of revolutions per second" so your saying the "one second" is an arbutrary value? Im just trying to understand what, for ex. counter++ or rev+1 etc is tied too? the interupt calls the function, then 1,2,3,4.....counts pass, its stored, then output according to what time? – Jim Jan 08 '18 at 11:02
  • perhaps the key thing Im missing is "reset", the interupt is used, calls its function, then resets so that time frame of all the sets/resets corresponds to the amount of total times it took to capture the time you want to turn on a motor, for ex. meaning that if it took 1 minute to capture 500 set/resets, then you could approx. capture that in a variable? – Jim Jan 08 '18 at 11:07
  • The key thing you are missing is that the "time" has absolutely nothing to do with the interrupt. It's elsewhere in the program as is written by the programmer of the sketch. It may be as simple as a delay(1000); in the main loop, or it may be done with millis() in a non-blocking fashion. – Majenko Jan 08 '18 at 11:08
  • yes, Ive seen it done in a sketch, without a delay or millis in the interupt function that is called – Jim Jan 08 '18 at 11:13

1 Answers1

1

All the interrupt does is count. It has no concept of time. For instance:

volatile uint32_t revolutions = 0;
void count() {
    revolutions++;
}
....
attachInterrupt(0, count, FALLING);

will just count up 1 every time the interrupt triggers.

To be able to convert that count into something meaningful you have to manually introduce the concept of time - that is, the count of "revolutions" (for example) between two points in time. And it's up to your sketch to implement that.

The simplest way may be:

// For anything more than an 8 bit value on an 8 bit machine
// make a critical section to save and reset the count
cli();
uint32_t savedResolutions = revolutions;
revolutions = 0;
sei();

Serial.print(savedRevolutions);
Serial.println(F(" revolutions per second"));

// Introduce the concept of time - this will
// make it get the count once a second.
delay(1000);

Of course, instead of delay() you can use millis() in much the same way as the BlinkWithoutDelay example in the IDE.

It is possible (as long as you're not counting too fast) to incorporate the time element into the interrupt routine by keeping track of the time in a variable:

volatile uint32_t rps = 0;

void count() {
    static uint32_t revolutions = 0;
    static uint32_t timestamp = millis();

    revolutions++;

    if (millis() - timestamp >= 1000) {
        timestamp = millis();
        rps = revolutions;
        revolutions = 0;
    }
}
....
attachInterrupt(0, count, FALLING);

Then you can just reference the rps variable at any time to get the revolutions per second. Again it should really be queried inside a critical section to prevent the value being changed while you're actively reading it...

cli();
uint32_t myRPS = rps;
sei();

Serial.print(myRPS);
Serial.println(F(" revolutions per second"));
Majenko
  • 105,095
  • 5
  • 79
  • 137
  • Ive seen people use a variable++ or +1 in a function called by the ISR, without any millis or time reference, then use that variable against another variable to capture a peak value, use that to turn something on for that duration, for example. – Jim Jan 08 '18 at 11:39
  • Sure, if that's what they are doing requires them to do... – Majenko Jan 08 '18 at 12:04
  • "like that they introduce the concept of time at a later stage" could you explain what you mean by this perhaps with an example? I dont quite get it – Jim Jan 08 '18 at 12:08
  • You mean besides the one I already show in my answer? – Majenko Jan 08 '18 at 12:09
  • yes, it would help – Jim Jan 08 '18 at 12:10
  • I'm not sure I could add anything by doing something I have already done. I have shown you the most simple and basic example possible. What more do you want? – Majenko Jan 08 '18 at 12:10
  • like if he was to use the interrupt to capture a reed interrupt once per second in a rev++ varible, and use it latter like you suggested – Jim Jan 08 '18 at 12:13
  • Combine the first code block with the second code block (which you wrap in a setup() and loop() combination with the right pinmodes, serial config, etc) and you have your example. – Majenko Jan 08 '18 at 12:14
  • well that clears things right up dude, thanks. Im imagining those code blocks with everything I should put in them right now. it seems you was suggesting there was a way people were using the count not tied to any milis or delay, so I asked for an example – Jim Jan 08 '18 at 12:17
  • I know how to use the code blocks and declare initialize in the set up and put the attachinterupt there, outside the loop so it runs independantly of the loop I wanted to know how the counter variable ++ can be mapped or relate to any duration when used with an interupt, but your saying it cant without additional millis internal interupt or delay , but Ive seen it done without all that so I dont get it – Jim Jan 08 '18 at 12:25
  • If you have seen it done without that then you are looking at something else entirely. You can't get X-per-second without introducing the concept of "seconds". The interrupt has nothing whatsoever to do with that unless you explicitly code it in there like my second example. – Majenko Jan 08 '18 at 12:26
  • so what is a counter like ++ or +1? its just a byte in the regisiters memory? – Jim Jan 08 '18 at 12:29
  • Either. They both mean the same thing. rev++ means "increment rev", rev = rev + 1 means "add 1 to rev and store it in rev". rev+=1 means "add 1 to rev and store it in rev". – Majenko Jan 08 '18 at 12:30
  • no, Im asking, like if it takes 1 sec for a rev to increment the counter ++ or +1, that one second has no relation to the counter? the value of the increment is just an additional byte into memory? – Jim Jan 08 '18 at 12:32
  • The value of the increment is just a change of a variable in memory. The number of bytes that takes depends on what the variable is. It's just a variable. There's nothing (apart from the volatile flag) that makes it different from any other variable. – Majenko Jan 08 '18 at 12:33
  • yeah I get that, like a float, int, long, etc, the variable size. Im saying time has no relation, its not stored along with the the increment. like, the magnet passes the reed, 1 count, 1 second, another pass, 2 count 2 sec etc? – Jim Jan 08 '18 at 12:35
  • Unless you create a variable to store that kind of thing, where would it store it? It only ever does precisely what you tell it. There's never any "magic" in the background storing extra data. – Majenko Jan 08 '18 at 12:36
  • ok cool. I thought maybe the function in the interupt was looking at the interupt pin, and timestamping that, the counts along with the time it took. Actually I see allot of code with just a variable ++ then they store that in a variable, and store the total count in another variable, use that for a duration etc. I didnt see any milis etc like you see in blink delay, none of that so was puzzled how it worked – Jim Jan 08 '18 at 12:38
  • Ok, I think I see what they were doing. They had rev++ in the interupt function to call, stored that count in a varable, rev, intialized to 0, then used another variable to store the total count into revA. when revA is bigger than rev, do something, else do nothing. still seems like it would be based on the time, but...confusing. – Jim Jan 08 '18 at 13:05
  • 1
    they were comparing 2 variables and saving the larger count, then using that condition to turn on a motor, so it wasnt timed to anything, just when one became larger than the other, save that, and that condition became true, turn on the motor... As for nested "if" statements, if you have an if then a nested if, that is equilivant to an AND, correct? but an if, then an if else is equilivant to a NOT, correct? – Jim Jan 18 '18 at 03:20