This is my first foray into programming microconttrollers so forgive any obvious mistakeI have not picked up on.
My project heavily relies on a robust serial link to a PC, where messages are in the format of unique identifiers as a frame, three characters as a command and four preceeding characters as data.
I am trying to accept data framed in the appropriate manner an ignore any other spurious data.
On recieving a frame, strip the command and data characters out of the frame into seperate arrays.
So far I am getting funny results. In the code shown below, the serialmonitor shows that i am not printing ch_array to the serial port and my command and data array are printed to the serial port minus a character.
Struggling to get my head round this one. I'd appreciate any general comments and hopefully a solution
Forgive the messines of the code it is posted mid-frustration/debugging.
//13.02.2014
//Serial comms control between PC & Arduino
//Serial frame format [STX]{Cmd}{Data}[EOT]
//Sends [ACK] and message retransmit as confirmation of recieved data
//Strips cmd and data out of recieved buffer into two arrays
//
//Serial Handshaking bytes//
const byte STX = 'q'; //0x02; //Start Transmission
const byte EOT = 'w'; //0x04; //End Transmission
const byte ACK = 'e'; //0x06; //Positive Acknowledgement
const byte NAK = 'r'; //0x15; //Negative Acknowledgement
//Arrays
char ch_array[7], msg_header[3], msg_var[4];
//Array pointers
int i, m, n=0;
//Msg rx flag
boolean message_rx=false;
//Chip Setup
void setup(){
Serial.begin(9600);
while(!Serial);
}
void loop(){
while(Serial.available()){ //True when data in the serial buffer. Buffer is 64Bytes circular
if(Serial.read()==STX){ //STX indicates start of transmission
message_rx=true;
for(i=0; i<sizeof(ch_array); i++){
ch_array[i]=Serial.read(); //Read data from buffer into array until array size reached
delay(2);
if(ch_array[i]==EOT){ //If EOT found then stop reading data
Serial.write(ACK); //Transmit Acknowldegement
Serial.println(ch_array); //Retransmit recieved data
}
}
}
}
//Serial Message Decode
//Extract data in header
for(m=0; m<sizeof(msg_header); m++){
msg_header[m]=ch_array[m]; //Elements 0 to 2 hold command
delay(2);
}
//Extract data in variable
for(n=3; n<(2+sizeof(msg_var)); n++){
msg_var[n-3]=ch_array[n]; //Elements 3 to 6 hold variable data
delay(2);
}
//Serial messages for debugging
if(message_rx){
Serial.print("Header:");
Serial.println(msg_header);
delay(10);
Serial.print("Var:");
Serial.println(msg_var);
delay(10);
Serial.print("ch_array_size:");
Serial.println(sizeof(ch_array));
delay(10);
Serial.print("hdr_array_size:");
Serial.println(sizeof(msg_header));
delay(10);
Serial.print("var_array_size:");
Serial.println(sizeof(msg_var));
Serial.println();
}
message_rx=false; //Reset serial rx flag
delay(1000);
}
The output on the serial monitor when sent 'qMSG1234w' & 'qRSP4321w' is the following
I don't understand these lines.
Can you explain them please?
while(Serial.available()){ //True when data in the serial buffer. Buffer is 64Bytes circular
if(Serial.read()==STX){ //STX indicates start of transmission
message_rx=true;
for(i=0; i<sizeof(ch_array); i++){
ch_array[i]=Serial.read();
This looks to me like the usual problem of finding that there's one character to read, reading it, and then reading all of its mates, which haven't yet arrived.
I don't understand these lines.
Can you explain them please?
I plan to use STX and EOT as my message frame begin and end. 0x02 & 0x04 are not visible or riteable on the serial monitor so I have changed them to characters for ease of testing.
while(Serial.available()){ //True when data in the serial buffer. Buffer is 64Bytes circular
This looks to me like the usual problem of finding that there's one character to read, reading it, and then reading all of its mates, which haven't yet arrived.
I did try a small delay /10ms/ in each iteration of the for loop but it didnt help.
Perhaps I don't know exactly what you wish to do, but this is what I think it is:
char msg[15];
char ch_array[7], command[4], data[5];
//Chip Setup
void setup(){
Serial.begin(9600);
while(!Serial);
}
void loop(){
int len;
while(Serial.available()){ //True when data in the serial buffer. Buffer is 64Bytes circular
if(Serial.read()==STX){ //STX indicates start of transmission
len = Serial.readBytesUntil('w', msg, 15);
msg[len] = '\0';
strncpy(command, msg, 3); // This is the command
strncpy(data, &msg[3], 4); // This is the data
Serial.print("Command:");
Serial.println(command);
Serial.print("Data:");
Serial.println(data);
delay(10);
Serial.print("total message size:");
Serial.println(len);
delay(10);
Serial.print("command size:");
Serial.println(strlen(command));
delay(10);
Serial.print("data size:");
Serial.println(strlen(data));
Serial.println();
}
}
}
The way you are using the sizeof() operator, it will always return the number of bytes allocated to the data item in question. It has nothing to do with what's contained in it. Also, I would use different variable names to better reflect what the variable is actually doing in the code. the Serial method, readBytesUntil() is exactly what you want to do, as you are using 'w' as a sentinel in the code. Just make sure the arrays are big enough to hold whatever is coming in.
Below is some simple modified test code from another project that might do what you want to do. Having control of the data sending format makes things simpler. You can test by sending MSG1234, or RSP4321, from the serial monitor. any type of error checking will depend on the way the sent strings are formatted. Not sure of the value of a data start identifier.
//zoomkat 3-5-12 simple delimited ',' string
//from serial port input (via serial monitor)
//and print result out serial port
String readString, data;
int CD, CM, CT, CS, BR;
void setup() {
Serial.begin(9600);
Serial.println("serial delimit test 1.0"); // so I can keep track of what is loaded
}
void loop() {
//expect a string like CD01,CM01,CT01,CS03,BR255,
//expect a string like MSG1234, or RSP4321,
if (Serial.available()) {
char c = Serial.read(); //gets one byte from serial buffer
if (c == ',') {
Serial.println(readString); //prints string to serial port out
if(readString.indexOf("MSG") >=0) {
data=readString.substring(3);
Serial.print("MSG is: ");
Serial.println(data);
CD = data.toInt();
Serial.println(CD);
Serial.println();
}
if(readString.indexOf("RSP") >=0) {
readString=readString.substring(3);
Serial.print("RSP is: ");
Serial.println(readString);
CM = readString.toInt();
Serial.println(CM);
Serial.println();
}
/*if(readString.indexOf("CT") >=0) {
readString=readString.substring(2);
Serial.print("CT is: ");
Serial.println(readString);
CT = readString.toInt();
Serial.println(CT);
Serial.println();
}
if(readString.indexOf("CS") >=0) {
readString=readString.substring(2);
Serial.print("CS is: ");
Serial.println(readString);
CS = readString.toInt();
Serial.println(CS);
Serial.println();
}
if(readString.indexOf("BR") >=0) {
readString=readString.substring(2);
Serial.print("BR is: ");
Serial.println(readString);
BR = readString.toInt();
Serial.println(BR);
Serial.println();
} */
//do some stuff
readString=""; //clears variable for new input
data="";
}
else {
readString += c; //makes the string readString
}
}
}