Hi, The programme i have has been sourced from another forum member after googling the task at hand which is counting the pulses from a slot interrupt counter on a drive shaft. it works well, but unfortunately my brain doesn't and a key part of the programme is a mystery to me:
When a rising voltage is detected, the interrupt service routine function is jumped to ISRcount and the pilse is added to the integer 'count'. What I don't understand is what happens then, because if the loop resumes, then count=0 is set and then copycount is printed - I don't understand how the pulses are being added to integer count several times (about 200/sec in my case). So my specific question is what is the path of the programme from the first pulse being detected being added to integer count and then the next one being added to count and so on... how does this happen before the count is reset to zero ?
Would someone be able to walk through the path of the programme?
//https://forum.arduino.cc/index.php?topic=401987.0
// count encoder pulses on a motor
volatile unsigned long count = 0; // +1 each time interrupt calls ISR
unsigned long copyCount = 0; // accumulates the interrupt count, after
unsigned long lastRead = 0;
unsigned long interval = 100; // interval must be set <= delay (eg 100, 100) set in the loop otherwise rps becomes amplified upwards
unsigned long speed = 0;
void setup()
{
Serial.begin(9600);
pinMode(2, INPUT_PULLUP); // set pin 2 as input and high when no input
attachInterrupt(0, isrCount, RISING); // interrupt programme when signal to pin 2 detected (0 = pin 2 and 1 = pin 2)
// count when rising, call ISR function when happens (irs = interupt service routine)
// pinMode(21, INPUT); // ?
// attachInterrupt(digitalPinToInterrupt(21), speed, FALLING); // ?
}
void loop()
{
if (millis() - lastRead >= interval) // read interrupt count every 0.1 second (100 ms). NB ~30 loops per milli sec
{
lastRead += interval; // add interval int to lastRead int
// disable interrupts,make copy of count,reenable interrupts
noInterrupts(); // don't interrrupt to count on pin while copying count
copyCount = count;
count = 0; // reset count to 0
interrupts(); // switch on interrrupts again
Serial.println(copyCount);
Serial.println(millis());
}
}
void isrCount()
{
count++; // put pulses in here
}
During that interval every time an ISR is triggered the value in the variable count is incremented.
At the end of the interval the accumulated value is copied into the variable copyCount and the value of count s set back to zero ready to be incremented again during the next interval.
So what gets printed by the line
Serial.println(copyCount);
is the number of counts in the most recent 100 millisecs.
Thanks. I kind of understand, but when I write out what's happening, I get stuck at the end, so let's start at the loop:
loop (let's assume a change in state detected while in IF part of loop, so millis has just ticked over to 100...)
if
100 - 0 >= 100 (YES, go ahead - it looped 1000s of times before millis got up to 100 ms)
then add interval to lastRead ( 0 + 100 = 100, new val of lastRead )
stop interrupt while counting
put val of count in copyCount ( 0, at the moment)
start interrupt ability again
lets assume encoder ticks.... as it would if motor spinning at 230 rps (6 v)... the programme interrupts and ISR
isrCount is called: integer count is increased by +1 then loop starts again:
100.01 - 100 >= 100 (NO, so don't go into IF loop.... assume it tool 10 micro sec to get through the programme loop)
So if the IF loop doesn't run how does the ISR function get to be called and so add more pulses to the count integer ??
Whatever the code is doing - as long as that interrupt is enabled - the trigger event will 'interrupt' the current instruction sequence, and then return to the same spot in code when the ISR has completed.
You don't have to do anything special to receive an interrupt - as long as you return from the ISR as quickly as possible - ready for another/next event.
Robin2:
If the Arduino has been running for 100 millisecs I don't understand your thinking when you assume that the value in the variable count will be zero?
If you explain your thinking it will be easier to help.
...R
Yes I don't know why this is so hard either as I am fairly intelligent (!) but programming is simply not my forte, to put it mildly...
My (flawed) thinking:
Before I start, there a couple of things I realised: 2 counts per rev on the encoder and so a readout of 20, 20, 20, etc means 20/2 = 10 pulses per 100 ms i.e. 100 per sec and so 6000 rpm
Lets say the motor starts (~6000 rpm, which is ~100 revs/sec (200 pulses/sec), or 20 per 0.1 sec) and the encoder starts ticking, the first pulse means the IRS is called and a count is incremented in integer 'count'.
As someone said above, the programme returns to the last place it left in the if loop so as the loop is running so quickly then I assume it must get to the point where the count = 0 is set before the ISR is triggered again as the loop runs faster than the encoder triggering... obviously this is wrong, but I don't get why, I just can't 'see' what the controller is 'thinking'.
mechengncl:
as the loop is running so quickly then I assume it must get to the point where the count = 0 is set before the ISR is triggered again
NO.
This line of code prevents that from happening
if (millis() - lastRead >= interval)
The code inside that IF clause will only be activated once every 100 millisecs even though loop() might have repeated a 100 times in that period.
A good way to figure out how a computer program works is to get a pencil and paper and work through the program line by line writing down the results of each line as you go - using your brain as the microprocessor.