i have a problem reading data from serial.
Small Datasets aren´t the problem, but when it comes to bigger sets like 1024 bytes it gets a little tricky.
The Problem is the there is always a shift of 256 bytes in my array and i´m not really sure why.
Below is my code, i hope somebody can help me.
I have a startmarker, so i now every answer must start with 65 0 1 83, but there is no endmarker, i just know that the telegram must have 1208 bytes. So normally it shoudnt be that hard,
void setup() {
Serial2.begin(38400, SERIAL_8N1, RXD2, TXD2); // Start Regulator Serial
}
void loop() {
readRegulator();
}
char TXBuffer[1000], RXBuffer[2000];
int PARAMS[1000];
unsigned int txp, rxp, ChecksumModBus;
int switchTelegram;
void readRegulator() {
unsigned int Crc;
txp = 0, rxp = 0;
delay(10000);
if(switchTelegram == 2) {
TXBuffer[txp++] = 80; // Adresse 0
TXBuffer[txp++] = 0; // Function 3
TXBuffer[txp++] = 1; // Function 3
TXBuffer[txp++] = 83; // StartAddr HB
TXBuffer[txp++] = 01; // StartAddr LB
TXBuffer[txp++] = 01; // Anzahl HB
TXBuffer[txp++] = 00; // Anzahl LB
TXBuffer[txp++] = 00; // Anzahl LB
}
ChecksumModBus = 0;
for (int i = 0; i < txp; i++) {
ChecksumModBus ^= TXBuffer[i];
}
Crc = ~ChecksumModBus;
TXBuffer[txp++] = ChecksumModBus;
TXBuffer[txp++] = Crc;
Serial.println("Send");
for (int i = 0; i < txp; i++) Serial2.write(TXBuffer[i]);
delay(100); // Added this line
//Serial.println("Data Received:");
while(Serial2.available()) {
char inChar;
/*
inChar = (char)Serial2.read();
RXBuffer[rxp++] = inChar;
delayMicroseconds(750); // inter character time out */
Serial2.readBytes(RXBuffer, 1208);
if(switchTelegram == 2) {
if(RXBuffer[0] == 65 && RXBuffer[1] == 0 && RXBuffer[2] == 1 && RXBuffer[3] == 83 && (((int)RXBuffer[1206] + (int)RXBuffer[1207]) == 255)){
for (int rxCnt = 0; rxCnt < 600; rxCnt++) {
unsigned char Hbyte = RXBuffer[6 + (rxCnt * 2)];
unsigned char LByte = RXBuffer[7 + (rxCnt * 2)];
int value = (int)(Hbyte + (LByte * 256));
PARAMS[rxCnt] = value;
}
for(int i = 1204; i < 1208; i++) {
Serial.println((int)RXBuffer[i]);
}
}
//memset(RXBuffer, 0, sizeof(RXBuffer)); // Removed this line
}
}
switchTelegram = 2;
}
Note Serial.readBytes() also stops reading after a time out! So you should use at least the return value to check if it indeed read 1208 bytes.
Next up, you expect a start marker after which you want to read 1204 more bytes. Why do you do excellently the opposite? You start by reading 1208 bytes, having NO CLUE where you actually start reading the data. After which you expect the start marker to be at the start of the stream...
Do you really need to set every every entry to 0 again?
int value = (int)(Hbyte + (LByte * 256));
You do know you make Hbyte the Low byte and the Lbyte the High byte here? Also shifting is considered to be more readable then multiplying
You need to post a complete program that demonstrates the problem.
What timeout have you set for readBytes() ?
What is sending the data? IMHO it would be much better to receive the data in smaller chunks. Have a look at the examples in Serial Input Basics - simple reliable ways to receive data.
Hi, thanks for the fast reply, i will change me code above.
septillion:
Note Serial.readBytes() also stops reading after a time out! So you should use at least the return value to check if it indeed read 1208 bytes.
I´ve done that and i´m always getting 256 as return value.
septillion:
Next up, you expect a start marker after which you want to read 1204 more bytes. Why do you do excellently the opposite? You start by reading 1208 bytes, having NO CLUE where you actually start reading the data. After which you expect the start marker to be at the start of the stream...
I know, but i´ve no clue how to change this. Is is possible to Read only 4 Bytes and then the last 1204 bytes?
septillion:
Do you really need to set every every entry to 0 again?
No, but its easier to detect if there is an error in my array.
septillion:
int value = (int)(Hbyte + (LByte * 256));
You do know you make Hbyte the Low byte and the Lbyte the High byte here? Also shifting is considered to be more readable then multiplying
I´m also getting data via modbus thats the reason why it is in the wrong order.
Robin2:
What timeout have you set for readBytes() ?
I dont have set any timeout
Robin2:
What is sending the data? IMHO it would be much better to receive the data in smaller chunks. Have a look at the examples in Serial Input Basics - simple reliable ways to receive data.
I also can get the data via modbus telegram but i need 1200 values, with modbus i have to make 6 different telegrams, so i would prefer getting everything a once.
UPDATE:
Now i´m receiving the data, what i have done is, i added a delay of 100 milliseconds before the while(serial2.available) and removed the memset. Even the checksum is correct, but i´m not understanding why it is working. I have read that the serial is very slow, so i thought maybe put a small delay so that the data can transfer.
MarcelW:
I´ve done that and i´m always getting 256 as return value.
First though was that readBytes() may only do up to 256 bytes but the fact it works now points to something else. But as I said, I really think using Serial.readBytes() is a terrible approach because of it's blocking nature.
MarcelW:
I know, but i´ve no clue how to change this. Is is possible to Read only 4 Bytes and then the last 1204 bytes?
Then you clearly didn't read the article Robin2 and I linked to
MarcelW:
No, but its easier to detect if there is an error in my array.
Fair enough. But I would remove it after debugging.
MarcelW:
I´m also getting data via modbus thats the reason why it is in the wrong order.
So? Is that a reason to use confusing variable names?
MarcelW:
I dont have set any timeout
Then it defaults to 1000ms.
MarcelW:
but i´m not understanding why it is working. I have read that the serial is very slow, so i thought maybe put a small delay so that the data can transfer.
Yeah, you probably timed out readBytes(). And depending on the speed (but again, can't say from a crappy snippet ) Serial can be very very very slow compared to the Arduino. And that's why it's best to NOT lock it into receiving data. Just read the data byte by byte when it becomes available. Heck, that way you don't even need a hellish 1208 bytes large array. Because you can just set PARAM[] every two bytes read (after receiving a start signal).
So yeah, we know you guys don't like to read long articles or being told the approach you have now isn't good. But if you want to have good/reliable/clear code you better do
septillion:
Yeah, you probably timed out readBytes(). And depending on the speed (but again, can't say from a crappy snippet )
I´ve updated my snippet, do you miss something? baud is 38k.
septillion:
So yeah, we know you guys don't like to read long articles or being told the approach you have now isn't good. But if you want to have good/reliable/clear code you better do
I have no problem with reading long articles and i know my approach is not the best, i even said that i want to understand why it is working, but its also not easy to work on a problem for hours and beeing a little bit helpless
septillion:
Just read the data byte by byte when it becomes available. Heck, that way you don't even need a hellish 1208 bytes large array. Because you can just set PARAM[] every two bytes read (after receiving a start signal).
I´m understanding what u want me to say but i´m not really sure how to do this.
Do you have a small example for me? Would me help a lot. And yes i have overflown the article of robin but its so much input at once.
Ahh, updating posts is very very confusing. Just make a new post if you want to add info.
And the example is almost 99% in the article of Robin2 Only he uses a single digit start marker and a stop marker. Not to hard to think of how to extend it to have multiple start markers and just count instead of a stop marker.
But, how do you know the stream never has the values (aka, PARAM's) 65 followed by 21249 in it? Aka, the start marker as data? You don't seem to write to code for the sending bit but just curious
septillion:
Ahh, updating posts is very very confusing. Just make a new post if you want to add info.
And the example is almost 99% in the article of Robin2 Only he uses a single digit start marker and a stop marker. Not to hard to think of how to extend it to have multiple start markers and just count instead of a stop marker.
But, how do you know the stream never has the values (aka, PARAM's) 65 followed by 21249 in it? Aka, the start marker as data? You don't seem to write to code for the sending bit but just curious
Also, which board are you using?
Hi, sorry for the long absence, i was on holiday.
I´m still trying to fix this and i think i found the problem.
When i´m displaying the Serial.available() it starts by 0 and then goes to 256, and at the end i´m missing some chars. So i think i´m getting an overflow and thats the reason why Serial.read() is not working but Serial.readByte is.
Changing RX_BUFFER is not really working, do you have an idea whats wrong?
EDIT :
I have changed the baud rate from 38k to 9600 and no everything is working like it should, the Serial.available never overflows. So the only problem now is to change the buffer size, but change it in HardwareSerial.h is not working.
MarcelW:
Hi, sorry for the long absence, i was on holiday.
I´m still trying to fix this and i think i found the problem.
Please post the latest version of your program in your next Reply. Also please describe in detail what it does and what you want it to do that is different.
I´m just waiting for Serial2 to be available, if this is the case, i´m reading byte by byte.
As mentioned before the "Serial.print(Serial2.available())" reaches 255, so there must be some kind of overflow. This appears with a baud of 38400, with 9600 baud the byte buffer of Serial2 never goes that high.
So now i´m looking for a way to extend the buffer.
Robin2:
What is RXBuffer[]? It is not defined in your program - maybe you have not posted the complete program?
...R
char TXBuffer[1000], RXBuffer[2000];
its the complete program, i have just ignored the includes and defines.
septillion:
The Serial buffer is big enough as it is. You just have to read it more often if it overflows. Making it larger will just delay the problem.
How can i read it faster? Making it larger would not delay the problem, if i could set it to 512 byte it would never overflows because i´m not sending that much at once.
I would not have a complex IF statement like this in any of my programs. I would have no confidence in what it does. I would at least make it a series of cascaded IF statements as that would allow me to Serial.print() statements in different parts to check what is happening.
Are you trying to analyse the data as it arrives or have you enough space in your buffer to save the whole incoming message. If the latter then I would receive all the data before trying to analyse any of it.
Robin2:
I would not have a complex IF statement like this in any of my programs. I would have no confidence in what it does. I would at least make it a series of cascaded IF statements as that would allow me to Serial.print() statements in different parts to check what is happening.
Are you trying to analyse the data as it arrives or have you enough space in your buffer to save the whole incoming message. If the latter then I would receive all the data before trying to analyse any of it.
...R
I have enough space to save the complete message, the message that i´m receiving is exactly 1207 bytes long, byte 1206 and 1207 is the checksum of the message.
The problem is that the serial.read() is to slow when i have a baudrate of 56k, so it is only reading around 800 bytes because there is an overflow in der serial.available buffer
MarcelW:
The problem is that the serial.read() is to slow when i have a baudrate of 56k, so it is only reading around 800 bytes because there is an overflow in der serial.available buffer
Can you write a short program that does nothing else than check the serial input buffer and save the data to your array?
Oh, wait, the second example in the link I gave you in Reply #2 should do that. Have you tried it?
MarcelW:
That's exactly that what I´m already doing.
The code in Reply #18 is not the same as the example in my Tutorial. Why not try the example with no changes except those needed to deal with the larger char array?