Pages: [1] 2   Go Down
Author Topic: Only reading one byte at a time through the serial port  (Read 2105 times)
0 Members and 1 Guest are viewing this topic.
UK
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset



I have an issue which is simple but perplexing at the same time:

I am sending a simple command over the serial port on a Mega 2560 over Serial1 to a device which returns a serial response back. For example I am sending:

const unsigned int STATUS_SEND[] = {0x61, 0x20, 0x11, 0x92};

using a button connected to one of the digital i/o pins correctly configured and all that.

I am expeciting to recieve a hex stream that should be 7120A031, however what I find is the Serial monitor only sends back 71. If I continue to press the button I eventually get the rest after a total of 4 button presses which look like this on the serial monitor:

71
20
A0
31

Now if I use Tera Term and send the commands through there I get the whole stream in one go as I should. I should be getting up to 128 characters through the serial buffer but it doesnt seem to be the case. I havent changed anything and my code to read it is quite standard and straight forward:

Serial1.print(STATUS_SEND);

if (Serial1.available() > 0) {

int read_status = Serial1.read();

Serial.print(read_status, HEX);

}

Any ideas?
Logged

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 74
Posts: 2214
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

you have only asked for one character when checking available so your code may start before 128 bytes of data has been received.

Code:
#define NUMBER_OF_BYTES_REQUIRED  128
if (Serial1.available() >= NUMBER_OF_BYTES_REQUIRED ) {

//Do something with 128 bytes not 1.
int read_status = Serial1.read();

Serial.print(read_status, HEX);

}
« Last Edit: July 12, 2012, 08:13:05 am by pYro_65 » Logged


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

Quote
Only reading one byte at a time through the serial port
That's the way it works. That should come as no surprise.

Quote
I am sending a simple command over the serial port on a Mega 2560 over Serial1 to a device which returns a serial response back. For example I am sending:

const unsigned int STATUS_SEND[] = {0x61, 0x20, 0x11, 0x92};
We'd need to see proof of that.

Quote
using a button connected to one of the digital i/o pins correctly configured and all that.
For what purpose?

Quote
I am expeciting to recieve a hex stream that should be 7120A031, however what I find is the Serial monitor only sends back 71. If I continue to press the button I eventually get the rest after a total of 4 button presses which look like this on the serial monitor:

71
20
A0
31
What you are expecting, and what actually happens, appear to be two different things. Serial data is sent one byte at a time. You need to read the whole reply, one byte at a time.

Quote
Any ideas?
Don't post code snippets. Post all of your code.
Logged

Greenville, IL
Offline Offline
Edison Member
*
Karma: 15
Posts: 1330
Warning Novice on board! 0 to 1 chance of errors!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

 I added comments to the code to explain what is happening. You need to add a code statement that says... do not send "STATUS_SEND" until I have read "x" bytes from Serial1.

Code:
Serial1.print(STATUS_SEND);  // step 1

if (Serial1.available() > 0) {  // step 2 check for byte available

int read_status = Serial1.read(); //read 1 byte save to read_status
 
Serial.print(read_status, HEX);   // print read_status

}

//return to step 1
Logged


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

@pyro_65
With a 64 character serial buffer (1.0+), waiting for the buffer to hold more than 128 characters will require a very long wait. That is not a realistic way of reading large amounts of data.
Logged

UK
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset




Here is my code:

Code:
#include <Bounce.h>



const unsigned int button = 30;
char STATUS_READ[] = {0x61, 0x21, 0x11, 0x92};


void setup() {
 
  Serial.begin(19200);                     //terminal serial port open
  Serial1.begin(38400);                    //DVR Serial port open
  UCSR1C = (UCSR1C & 0xCF) | (0b11 << 4);  //Change serial 1 to odd parity
 
 
  pinMode(button, INPUT);
}

const unsigned int DEBOUNCE_DELAY = 20;
Bounce button_fire(button, DEBOUNCE_DELAY);


void loop() {
  handle_button_fire();
}

void handle_button_fire() {
  if (button_fire.update()) {
    if (button_fire.read() == HIGH) {
     
      Serial1.print(STATUS_READ);
     
      if (Serial1.available() > 0) {
     
      int readstatus = Serial1.read();
      Serial.println(readstatus, HEX);
      }
    }
  }
}


Logged

UK
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset



I know I can get around the problem by having a simple loop that runs 4 times to return what I am expecting, but is there no way to just read the stream buffer as it is because I'm not expecting the hardware will go crazy and send a load of junk down the port?


Quote
#define NUMBER_OF_BYTES_REQUIRED  128
if (Serial1.available() >= NUMBER_OF_BYTES_REQUIRED ) {

//Do something with 128 bytes not 1.
int read_status = Serial1.read();

Serial.print(read_status, HEX);

}

I have tried the above but with no luck...

Logged

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

See the comment above about receive buffer size.
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.

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

Quote
I know I can get around the problem by having a simple loop that runs 4 times to return what I am expecting, but is there no way to just read the stream buffer as it is because I'm not expecting the hardware will go crazy and send a load of junk down the port?
How do you know to expect 4 bytes?

Are you not aware that serial data can get lost?

The fact that you are not expecting the hardware to go crazy is no guarantee that it won't.
Logged

UK
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset



So what your saying is the only way is to read it all is to iterate the read 4 times to get my stream of data?

Logged

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

Quote
So what your saying is the only way is to read it all is to iterate the read 4 times to get my stream of data?
I'm saying that that might not even work. Data can be lost, so you only might get less than bytes. Hardware can generate unexpected results, so you might get more than 4 bytes.

You need to either wait a little while for a response, and then read everything available (not the preferred solution) or read all the data until the end-of-packet marker arrives. Of course, this means that the device needs to send some end of packet marker and that you know what the end of packet marker is (and that it doesn't get lost).

If you don't know what the end of packet marker is, or there isn't one, then, depending on what else the Arduino is doing, perhaps a function that read all the data that arrived in the next 100 milliseconds might be appropriate to call. If 100 milliseconds is too long, make it shorter. You'll need to experimentally determine how long to wait for the data. The millis() function would prove useful for determining how long you have been waiting for data.
Logged

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 74
Posts: 2214
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@pyro_65
With a 64 character serial buffer (1.0+), waiting for the buffer to hold more than 128 characters will require a very long wait. That is not a realistic way of reading large amounts of data.

And if someone said they "feel like shit" would you poo on a plate? smiley

Enlarge the serial buffer.

...If you are performing a calculation on a large amount of data, that cannot be calculated without all data, then you really have no option but waiting. Also if you are stressing that a blocking loop is time consuming, then simply don't block. Copying out into a working data buffer might have no actual benefit over storing the data in an enlarged serial buffer unless you need more than one pass of the data.

The point I was stressing is the code was expected read more than one byte, so therefore a wait for an acceptable amount of data is closer to what is expected.

Quote
I have tried the above but with no luck...

Probably won't as it waits for 128 bytes ( standard serial support 64 ) and only reads one byte into an int.
Logged


UK
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


I can understand your logic if I had a load of data coming in, but 4 bytes per message sent which will be approximately once every 5 seconds to check status, seems a bit complicated..at the data rate of the dvr which is 38400bps, it roughly means it sends 4.8bytes/ms which means my timer would only have to wait 1ms...unfortunately no terminating character is sent except the last byte is a modulo-256 checksum of 3 bytes before it.
Logged

New Hampshire
Offline Offline
God Member
*****
Karma: 17
Posts: 781
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


I can understand your logic if I had a load of data coming in, but 4 bytes per message sent which will be approximately once every 5 seconds to check status, seems a bit complicated..at the data rate of the dvr which is 38400bps, it roughly means it sends 4.8bytes/ms which means my timer would only have to wait 1ms...unfortunately no terminating character is sent except the last byte is a modulo-256 checksum of 3 bytes before it.

That is completely incongruous to all your previous posts, which talked about a stream of 128 characters coming in.

The quality of the help you receive will almost always be directly proportional to the quality of the information you provide.

That being said, Serial comms should NEVER be coupled to some external activity (in this case, a button press).  Execute your Serial comms completely independently of everything else, store the necessary results somewhere, and then act upon them when necessary (either immediately, or if necessary based on that external activity).

What is this dvr you referred to as well.  Based on your last post, it sounds like the proper means of handling incoming serial data is with a small 4 character ring buffer, constantly checking for a valid checksum with each character read in, until you have a valid checksum, and thus a valid packet of data.  With the absence of any synchronizing  characters, there aren't m/any other options for properly processing the incoming data.
Logged


Peoples Republic of Cantabrigia
Offline Offline
God Member
*****
Karma: 6
Posts: 722
Arduino happiness
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

My recommendation is to use Bill Porters EasyTransfer to help with this sort of problem. It performs CRC checks, so if the data is good, you can send it back to the Mega and verify that the right data was received. If the data wasn't good then you can signal that too.
Logged

Pages: [1] 2   Go Up
Jump to: