Hi all,
I've been struggling with this for a couple of days now so any help would be greatly appreciated. My full code is at the bottom of this post.
I have a relatively simple code which uses interrupts to count how many pulses are created by a flowmeter. Once the target number of pulses of 300 are reached, a success value is sent to the Serial unless a delay of 10 seconds is reached which would signify an inadequate amount of flow in a given time.
Physical Setup
An Arduino Nano ATmega328P and a hall effect flowmeter connected to physical pin 2 with a 10K pull-up.
Problem
Approximitely every 1 in 10 cycles results in my pulse count not being greater, equal to, or less than my target value, pushing the code to the 'else' statement in the code below. When this happens, the value always reported back is 256.
After a lot of trial/error with various count targets, testing parts of the code and reading up on forums I suspect that because any int more than 255 requires more than 1 byte/8bits, which to my understanding means that the 8 bit arduino chip will have to run twice to copy (save?) a 16bit number. So if the interrupt detects another pulse between the copy, the the second 8bit of the number won't be correct, hence pushing me to the 'else' statement?
From reading other posts there are some hints at disabling interrupts which I've attempted (as mentioned in the points below) but I am unclear at what point and for how long to do this in my main loop? I'm also concerned with accuracy and I'm unsure about how disabling interrupts would affect this?
If disabling interrupts intermitently is the answer then it would be great to understand where to do this in my main code.
What I've tried
- using 'ATOMIC_BLOCK(ATOMIC_RESTORESTATE)' from the atomic library and various trial and error of disabling and enabling interrupts inside and just before my 'while (count < Target)' loop. This appears to reduce the amount of times this error happens to 1 in ~30 but it is still an issue
- I was concered that my millis() timer could have had an effect but I have the same results if this is commented out.
- I've also tried the below code in my 'while (count < Target)' loop to continously print all count values. This has produced no errors after multiple attempts, I'm not 100% sure why but I would rather not send all this data to the Serial when the connected computer is only looking for one value... I'm also uncertain as of yet how this affects the accuracy.
while (count < Target)
{
Serial.println(count);
if (delayRunning && ((millis() - delayStart) >= DELAY_TIME)) // Check if the timeout has been reached
{
delayRunning = false; // finished delay
fillerror(); // Send Error signal
break;
}
}
My full code below. (I'm relatively new to this so I've tried to make it as legible as possible in case I've done something odd...)
int flowPin = 2; //Input pin on the Arduino
volatile int count; //Integer set as volatile
// Set variable defaults
int Target = 350; //Target number of pulses from the flowmeter
unsigned long DELAY_TIME = 10000; // 10 sec
unsigned long delayStart = 0; // the time the delay started
bool delayRunning = false; // true if still waiting for delay to finish
void setup()
{
pinMode(flowPin, INPUT); //Set the pin as an input
attachInterrupt(digitalPinToInterrupt(2), Flow, FALLING); // Configures interrupt and 'FLOW' ISR
Serial.begin(9600); //Start Serial
while (!Serial) {}; // Wait for serial to start
interrupts(); //Enable interrupts (should be on by default but I thought it was no harm to add?)
}
void loop()
{
if (Serial.available())
{
char ch = Serial.read();
// If '1' is sent to the serial, reset the counter and mills start time, and send back '5' to the Serial to notify an external computer.
if (ch == '1')
{
delayStart = millis();
delayRunning = true;
count = 0; //Reset Counter
Serial.println("5");
while (count < Target)
{
if (delayRunning && ((millis() - delayStart) >= DELAY_TIME)) // Check if the timeout has been reached
{
delayRunning = false; // finished delay
fillerror(); // Send Error signal
break;
}
}
if (count >= Target)
{
fillstop(); // Send success signal
}
else
{
Serial.println("What Happened Here?....");
Serial.println(count);
}
}
}
}
void Flow() {
count++; //Every time this function is called, increment "count" by 1
}
void fillstop() {
Serial.println("9"); //success value sent to Serial
}
void fillerror() {
Serial.println("0"); // Timeout value sent to Serial
Serial.println(count);
}