Would someone point me to an example (or documentation) of reading a Serial port that is interrupt based?
I'd rather have loop() doing other things- until an interrupt arrives indicating there is serial data to be read.
I'm sure this is possible going directly to the ATMEL 168/328, I don't know if it can be done going through the Arduino software.
void loop(void) {
if ( Serial.available() ) {
// read the character and do what you need
return; // just runs loop() again immediately
}
// no need for else with that return in there
// the rest of your code can run while waiting for the next available character
// which may take many loop() cycles even with serial data being sent, depending on your code
// here's a consideration though. if your code is thick then catching every character as it comes
// won't save you anything that the rather large serial chip buffer already will unless your code
// is really, really thick.
}
HardwareSerial already calls an interrupt when a character arrives. The ISR puts the new character into its internal buffer. So you can still be doing other things while waiting for things to arrive.
So if you are going to write your own handler that "sets a flag" to show data is available, well that happens now. The "flag" is that Serial.available () returns non-zero.
Since interrupt handlers aren't supposed to do much, you would need a rather specific case (where you need to respond very promptly for example) for the current method to not be adequate.
I'd rather have loop() doing other things- until an interrupt arrives indicating there is serial data to be read.
As I said, you can be doing other things right now. Just test Serial.available () amongst doing those other things.
pYro_65:
look at the reference section for the interrupt handling functions.
your loop() can do whatever it wants, the interrupt will pause it and can read serial then, or flag loop() to read serial on its next loop.
any tutorial using interrupts will contain the basis of what you need, then add in serial handling.
Are you guessing, or have you actually seen an example?
Have you looked in the interrupt handling reference yourself?
I've already done this and I've successfully used an interrupt handler for handing signals on pin2.
There doesn't seem any obvious way to create an interrupt handler to handle incoming serial data, without polling.
cappy2112:
Are you guessing, or have you actually seen an example?
Have you looked in the interrupt handling reference yourself?
Did you read HardwareSerial.cpp? As Nick says, the interrupt handler on the USART fills a buffer, and Serial.available() just checks that buffer. No polling on the serial port at hardware level.
// The ISR
SIGNAL(USART_RX_vect)
{
#if defined(UDR0)
unsigned char c = UDR0;
#elif defined(UDR)
unsigned char c = UDR; // atmega8535
#else
#error UDR not defined
#endif
store_char(c, &rx_buffer);
}
int HardwareSerial::available(void)
{
return (unsigned int)(RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE;
}
cappy2112:
There doesn't seem any obvious way to create an interrupt handler to handle incoming serial data, without polling.
Common conventions says you should spend as little time as possible in a ISR. Typically you use a ISR to set a flag. Which as Nick pointed out, is what Serial.Available() already provides.
What is it you are doing that timing is so critical you need to see every serial character as it comes in?
I agree. But having a function called automatically no matter where your code is in it's execution is a better way to go.
As long as interrupts are not disabled in loop(), everything just works nicely and loop() doesn't get so cluttered.
[quote author=Nick Gammon link=topic=80635.msg609226#msg609226 date=1322542061]
I'm not sure what you achieve by doing this.
Avoid polling.
Take a look at attachInterrupt()
[/quote]
I understand how interrupts work, but in this case you aren't polling the serial port. You are checking from time to time to see if serial data has arrived. The HardwareSerial implementation has at least a 32-byte buffer, so you can afford to be doing other stuff while that fills up (via its own interrupts). Then in loop, you can see if there is data in the bufffer.
Let me put it another way, your thread heading was "Example of interrupt-based version of reading serial port". The current implementation already uses interrupts to read the serial port. So, job done. Or if you want to improve upon it, the HardwareSerial.cpp file is such an example.
As has been said the current function is already interrupt driven, the only reason I can see for doing a new version is if you have some serious timing constraints and need to detect an EOF char in the ISR or something like that.
I think you can "overload" the default handler, if you have
SIGNAL(USART_RX_vect)
{
// my code here
}
in your program. I know it compiles, I can't vouch for it working though.
cappy2112:
But having a function called automatically no matter where your code is in it's execution is a better way to go.
In what way is it better? Let's say when an interrupt occurs you take some sort of action (like, closing a door). But what if this interrupt occurs while you are in the middle of doing something else (like opening the door)?
You could regard the loop function as a message-despatcher. Even in advanced operating systems like Windows or OS/X, low-level hardware interrupts actually only usually put things into a queue (a message queue) which are pulled out in an orderly way by the application - the main application loop. So the loop function, by checking Serial.available () is effectively checking if a "message" (serial data) is available, at a time when it can be processed in an orderly way.
Perhaps, like a lot of other low-level questions we have seen recently, if we moved away from what you think you need (handling serial interrupts) to what real-world problem you are trying to solve. Is this an RFID security system? A fish-tank feeder? A moon rocket? It might be, for example, that serial data is not the best way of solving this problem. So, whether or not you use interrupts to access that data then becomes irrelevant.
Did you read HardwareSerial.cpp? As Nick says, the interrupt handler on the USART fills a buffer, and Serial.available() just checks that buffer. No polling on the serial port at hardware level.
No. I don't know the layout of the code under the IDE.
I've only used the constructs available in the IDE so far.
Yes, you can save the cycles it takes to check. Perhaps your ISR changes some value that affects your run where until then it doesn't, ie you use the incoming serial as real-time event. A real-time event constricted by baud rate and transmission btw, as opposed to data collected directly on an interrupt-capable I/O pin.
Oh well, you can save cycles checking available() loop after loop. You can also make your code runs very hard to debug.
cappy2112:
But having a function called automatically no matter where your code is in it's execution is a better way to go.
Says who? I don't agree with that statement at all. Again, unless there is a critical need to act immediately on a character why not let the built-in interrupts handle it? Nick mentioned a buffer. Incorrectly he called it a 32-byte, when it is in fact 128 bytes. Regardless, interrupts already handle incoming bytes.
cappy2112:
As long as interrupts are not disabled in loop(), everything just works nicely and loop() doesn't get so cluttered.
I didn't want to work out what RAMEND was for a particular case so I said "at least a 32-byte buffer" which also covers 128 bytes from the define above.
Did you read HardwareSerial.cpp? As Nick says, the interrupt handler on the USART fills a buffer, and Serial.available() just checks that buffer. No polling on the serial port at hardware level.
No. I don't know the layout of the code under the IDE.
I've only used the constructs available in the IDE so far.
The documentation of which says, for Serial.available() (emphasis mine):
Get the number of bytes (characters) available for reading from the serial port. This is data that's already arrived and stored in the serial receive buffer (which holds 128 bytes).
No low level polling or even blocking as I read it. The ISR just writes the buffer (see my former post), your (loop) code reads and handles it. I'd say: well designed.
The documentation of which says, for Serial.available() (emphasis mine):
Well, we all know how much fun it is to maintain documentation, and keep it current, for every variation of the Arduino, without adding so much material that newbies get confused.
The definitive source of information is NOT the documentation. It is the source code.
The definitive source of information is NOT the documentation. It is the source code.
Unfortunate but true.
There is so much to be improved with the documentation but who's gunna do it? Not this little black duck unless the $s are flowing (unlikely to impossible)