Hello,
I have device connected to Arduino using RS232, which is sending me a frame with 253 bytes length. I was looking for help in Google, but I couldn't find any solution. Does exist one?
Have a look at serial input basics. It will receive as many bytes as you have space in memory for. Just change the value of numChars from 32 to whatever you need.
...R
Found this page on the web...
Robin2:
Have a look at serial input basics. It will receive as many bytes as you have space in memory for. Just change the value of numChars from 32 to whatever you need....R
Unfortunately, it is not working. I know that my receiving frame has 253 bytes and it ends with 16 (in HEX). I modify this sketch for my purpose:
const byte numChars = 255;
char receivedChars[numChars]; // an array to store the received data
unsigned long pomocnicza = 0;
#define interwal 60000
boolean newData = false;
byte frame[] = {0x10, 0x5B, 0xFE, 0x59, 0x16};
int dataNumber = 0; // new for this version
void setup() {
Serial1.begin(9600, SERIAL_8E1);
Serial.begin(115200);
delay(1000);
for (int i = 0; i < 5; i++)
{
Serial1.write(frame[i]);
delayMicroseconds(1719);
}
delayMicroseconds(3438);
}
void loop() {
recvWithEndMarker();
showNewData();
}
void recvWithEndMarker() {
static byte ndx = 0;
char endMarker = 0x16;
char rc;
if (Serial1.available() > 0) {
rc = Serial1.read();
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
newData = true;
}
}
}
void showNewData() {
if (newData == true) {
dataNumber = 0; // new for this version
dataNumber = atoi(receivedChars); // new for this version
Serial.print("This just in ... ");
Serial.println(receivedChars);
Serial.print("Data as Number ... "); // new for this version
Serial.println(dataNumber); // new for this version
newData = false;
}
}
Nothing happened on Serial - I think the newData hasn't change to TRUE, because he read only about 114 bytes instead of 253 bytes.
bcarteruk:
Found this page on the web...
This is solution for Arduino 1.0.1. I was looking in HardwareSerial.cpp and there is no #define SERIAL_BUFFER_SIZE 64. I checked on HardwareSerial.h and there is something similar, but it is about RX and TX. I've changed it from 16 and 64 to 256 and reset arduino software - nothing changed. I also change boards.txt, but still I read only 114 bytes - no more.
A quick search shows for 1.5.8 SERIAL_BUFFER_SIZE is defined in ringbuffer.h and usbapi.h you could try changing these..
As for your code I would try setting ndx+1 to \0 and always running shownewdata so that I could see the buffer being built as it is received . This might cause data overruns due to print overhead but should confirm that you are receiving something.
receivedChars[ndx] = rc;
ndx++;
receivedChars[ndx] = '\0';
bcarteruk:
A quick search shows for 1.5.8 SERIAL_BUFFER_SIZE is defined in ringbuffer.h and usbapi.h you could try changing these..As for your code I would try setting ndx+1 to \0 and always running shownewdata so that I could see the buffer being built as it is received . This might cause data overruns due to print overhead but should confirm that you are receiving something.
receivedChars[ndx] = rc;
ndx++;
receivedChars[ndx] = '\0';
I can't find ringbuffer.h at all
I've changed it in usbapi.h, but I think there will change nothing because I'm using Serial1 to receive this "big" amount of data. I changed from receivedChars[ndx] = '\0'; to receivedChars[ndx+1] = '\0'; and disable "newData" to show me every time what is in receivedChars. Now my code looks like :
const byte numChars = 254;
char receivedChars[numChars]; // an array to store the received data
unsigned long pomocnicza = 0;
#define interwal 6000
boolean newData = false;
byte frame[] = {0x10, 0x5B, 0xFE, 0x59, 0x16};
int dataNumber = 0; // new for this version
void setup() {
Serial1.begin(9600, SERIAL_8E1);
Serial1.setTimeout(interwal);
Serial.begin(115200);
delay(3000);
for (int i = 0; i < 5; i++)
{
Serial1.write(frame[i]);
delayMicroseconds(1719);
}
delayMicroseconds(3438);
}
void loop() {
recvWithEndMarker();
showNewData();
}
void recvWithEndMarker() {
static byte ndx = 0;
byte endMarker = 0x16;
byte rc;
if (Serial1.available() > 0) {
rc = Serial1.read();
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx+1] = '\0'; // terminate the string
ndx = 0;
newData = false;
}
}
}
void showNewData() {
if (newData == false) {
//dataNumber = 0; // new for this version
//dataNumber = atoi(receivedChars); // new for this version
Serial.print("This just in ... ");
Serial.println(receivedChars);
//Serial.print("Data as Number ... "); // new for this version
//Serial.println(dataNumber); // new for this version
// newData = false;
}
}
And this is what I've got in Serial0 Monitor:
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This is not so many buffer (<64 for 100%) it is only start of my buffer. Any ideas?
REACTIVE86:
Unfortunately, it is not working. I know that my receiving frame has 253 bytes and it ends with 16 (in HEX). I modify this sketch for my purpose:Nothing happened on Serial - I think the newData hasn't change to TRUE, because he read only about 114 bytes instead of 253 bytes.
I can't think why it would not work unless the transmitted data is not what you think it is.
Try adding some Serial.println()s into the function recvWithEndMarker() so you can see what is going on. Maybe also add a counter to keep track of how many bytes are received.
Have you the scope to change the transmitted data as part of the debugging process ?
I note you are using SERIAL_8E1 - I presume that is correct, _8N1 is more common.
Is your transmitting device a "real" RS232 device using 12v signal levels? If so have you converted them to TTL voltage levels. If not you may damage your Arduino.
AND ... changing the buffer size in the Serial library is completely unnecessary.
...R
Remove the calls to delay() and your MBUS code might start working. You are allowing
the HardwareSerial RX buffer to overflow by deliberately not looking at it for ages....
Forget all the above advice about altering the libraries, once you start reading the serial port
promptly there's no chance the HardwareSerial buffer will fill up at all at 9600 baud, that
would take 73 ms and loop will be running every few us....
Helping people by mentioning MBUS in the title too would be useful.
REACTIVE86:
I can't find ringbuffer.h at allI've changed it in usbapi.h, but I think there will change nothing because I'm using Serial1 to receive this "big" amount of data. I changed from
receivedChars[ndx] = '\0';toreceivedChars[ndx+1] = '\0';and disable "newData" to show me every time what is in receivedChars. Now my code looks like :const byte numChars = 254;
char receivedChars[numChars]; // an array to store the received data
unsigned long pomocnicza = 0;
#define interwal 6000
boolean newData = false;
byte frame[] = {0x10, 0x5B, 0xFE, 0x59, 0x16};
int dataNumber = 0; // new for this version
void setup() {
Serial1.begin(9600, SERIAL_8E1);
Serial1.setTimeout(interwal);
Serial.begin(115200);
delay(3000);
for (int i = 0; i < 5; i++)
{
Serial1.write(frame[i]);
delayMicroseconds(1719);
}
delayMicroseconds(3438);
}
void loop() {
recvWithEndMarker();
showNewData();
}
void recvWithEndMarker() {
static byte ndx = 0;
byte endMarker = 0x16;
byte rc;
if (Serial1.available() > 0) {
rc = Serial1.read();
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx+1] = '\0'; // terminate the string
ndx = 0;
newData = false;
}
}
}
void showNewData() {
if (newData == false) {
//dataNumber = 0; // new for this version
//dataNumber = atoi(receivedChars); // new for this version
Serial.print("This just in ... ");
Serial.println(receivedChars);
//Serial.print("Data as Number ... "); // new for this version
//Serial.println(dataNumber); // new for this version
// newData = false;
}
}
And this is what I've got in Serial0 Monitor:This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/
This just in ... h÷÷h2rP$8i-,/This is not so many buffer (<64 for 100%) it is only start of my buffer. Any ideas?
Yes, indeed.
When I sending frame - 10 5B FE 59 16 I should receive exactly 253 bytes, which I can see, because when I'm using PComm Terminal Emulator and sending this frame from my computer I got 253 bytes. When I'm sending the same frame using Arduino Leonardo I'm getting right now only 114bytes and this is it.
8E1 is for purpose - it is needed in communication with MBus devices. This is real RS232 with proper voltage (look below about sending frame from computer).
MarkT:
Remove the calls to delay() and your MBUS code might start working. You are allowing
the HardwareSerial RX buffer to overflow by deliberately not looking at it for ages....Forget all the above advice about altering the libraries, once you start reading the serial port
promptly there's no chance the HardwareSerial buffer will fill up at all at 9600 baud, that
would take 73 ms and loop will be running every few us....Helping people by mentioning MBUS in the title too would be useful.
I need only one delay - delayMicroseconds in loop for in "wyslij" function to properly frame sending. Now my program is looks like that:
byte buffer[254];
#define timeOut 5000
byte j;
byte i = 0;
unsigned long helping = 0;
#define interval 6000
byte frame[] = {0x10, 0x5B, 0xFE, 0x59, 0x16};
void setup() {
Serial.begin(115200);
Serial1.begin(9600, SERIAL_8E1);
Serial1.setTimeout(timeOut) ;
}
void loop()
{
if (Serial1.available() > 0)
{
j = Serial1.readBytes(buffer, 254);
for (int i = 0; i < j; i++)
{
Serial.write(buffer[i]);
}
}
if (millis() - helping > interval)
{
for (int i = 0; i < 5; i++)
{
delayMicroseconds(1719);
Serial1.write(frame[i]);
}
helping = millis();
}
}
Unfortunately I'm not receiving whole frame 253 bytes. Under you have a proof:
COM2 is RS232 from Computer and COM17 is USB from Arduino.
You packetizing should be in terms of timeouts, not the expectation of seeing valid packets. If
you are always looping and calling Serial1.available() bump from 0 to 1 then you can call millis()
to determine the time of arrival of each byte. If the time since the last byte is greater than
some threshold (or that time has elapsed with no more incoming bytes), then the previous
input is a complete packet, which you can then go and parse, sanity and parity check...
Looking for a terminating 0x16 is brittle and risks an infinite loop.
The MBUS spec is horrible alas, good luck there...
MarkT:
You packetizing should be in terms of timeouts, not the expectation of seeing valid packets. If
you are always looping and calling Serial1.available() bump from 0 to 1 then you can call millis()
to determine the time of arrival of each byte. If the time since the last byte is greater than
some threshold (or that time has elapsed with no more incoming bytes), then the previous
input is a complete packet, which you can then go and parse, sanity and parity check...Looking for a terminating 0x16 is brittle and risks an infinite loop.
The MBUS spec is horrible alas, good luck there...
I threw away that code. Now I have a little different. Millis() should not take affect to receiving frame, because when Serial1.available() it will copy whole frame to my buffer - it should be, but there is something wrong. If I would have whole frame, the rest is very easy in MBus ![]()
You're calling delayMicroseconds now! Don't do this!
loop() should always be running often enough (at least once each millisecond) that you have correct
millisecond granularity timestamps on each byte read - you suck on Serial.read() as fast as it gets
bytes.
In particular you need to use non-blocking writes (look up availableForWrite()) if expecting incoming
packets while outputing a packet (ie more than one slave on the bus).
This is basic packet networking, not a simple serial interface.
MarkT:
You're calling delayMicroseconds now! Don't do this!
I need this, because on this baud (9600) if I erase it, it will send me bad frame. How can I change it to micros() to send proper frame?
UPDATE:
I erase that line, but still I can't receive whole frame ![]()
MBUS specifies 11 bit serial, with no delay between characters within a packet.
Perhaps you are trying to wait for all the bytes to go out - look at availableForWrite(), it will
tell you when the buffer's empty, then you only have to allow for the last byte
going out, which is done using millis(), not delay() - calling delay will risk losing input.
int tx_buffer_size ;
void setup ()
{
Serial1.begin (9600, SERIAL_8E1) ;
tx_buffer_size = Serial1.availableForWrite () ;
}
int bytes_in_tx_buffer ()
{
return tx_buffer_size - Serial1.availableForWrite () ;
}
This sort of coding needs to be done as two state machines, one driving output,
one driving input and neither holding the other up - such synchronization belongs
in the application layer, not at the low level.
OK, I modified my code to:
byte buffer[254];
int j=0;
byte frame[] = {0x10, 0x5B, 0xFE, 0x59, 0x16};
int tx_buffer_size ;
void setup ()
{
Serial.begin(115200);
Serial1.begin(9600, SERIAL_8E1);
Serial1.setTimeout(6000) ;
delay(3000);
for (int i = 0; i < 5; i++)
{
Serial1.write(frame[i]);
}
tx_buffer_size = Serial1.availableForWrite () ;
Serial.write(tx_buffer_size);
}
void loop()
{
if (Serial1.availableForWrite())
{
j = Serial1.readBytes(buffer, 254);
for (int i = 0; i < j; i++)
{
Serial.write(buffer[i]);
}
}
}
int bytes_in_tx_buffer ()
{
return tx_buffer_size - Serial1.availableForWrite () ;
}
I don't really know how to use function bytes_in_tx_buffer() ? On the beginning of program I'm checking and writing how many data is AvailableForWrite in Serial1 and I can see only "3C" = 60dec, but After loop() I'm getting about 130 bytes, which the last 10 is wrong.
No no no no.
I told you to do this:
Serial1.begin (9600, SERIAL_8E1) ;
tx_buffer_size = Serial1.availableForWrite () ;
and you then do this:
Serial1.begin(9600, SERIAL_8E1);
Serial1.setTimeout(6000) ;
delay(3000);
for (int i = 0; i < 5; i++)
{
Serial1.write(frame[i]);
}
tx_buffer_size = Serial1.availableForWrite () ;
You set tx_buffer_size when you know the tx_buffer is empty, immediately after
begin() and before any writes .... The whole idea is you need a programmatic
way to know the size of the buffer!!!!
Then you do this:
void loop()
{
if (Serial1.availableForWrite())
{
j = Serial1.readBytes(buffer, 254);
for (int i = 0; i < j; i++)
{
Serial.write(buffer[i]);
}
}
}
And I just despair!
Read only when there's a byte to be read, write only when there's a space in the tx-buffer,
keep timestamps for each byte read so you know where the RX packet ends, do everything
without blocking.
Look, the basic outline is:
void loop()
{
if (millis () - last_read_time > TIMEOUT)
{
handle_incoming_packet () ;
}
if (Serial1.available () > 0)
{
char ch = Serial1.read () ;
last_read_time = millis () ;
// and stick it in the packet buffer if there's room
}
if (outgoing_buffer_not_empty && Serial.availableForWrite () > 0)
{
char ch = extract_from_outgoing buffer () ;
Serial1.write (ch) ; // this cannot block
}
}
Then the rest of the code can elect to fill an outgoing packet, and handle incoming ones.
All the I/O is asynchronous and non-blocking.
You can elect to queue up packets until bytes_in_tx_buffer() returns 0 and a certain
extra time has elapsed if you want to avoid dropping new outgoing packets ontop
on an existing exchange. That would need a queue - you could alternatively use
a flag to indicate "transaction in progress" and refuse new transactions until its
been cleared.