Pages: [1] 2   Go Down
Author Topic: How do I detect if I'm receiving serial data.  (Read 953 times)
0 Members and 1 Guest are viewing this topic.
DK
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi there.

I've googled and googled and haven't found any solution for my problem. I hope someone in here knows how to do it the right way.

The problem is, that I need to know if somebody is sending me data, before I send data back. In other words, a simple kind of collision detection.

In psudo code:


Code:
#define LINE_CLEAR_SPAN 500

void sendData() {
  long timeSinceLastByteReceived = SomeMethodToGetTheTimeSinceLastByteReceived();
  while (timeSinceLastByteReceived < LINE_CLEAR_SPAN)
  {
     delay(TIME_OUT);
     timeSinceLastByteReceived = SomeMethodToGetTheTimeSinceLastByteReceived();
  }
  // ok clear to send!
  Serial.write("yeah!");
}

But how do I get the information from Serial? How do I implement the "SomeMethodToGetTheTimeSinceLatByteReceived()"?

I thought about some kind of interrupt that resets a counter each time the Serial receives a byte. But how do I attach an interrupt handler to the serial device?

If nobody guessed it by now, I need to say, that i'm a totally newbie in embedded programming. So please be gentle!

Thanks!

Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 289
Posts: 25697
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Why an interrupt?
Could you use "Serial.available"?
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

DK
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

He - well yeah.. I suppose I could. But then I can not know how long I need to wait before sending.

It's okay that something is in the buffer as long as it's received longer ago than "time between messages". But then again - maybe it's my design that sucks then. I'm used to use threads, mutex'es and managed garbage collection.




Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 289
Posts: 25697
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
But then I can not know how long I need to wait before sending
Why not?
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

DK
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

As it is now - the logic in my program looks like this.
Code:
void loop()
{
  while (Serial.available() > 0)
  {
    //handle the incoming data.
  }
  //do some plumbing
  //[...]
  sendMessage();
}

If I understand correctly - the uart will/could still receive data while I'm doing other stuff in my loop. When I send my message I need to be sure that I send the message at least let's say 30 ms after the last byte has been received/buffered by the uart. In the time span between "Serial.Available == 0" and I call "SendMessage()" data could have been received and if I send my message without waiting, contention occurs.








Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
When I send my message I need to be sure that I send the message at least let's say 30 ms after the last byte has been received/buffered by the uart.
Why?

Data arrives on the serial port when it wants to. You have no way of knowing when the interrupt that processed the serial data occurred.

At best, you could periodically check the amount of data in the buffer. Store the time you do that. At some future time, if the amount of data is still the same, and your desired interval has elapsed, send the message.
Logged

DK
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
When I send my message I need to be sure that I send the message at least let's say 30 ms after the last byte has been received/buffered by the uart.
Why?

Because my serial port is connected to a bus.  On the bus datagrams between 4-8 bytes is sent. If somebody else is sending a datagram on the bus, I'd ruin it by starting sending my datagram when the other part has sent f.x. two bytes out of four. Thus I'll have to wait until the other part has finished sending his datagram to minimize the risk on contention.

Data arrives on the serial port when it wants to. You have no way of knowing when the interrupt that processed the serial data occurred.

I just started all this electronics stuff so please forgive me. But isn't it somehow possible to connect the rx-line both to the rx-pin and to another pin (through some resister) on the arduino and detect when it goes low? Then I could attach an interrupt routine and reset some kind of timer each time the rx-line goes low.

Code:
volatile long lastByteReceived;

//called when the interrupt occurs.
void onRxGoesLow()
{
  lastByteReceived = millis();
}

//called by my send routine.
byte timeSinceLastByteReceived()
{
  return millis() - lastByteReceived;
}

At best, you could periodically check the amount of data in the buffer. Store the time you do that. At some future time, if the amount of data is still the same, and your desired interval has elapsed, send the message.

Okay.. Do you know where I can read about accessing the serial buffer? (I don't know what I should search for).

Logged

New Jersey
Offline Offline
Faraday Member
**
Karma: 65
Posts: 3638
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Could you give a view of the bigger picture - what are you trying to do?
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 289
Posts: 25697
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Do you know where I can read about accessing the serial buffer?
Serial.read will return the next character available, if there is one, or return -1 if there isn't.
Serial.available will tell you how many characters are in the serial buffer (including zero if there aren't any)

What more access do you need?
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

DK
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Do you know where I can read about accessing the serial buffer?
Serial.read will return the next character available, if there is one, or return -1 if there isn't.
Serial.available will tell you how many characters are in the serial buffer (including zero if there aren't any)

What more access do you need?

Not much more I guess. I'll check tonight if the following works. I'm not sure if I like the solution, but if it works it's okay for now. Thanks.

Code:
#define CONTENTION_TIMEOUT 30
void WaitForBusClear()
{
  if (Serial.available() > 0)
  {
    int count = Serial.available();
    delay(CONTENTION_TIMEOUT);
    while (Serial.available() > count)
    {
      count = serial.available();
      delay(CONTENTION_TIMEOUT);
    }
  }
}
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 126
Posts: 8471
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It sounds like you want to detect an idle bus. For my money the best way to do this is start a timer and reset it every time there is an edge on the RX pin. If the timer ever reaches 0 nobody has transmitted for N time and you can go.

BUT

If you have more than one node doing this (and you will or there's not point in the first place) you will have a race condition.

How will you know that another node hasn't done exactly the same thing? You have to detect bus clashes and try again after a random period.

This is a multiple access protocol and it needs a lot of deep thought.

______
Rob
« Last Edit: August 18, 2011, 07:20:31 am by Graynomad » Logged

Rob Gray aka the GRAYnomad www.robgray.com

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I'm not sure if I like the solution, but if it works it's okay for now.
I know I don't like it. Something like this maybe:

Code:
int oldCount = 0;
int newCount = 0;
unsigned long lastSerial = 0;

void loop()
{
   newCount = Serial.available();
   if(newCount != oldCount)
   {
      oldCount = newCount;
      lastSerial = millis();
   }

   // Rest of loop
}

Then a function to send data
Code:
void sendFunc(/*whatever args are needed*/)
{
   unsigned long currTime = millis();
   // Diddle until enough time has elapsed
   // since last serial data received
   while(currTime - lastSerial < CONTENTION_TIMEOUT)
   {
      // Check for new serial data
      newCount = Serial.available();
      if(newCount != oldCount)
      {
         oldCount = newCount;
         lastSerial = millis();
      }
      currTime = millis();
   }
   // When we get to here, no serial data was
   // received in the last CONTENTION_TIMEOUT
   // milliseconds

   // Send the data...
}
Logged

DK
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It sounds like you want to detect an idle bus. For my money the best way to do this is start a timer and reset it every time there is an edge on the RX pin. If the timer ever reaches 0 nobody has transmitted for N time and you can go.

Well that's exactly what I've tried to explain you all that I needed! smiley If then somebody could tell me HOW I could detect an edge on the RX pin (how would I wire it up) and how to attach an interrupt handler method. (please)
 
BUT

If you have more than one node doing this (and you will or there's not point in the first place) you will have a race condition.

How will you know that another node hasn't done exactly the same thing? You have to detect bus clashes and try again after a random period.

This is a multiple access protocol and it needs a lot of deep thought.

I'm aware of the risks. Garbage packages will be discarded (and is expected). The timeout value will be arbitrary, and I think this would solve most clashes.


Logged

DK
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I'm not sure if I like the solution, but if it works it's okay for now.
I know I don't like it. Something like this maybe:

Thanks!  If I can't get the idle detection working, I'll try to work something out based on both mine and your code examples.
Logged

DK
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I know I don't like it. Something like this maybe:

After a second thought.. Would you mind explain to me why you prefer your own solution and don't like mine?
Logged

Pages: [1] 2   Go Up
Jump to: