Hello
Using a Mega 2560 and I'm quite new to programming so be gentle please.
It's my first time with interrupts and pulseIn as well. It should be a simple easy code as I see it but it does not do as I expect since I'm obviously doing something wrong.
When a pin goes HIGH I need to see how long time it has been on (later on put an output ON equally long time but I think I can handle that part) and I though pulseIn was perfect for this and easy to work with and little code and such.
However, with the code below whatever I do it just show nothing as in nothing is written in "sensor" as I see it.
#include <LiquidCrystal.h>
LiquidCrystal lcd(40, 42, 28, 26, 24, 22);
unsigned long sensor = 0;
void setup() {
lcd.begin(20, 4);
lcd.clear();
pinMode(2, INPUT);
attachInterrupt(2, count, RISING); //When pin 2 goes from LOW to HIGH run "count"
}
void loop() {
}
void count() {
sensor = pulseInLong(2, HIGH, 60000000UL); //when pin 2 goes from LOW to HIGH start timer,
//when goes LOW then save time value in "sensor".
if (sensor > 0) //If there is no value in "sensor", print nothing.
lcd.print(sensor);
sensor = 0; //sensor contain value from previous measurement, not anymore.
//Perhaps not needed though since its overwritten with next measurement?
}
I hoped that the very µs pin 2 goes low again it would display the timed value. It doesn't so I have obviously messed something up, maybe the interrupt thing that I have never used before.
LCD and all that is not going to be used in the final version, that is just to confirm this work as it should. Final version will using millis() a little but don't know it that would work with interrupt what I have read. And the pin by the way will be toggled at maximum 2000 times a second but that shouldn't be any problems what so ever.
Nothing in loop but I assume interrupt start the program every time pin 2 goes high?
Any suggestions? I'm out of options.
/Kevin
You would be better off setting a flag in the ISR and doing the pulseInLong() and printing in loop if the flag is set, then clear the flag. Since interrupts are disabled in an ISR and the print method depends on interrupts, printing in an ISR won't work. PulseInLong is a blocking function and has no place in an ISR. ISRs must execute quickly.
Thanks a lot for the answer!
Ok got it, not strange that my code doesn't work then.
So the interrupt only do as little as possible sort of speak and not a full blown routine with several lines of code, didn't thought that.
Use a flag to init the routine, got it.
A question to that though, in my case that way wouldn't really matter since it short but I'm guessing that it wouldn't have been the ideal way if a code is long? I mean the flag would only have been seen in the loop when the cpu has got to that line and not jump to that part in the code when the flag was set the instance the interrupt was toggled?
I made a simple program based on the recommendation above but with no luck so now I just tested this simple code from the Arduino repository to be sure I wasn't wrong in some way in the programming but not even this one worked that really should work as I see it:
int pin = 28; //Yes, I have tested different pins and such and also LCD ones that I know works
unsigned long duration = 0;
void setup() {
Serial.begin(9600);
pinMode(pin, INPUT);
}
void loop() {
duration = pulseIn(pin, HIGH, 4000000UL);
Serial.println(duration);
}
Nothing more then 0 shows when I poke the pin with 5V.
However when I accidentally touched the bottom of some pins around it with my bare fingers a lot of numbers and very fast in the 10000 microseconds area (+ a lot - a little) is shown but totally uncontrollable.
It doesn't detect when a pure 5V signal is applied to it, no only when noise is applied.
What is this? Any ideas?
Kevin_tvsg:
What is this?
A missing pull down resistor on the input pin.
Whandall:
A missing pull down resistor on the input pin.
While Whandall may be correct about you missing a pulldown resistor, if you still are having problems with your code, maybe something like this may work for you.
( I know it might look complicated but at least its non-blocking!
)
#define INTR_pin 2
volatile unsigned char buff_size = 4; //change size if too much or too little
volatile unsigned char head = 0, tail = 0, intr_state;
volatile unsigned long oldtime, sensor_pulses[buff_size];
void setup() {
Serial.begin(115200);
pinMode(INTR_pin, INPUT);
intr_state = digitalRead(INTR_pin); //initialise intr_state.
oldtime = micros();
attachInterrupt(digitalPinToInterrupt(INTR_pin), count, CHANGE); //When pin 2 goes from LOW to HIGH run "count"
// intr_state = 0: input was low. transitioning LOW-> HIGH, record current time;
// intr_state = 1: input was high. transitioning HIGH-> LOW. Save HIGH pulse time;
}
void loop() {
if ( head != tail) {
Serial.println(sensor_pulses[tail]);
tail = (tail + 1) % buff_size;
}
}
void count() {
switch (intr_state) {
case 0:
oldtime = micros();
intr_state = 1;
break;
case 1:
sensor_pulses[head] = micros() - oldtime;
head = (head + 1) % buff_size;
intr_state = 0;
break;
}
}
sherzaad:
if you still are having problems with your code, maybe something like this may work for you.
That will produce unpredictable results. Access to 'unsinged long' on an 8-bit AVR is non-atomic. You should transfer each value to a local variable inside a protected section:
void loop() {
uint32_t localPulse;
if ( head != tail) {
noInterrupts();
localPulse = sensor_pulses[tail];
interrupts();
Serial.println(sensor_pulses[tail]);
tail = (tail + 1) % buff_size;
}
}
About the resistor, dammit, yea I actually thought about that but since there is an internal pullup to choose so did I stupidly assumed there was automatically a pulldown set otherwise. It should have been obvious for me that it of course can't be.
I never thought that something simple to check a simple time would need a code a "big" code like this, sigh. I thought maybe 10 lines and all done, but noo. 
The first plan was actually to fit the code in a ATTiny10, but I guess that is just something to forget since the code is bigger then I thought it would be and way over 1kb no matter what due to many thing of. It's fixable though since I think slightly bigger and more flash like fex a QFN-20 size would work.
Ok, thanks for the code snippets guys! Things that I have to check up and get the hang of but I will get it.
Btw, it is a 8-bit avr but how come you then still can use that 32-bin thing in it as in the above code? Just curious, and of course don't really understand how that works. I have seen code with unsigned long and stuff on the mega before but that is perhaps for something else then or something, I don't remember.
And about the basic code as is, I have thought a little; is a interrupt really necessary? If the timing is in like +- some 100µs+ or so and it should be just fine.
Thought about less code wise to handle for me and such to finally get it done.