Hoping someone can advise. I working on an arduino based weather station. So far I only have temperature sensing and now working on a rain gauge. I purchased a Rainwise tipping bucket rain gauge. My problem is that the tipping bucket trigger is a very quick on/off each time the bucket tips my arduino sketch can very easily miss a tip count while off reading the temperature sensor. Would using an interrupt be the best way to go about solving this issue? Any advise is greatly appreciated.
Would using an interrupt be the best way to go about solving this issue?
Yes. Be careful of writing the interrupt handler, though. It must be as fast as possible.
An interrupt would work well in this situation. Just keep the interrupt function short & sweet, most especially, don't use any serial print commands. A simple NumberOfTips++; would be suitably minimal.
Edit: Too slow!
And declare all vars used in the irq routine volatile so
volatile unsigned long numberOfTip=0;
And, when accessing multi-byte variables from the loop side, use critical sections.
And, when accessing multi-byte variables from the loop side, use critical sections.
It would be nice to see this advice elaborated on. What are critical sections, and how are they used?
No problem...
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1261124850
The section that starts "Data that cannot be accessed atomically" describes a "critical section".
umm ... WOW. Thanks everyone. Now just to figure out exactly how to implement an interrupt. I have a general idea, but its going to take some serious trial and error experimenting.
Now just to figure out exactly how to implement an interrupt.
It's not all that hard. You need to connect the signal that defines the interrupt to an external interrupt pin (2 and 3 on the Duemilanove/UNO), and attach an interrupt handler to the appropriate interrupt vector (0 == pin2; 1 == pin3), and define the condition under which the handler is invoked (RISING (LOW to HIGH), FALLING (HIGH to LOW), or both (CHANGE)).
In the interrupt handler, do the minimum work required to process the interrupt - generally just noting when the interrupt occurred or incrementing a counter or setting a flag.
Then, in loop(), check whether the interrupt occurred, and changed anything (the flag is set) or just deal with the current data (number of bucket tips, number of revolutions, when the interrupt occurred, etc.). Reset flags/values as appropriate (in a critical section).
Try to isolate each section of the code, to make troubleshooting easier. For instance, toggle an LED when the interrupt occurs, so you can see that the event is happening/the handler is called.
Then, perform calculations based on the collected data, without resetting.
Finally, add the code to reset stuff.
So I found a pretty good example of using an interrupt here http://www.dave-auld.net/index.php?option=com_content&view=article&id=107:arduino-interrupts&catid=53:arduino-input-output-basics&Itemid=107
I changed it a bit to suite my rain gauge by replacing the switch with the actually rain gauge trip switch. The code I modified a bit just to better display the tip counts.
int pbIn = 0; // Interrupt 0 is on DIGITAL PIN 2!
int ledOut = 4; // The output LED pin
volatile int state = LOW; // The input state toggle
int tipped = 0;
int tipcount =0;
void setup()
{
// Set up the digital pin 2 to an Interrupt and Pin 4 to an Output
pinMode(ledOut, OUTPUT);
//Attach the interrupt to the input pin and monitor for ANY Change
attachInterrupt(pbIn, stateChange, CHANGE);
Serial.begin(9600);
}
void loop()
{
//Simulate a long running process or complex task
for (int i = 0; i < 100; i++)
{
// do nothing but waste some time
delay(10);
}
if (tipped == 1)
{
Serial.println("tipped");
tipcount++;
Serial.println(tipcount,DEC);
tipped = 0;
}
}
void stateChange()
{
state = !state;
digitalWrite(ledOut, state);
tipped = 1;
}
Serial Monitor displays as follows ...
tipped
1
tipped
2
tipped
3
tipped
4
tipped
5
tipped
6
tipped
7
Now all I need to do is add this sketch to my temperature sketch which should be pretty easy. Thanks everyone for your advise and guidance.
Next step is to find a good inexpensive anemometer to measure wind speed and direction. Anybody know a good source?
The code has a race condition that may lead to missing bucket tips.
Race condition ???
Per Wikipedia "A race condition or race hazard is a flaw in an electronic system or process whereby the output and/or result of the process is unexpectedly and critically dependent on the sequence or timing of other events. The term originates with the idea of two signals racing each other to influence the output first.
Race conditions can occur in electronics systems, especially logic circuits, and in computer software, especially multithreaded or distributed programs."
But thats all I got. No clue how to fix it. I thought I was good to go with this. doh!
Yup. There are two problems. The first problem is because the data-type for tipped is more than one byte. An int in the Arduino world is two bytes. It takes at least two machine instructions to perform any operation on tipped (one machine instruction for each byte). If the CHANGE interrupt occurs between the two machine instructions, it is possible the value of tipped can become corrupt. Imagine if loop writes the first byte of tipped, the CHANGE interrupt occurs, stateChange is called which writes to both bytes of tipped, and, returning to loop, the second byte is written. tipped now stores one byte from loop and one byte from stateChange. That can't be good. Because only a zero or a one is stored in tipped, it is not possible for the value to become corrupt. In other words, you got lucky with this race condition.
The second problem is that the access to tipped in loop is split into two operations. "if (tipped == 1)" reads tipped and then "tipped = 0;" writes to tipped. What happens if an interrupt occurs between the two operations?
[quote author=Coding Badly link=topic=68073.msg502545#msg502545 date=1312261118]
What happens if an interrupt occurs between the two operations?[/quote]
You'll wish you had completed your ark project?
The variable tipped must be volatile too.
better solution:
- increase tipcount in the interrupt routine (tipcount must be volatile unsigned long)
- check in loop if it has increased - keep a separate var with the previousTipcount (also unsigned long)
Rob
k3v1np:
tipping bucket trigger is a very quick on/off each time the bucket tips
I am of the purley personal opinion that most "interrupt" code attempted by people here is totally uneccessary.
How long is "very quick"? Have you made some temporary code/setup that actually measures how long the switch/sensor is closed (you could use the pulseIn() to test it)? It is a mechanical device ... What is the fastes times per second it can trip - once?, hundreds? That is still soooo slow to the Arduino.
It can measure the input many thousands times in one tip. Even with alternating with the analogread for the tempertaure you can still look at the bucket switch 5 - 8 thousands times each second (or about 50-100 times in the time it takes one tip assuming it tips 100 times a second) so you should have little trouble catching it in its "tipped" state.
As you have seen from this thread, interrupts are not a beginners coding exercise. I used to do operating systems (many years ago), and that was hairy, and which is why after doing various Arduino projects for a year now I still have not used an interrupt. Most of my loop() code is written with a bit care, avoiding blocking code (and certainly never a delay()! ) and usually runs at 10 or 50 Khz (ie takes 100 or 20 microseconds to loop once)
Get rid of the interrupt code. Well, that was just an opinion.
I think the switch is magnetically driven. Tiny circuit board with a resistor and another resistor shaped shiny glass thing right beside it that the magnet passes by during the "tip". I think the switch is normally open then when it tips it closes and is then open again. I will try measuring the time it is closed during the tip.
One feature of the reed switch you are describing is that it "bounces" when closing and opening. This means that during a period of a few microseconds to a few milliseconds you will get from a few, to many, closures. If you're not aware of this, you can get some results that don't match your expectations. One use of interrupts is to solve this problem. Certainly not the only way to solve the problem nor the only use of interrupts.
One use of interrupts is to solve this problem. Certainly not the only way to solve the problem nor the only use of interrupts.
Since the interrupt gets fired EVERY time the switch bounces, how does the use of an interrupt help?