I have a device sending high pulses. They come in banks of between 1 and 10 and fast, so even a bank of 10 pulses will arrive within a second. A new banks of pulses will normally have a slight delay between them coming.
I want to count how many pulses came in each set and write it to a variable.
I am currently counting pulses in an interrupt using "attachInterrupt" on a RISING edge, in the interrupt I have a count and I can display this on the serial monitor. So I can currently count the pulses, but I`m not seeing them as banks of pulses, just a continuous count.
Ive been told that the correct way to do this would be to setup a timer, use a flag set to the first pulse to start the timer, wait a second counting the pulses - record this value to a variable and reset the count, timer and flag waiting for the next banks of pulses. Ive no idea how to even start this task!
I want to count how many pulses came in each set and write it to a variable.
How do you define a set? In the ISR you can record when each pulse arrives, along with counting it. A set could start when the interval between this pulse and the last pulse exceeds some threshold.
So I can currently count the pulses, but I`m not seeing them as banks of pulses, just a continuous count.
Your code? You should not be Serial.printing() in the ISR. If, as noted above, you record the time (using millis() or micros()), and then print it, you might see the pulses are grouped.
craynerd:
Ive been told that the correct way to do this would be to setup a timer, use a flag set to the first pulse to start the timer, wait a second counting the pulses - record this value to a variable and reset the count, timer and flag waiting for the next banks of pulses. Ive no idea how to even start this task!
You were told wrong, unless there is always at least one second between the start of one group and the start of the next.
What I would do is have the ISR increment the count and record the time (millis()). In loop() I would process the count if (count>0 && millis()-lastPulseTime > threshold). That means "at least one pulse has come in and the last pulse was more than 'threshold' milliseconds ago".
PaulS means nothing. I wouldn't be on here asking if I could do it
I'd like to understand this better John?
What I would do is have the ISR increment the count and record the time (millis()). In loop() I would process the count if (count>0 && millis()-lastPulseTime > threshold). That means "at least one pulse has come in and the last pulse was more than 'threshold' milliseconds ago".
PaulS means nothing. I wouldn't be on here asking if I could do it
You need to determine WHEN each pulse occurs. That is done using millis() or micros(), as I showed. Once you can do that, you can determine time between pulses.
Look at the blink without delay example, to understand how millis() can be used to cause events to happen on a regular basis. It's not difficult to understand how to turn that around and determine the interval between two events - such as the pulses as coins are inserted.
tylernt:
How does it differentiate coins -- does each different coin have a different pulse length?
You can programme the acceptor to pulse a set number of pulses between 0-50 for each of the 6 coins it will accept. You have full control over the number of pulses it can generate. The pulse length is the same for each coin, it is a literally the number of pulses in the group generated for each coin that are different,
So, create a volatile unsigned long timer variable, and volatile byte counter variable. In your RISING ISR, assign millis() to your timer variable and increment your counter.
(Note that millis() never increments in an ISR, but you are allowed to grab whatever timestamp millis() had when the interrupt occurred.)
In your main loop, check to see if the difference between millis() and your timer variable is greater than the period between pulse intervals. If it is, you've just finished accepting a coin and your counter will indicate which coin (zero will indicate no coin). Do whatever you need to do with this information (quickly, before another coin comes along) and zero your counter.
No need to turn interrupts on and off or muck about with hardware timers.
OK - Ive done my best but something isnt quite right.
I`ve currently got the programmer just set to 10p pieces which send a bank of 5 pulses. Based on this code, my serial monitor displays 2p, 5 times in succession for each coin inserted. I was expecting it to write 50p once on the serial monitor to match the 5 pulses!!
volatile byte coinPulseCount=0; // a counter to see how many times the pin has changed - which coin inserted
byte newCoinInserted; // a place to put our last coin pulse count
byte cmd=0; // a place to put our serial data
int opCountPin = 3; // pin3 as optical count input
volatile unsigned long pulseTime; //this stores the time of the last pulse.
void setup() {
Serial.begin(9600);
Serial.print("Input on pin ");
Serial.print(opCountPin);
Serial.println();
pinMode(opCountPin, INPUT); //optical count is an input
attachInterrupt(1, coinpulse, RISING); // attach a PinChange Interrupt to our pin on the rising edge
// and execute the function burpcount when that pin changes - ALWAYS CHECKING CHANGES
}
void loop()
{
//SERIAL MONITOR STUFF
cmd=Serial.read();
if (cmd=='p')
{
Serial.print("coinPulseCount:\t");
Serial.println(coinPulseCount, DEC);
}
cmd=0;
// SERIAL MONITOR STUFF
//****************************************************************
//CHECK NOW TO SEE WHICH COIN IS INSERTED
if (coinPulseCount >0 && millis()- pulseTime > 1000) //if there is a coin count & the time between now and the last pulse is greater than 1/4 of a second - THE END OF BANK OF PULSES
{
newCoinInserted = coinPulseCount; //new variable to free up coinPulseCount on the interrupt.
coinPulseCount = 0; // clear pulse count ready for a new pulse on the interrupt.
}
//Proccess the coin inserted
switch (newCoinInserted) {
case 1:
Serial.println("2p inserted");
newCoinInserted = 0;
break;
case 2:
Serial.println("5p inserted");
newCoinInserted = 0;
break;
case 3:
Serial.println("10p inserted");
newCoinInserted = 0;
break;
case 4:
Serial.println("20p inserted");
newCoinInserted = 0;
break;
case 5:
Serial.println("50p inserted");
newCoinInserted = 0;
break;
case 6:
Serial.println("£1 inserted");
break;
}
}
void coinpulse()
{
coinPulseCount++;
pulseTime = micros(); //store current time in pulseTime
}
PaulS is right as usual. But really, you need to work out the time between the pulses (presumably quite short). You could always measure to be sure. Say it is 0.1 seconds. Then anything over that is a new coin, not the pulses for the old coin. My guess is that something like one second would be adequate for saying "new coin" but that is just a guess. See how fast you can cram coins into it, compared to the rate at which the pulses come out.
I think something like this will help you find the pulse length:
if (coinPulseCount >0 && millis()- pulseTime > 1000) //if there is a coin count & the time between now and the last pulse is greater than 1/4 of a second - THE END OF BANK OF PULSES
{
newCoinInserted = coinPulseCount; //new variable to free up coinPulseCount on the interrupt.
coinPulseCount = 0; // clear pulse count ready for a new pulse on the interrupt.
}
else if (coinPulseCount >0)
{
Serial.print("Pulse time was "); Serial.print(millis()- pulseTime);
}
Am I too naive thinking the coin acceptor tries to do the work for you ( i.e. the Arduino ) already ?
If a 10p coin produces 5 pulses, a 20p coin should produce 10 pulses, and Arduino should not mind if there were 2 coins of 10p inserted too quickly or a single 20p coin. The intermediate value of 10p is never displayed perhaps, but finally customer should see what they put in.
The pulse length should be rather fixed, and so should be the pauses inside a "set". Whenever there is a pause say longer than double the standard pause, you might display the new value , and act upon it.
So the ISR just counts up and stores the millis() value, and in loop you compare this last pulse time.
Assuming a pulse is 50 ms and a pause is 50 ms as well, you can simply reloop until (millis() - lastpulsetime > 200).
Simple !
I would reset the coin pulse count only when the desired total amount is reached.
( Hopefully the coin acceptor never produces too few or too many pulses
There was a whole thread on exactly this coin-mech pulse-count but it may have been a year or so ago. But search being what it is, it may take forever to find it.