Here is my sketch. I have spent hours trying to sort this out. It's a nice little frequency counter, tho I'm just trying to count pulses from my Water Meter. I am using 1.8.19, on a Nano. It will give me the correct answer the first time thru the loop, but after that the counting is goofed up. My comments at the top give more details. I would appreciate it if anyone would help.
// This sketch runs fine and consistently displays the 88 Hz freq fed in on Pin D2 correctly. // That is, when the digitalWrite() function is commented out. // But if it is not, the first time thru the Flow Rate correctly display shows 88 Hz (from my function generator) // but every loop after that it shows the Water Flow Rate (which is based on the count) in the 700' or 800's. // I put in some Serial.print's to diagnose what is going on. // I think the problem is that while the digitalWrite function is executing, the counter just keeps on rocking, // and I don't know how to make it stop. count = 0 at the bottom doesn't work. I can't get cli()/sei() to work either. // // const byte flowPin = 2; // input from Frq Gen simulating Pulses from Water Flow Meter sensor in garage. int LowVoltageAlarm = 6; // 'time to Replace Battery' LED volatile int flowRate; volatile int count = 0; void setup(){ Serial.begin(19200); // Debugging only pinMode(flowPin, INPUT_PULLUP); // D2 pinMode(LowVoltageAlarm, OUTPUT); digitalWrite(LowVoltageAlarm, LOW); // turn the LED off by setting it LOW attachInterrupt(0, Flow, RISING); // Func Gen input Serial.begin(19200); // Setup Serial Monitor } void Flow() { count++; } void loop() { Serial.print("count1 = "); Serial.println(count); // for diagnostics count = 0; Serial.print("count2 = "); Serial.println(count); delay(1000); Serial.print("count3 = "); Serial.println(count); flowRate = count; Serial.print("count4 = "); Serial.println(count); digitalWrite(LowVoltageAlarm, HIGH); Serial.print("count5 = "); Serial.println(count); Serial.print("Water Flow Rate = "); Serial.print(flowRate); Serial.println(" Pulses/sec"); Serial.print("count6 = "); Serial.println(count); count = 0; Serial.print("count7 = "); Serial.println(count); }
@pratto20 I have no idea why your code behaves the way it does, but I am using several ISR's and according to the doc'n I read this is how to set them up.
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; // change ICACHE_RAM_ATTR to just IRAM_ATTR ?????? WHY ???? IRAM_ATTR void Timer1_ISR() { portENTER_CRITICAL_ISR(&timerMux); TimerKitchenOn = false; portEXIT_CRITICAL_ISR(&timerMux); }
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
@pratto20 My apologies, I think I am using a different kind of interrupt mechanism than you, mine are the 4 built-in hardware interrupts on an ESP32. Therefore my example code may be totally irrelevant.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
I haven't used ISRs in the past, so this is pure speculation ...
The approved specification of the definition for your sketch would be
attachInterrupt(digitalPinToInterrupt(flowPin), Flow, RISING); // Func Gen input
whereas you have a 0 as the first parameter.
I don't know why sei() and cli() don't work for you (that seems kind of alarming) but you may be able to control the accumulation by introducing a new bool value doCount and setting it false. In the Flow(), change the code to
if (doCount) count++;
and then change the code in the loop() to
doCount = true;
delay(1000);
doCount=false;
This should allow Flow to increment count only when you've set doCount true.
Anything seems possible when you don't know what you're talking about.
@will @pratto20 GAH, missed that 1st argument difference. I would do that first, the second part only adds more and unnecessary code to the critical section opening up the remote chance of an ISR foobar. Also, isn't he saying the count is too low?
I was wondering if anybody knows how to get the assembler listing so I can look at the difference between count++, ++count, count = count + 1. It shouldn't be any different with a fully optimizing compiler but until you look it's impossible to say.
Also, the ISR is running in slow program memory, would it help to run it in fast ram memory as the doc'n advises?
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
@will thanks for the suggestions. I did change the attach interrupt syntax. but I had already tried it both ways many times. it is my understanding that either way is the same thing.
the boolean didn't work in the ISR, nor did any other if() I tried.
the bottom line is still the same : with the digitalWrite commented out, it works and following the count value makes sense, but un-comment it and it all goes to pieces.
@zander no, the count goes much higher from loop two on. whether I use count++ or count = count+1, it won't work unless I comment out the digitalWrite.
@pratto20 Sorry, I am getting confused between my timer based hardware interrupts and the sofgtware interrupts. First thing you need to do is fix parametyer one, it should be as @will said,
attachInterrupt(digitalPinToInterrupt(flowPin),........
What line number are you referring to re the digitalwrite causing a problem?
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
@zander I did change it. no line number shown in the post, so ;
flowRate = count; Serial.print("count4 = "); Serial.println(count); digitalWrite(LowVoltageAlarm, HIGH);
@pratto20 I find it much easier to help folks who go to prefs and set it up like (see pic), also goto Tools -> Auto Format.
Now, I do NOT understand the purpose of your sketch. You are setting count to 0 at the top of the loop and the bottom. You are printing the value of count multiple times and most of the loop is running at something like 80 million instructions per second. Perhaps some print screens of the sketch working and not working would help. AND make sure the attachInterrupt is coded correctly, it will NOT work with 0 as the first argument.
BTW, one of those pins 6 IIRC is a PWM pin, what freq is the PWM on that board, maybe change to a non PWM pin like 4.
If you preface the sketch with a statement of function like 'This sketch computes the square root of the input and prints it to Serial.' that would be a good start.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
@pratto20 Ok, I think I understand what you are trying to accomplish. It looks like you want to know flow rate in x units / time interval. The problem is you have no close to accurate time interval. Either use some millis times and normalize (if you want per second but your resolution etc gives 1,003 or 1,005 then divide by 1003 and multiply by 1,000 sort of thing. The other approach is to use a hardware timer which is another kind of interrupt to fire off every second if that is your timer choice or 1 per minute etc. Now your code is totally interrupt driven and the main loop is basically doing nothing waiting for the timer to pop. When it does, grab the count and elapsed time real quick (use RAM and critical section wrappers to guarantee granularity, I posted those earlier)
The use of delay is not a good idea for this kind of application. A general rule of design is to do as little work in the ISR but instead just set the key variable that allows the outside logic to work and do the bulk of the work outside the ISR. These are very fast devices, so once per second frequencies are easy, but at some point something finer will cause a break in the ISR code so be reasonable.
First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, and 360, fairly knowledge in PC plus numerous MPU's and MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.
I'm wondering if this is because you're using two pins on port D of the NANO. Please try moving the LED from pin 6 to one of 8-13 (i.e. PORT B) and see if that makes a difference.
Anything seems possible when you don't know what you're talking about.
@will Thank you, thank you. I used Pin 8 instead of 6, as you suggested, and that solved the problem.
no doubt you can tell I am not wise in the ways of programming, but if you would, will you give me a dumbed down version of what the problem was ?
I'd be happy to explain it if I could, but as I said, I don't use interrupts.
The wild goose I was chasing is that there are several different styles of interrupts. One of them homes in on the individual pins on the different ports of the NANO. You can Google "arduino port" for more information than I can give you.
Anyway, it occurred to me that pins 2 and 6 are on the same port (PORT D to be specific) and it might be possible that the interrupt was conflicting because both pins were on the same port. Hence, changing the configuration so that they were on different ports MIGHT work. Since you needed to keep the interrupt for pin 2, it had to be the other pin that moved.
Changing it to pin 8 means that it's now on PORT B and appears to have eliminated the conflict.
I'm glad it worked for you 🙂
Anything seems possible when you don't know what you're talking about.
@will This is embarrassing. When I tested it, I had forgotten to move the LED to Pin 8, so no LED was connected to it. As soon as I put the LED in place the LED turned on, and the problem was back.
So I set the Pin back to 6, plugged in the LED and it worked as long as the LED was set LOW, but as so as it went HIGH (and the LED lit up), the problem was back.
So it seems that the problem occurs when the board actually sends current to the LED (not just sets it HIGH), on Pin 6 or 8.