serial.write is not writing

I’m having problem with serial.write. It doesn’t always send (write to the serial port). Here’s my code:

// Serial Data from host is stored in these variables for processing
char  SerialIn[5];    //SerialReadbytes function expects char data type.  An array of 5 bytes are reserved for receiving commands from the host PC.
byte SerialOut[5];    //SerialWrite expects byte data type.  An array of 5 bytes are reserved for sending data to host PC.
byte  command = 0;   //command byte 
byte  parameter1 = 0;  //parameters
byte  parameter2 = 0;  //
byte  parameter3 = 0;  //    
byte  parameter4 = 0;  //

// Output pins
const int Output1 = 4;
const int Output2 = 5;
const int Output3 = 6;
const int Output4 = 7;

// Actuator pins
const int Actuator1 = 8;
const int Actuator2 = 9;
const int Actuator3 = 10;
const int Actuator4 = 11;

// Read Voltage pins
const int Voltage1 = A0;
const int Voltage2 = A1;

// Input pins
const int Input1 = A2;
const int Input2 = A3;
const int Input3 = A4;
const int Input4 = A5;

// Variables
word V1_Value = 0;    //use for storing voltage value of channel 1
word V2_Value = 0;    //use for storing voltage value of channel 2
word Duration = 0;    //use for storing the duration on the actuators
int bytesent = 0;    //returns the number of bytes written in the serial port

void setup() {
  // initialize serial communication at 115200 bits per second:
  Serial.begin(9600);    //9600 bps on serial communication
  pinMode(Output1, OUTPUT);
  pinMode(Output2, OUTPUT);
  pinMode(Output3, OUTPUT);
  pinMode(Output4, OUTPUT);
  pinMode(Actuator1, OUTPUT);
  pinMode(Actuator2, OUTPUT);
  pinMode(Actuator3, OUTPUT);
  pinMode(Actuator4, OUTPUT);
  pinMode(Input1, INPUT);
  pinMode(Input2, INPUT);
  pinMode(Input3, INPUT);
  pinMode(Input4, INPUT);
  pinMode(Voltage1, INPUT);
  pinMode(Voltage2, INPUT);
}  //setup

void loop(){
      //Wait for host PC to send data to board
      while (Serial.available() < 1) {
        delay(10);
      }  //while loop
      
      // Get 5 bytes of data from Host  
      Serial.readBytes(SerialIn, 5);    // read 5 bytes into SerialIn buffer
      command = byte(SerialIn[0]);     //cast char to byte data type  
      parameter1 = byte(SerialIn[1]);  //    ""
      parameter2 = byte(SerialIn[2]);  //    ""
      parameter3 = byte(SerialIn[3]);  //    ""  
      parameter4 = byte(SerialIn[4]);  //    ""
    
    // Check what command was received
    switch (command) {
      case 0x10:
        //Set Actuator, PortB.0 = Actuator1, PortB.1 = Actuator2, PortB.2 = Actuator3, PortB.3 = Actuator4
        PORTB = parameter1;    //parameter1 contains the Actuator bit mapping information, see Typing Machine doc.   
        break;
      case 0x11:
        //See Typing Machine document for explanations of the parameters
        Duration = word(parameter2, parameter3);    //parameter2 = highbyte, parameter3 = lowbyte
        //Set Actuator, PortB.0 = Actuator1, PortB.1 = Actuator2, PortB.2 = Actuator3, PortB.3 = Actuator4
        PORTB = parameter1;
        // Delay in mS
        delay(Duration);
        // Actuators Off
        PORTB = B00000000;
        break;
      case 0x12:
        //Read channel 1 voltage
        V1_Value = analogRead(Voltage1);
        //Pack the data into parameter1 & parameter2 for sending it to the host PC
        parameter1 = highByte(V1_Value);  //parameter1 contains the voltage highbyte value
        parameter2 = lowByte(V1_Value);   //parameter2 contains the voltage lowbyte value
        break;
      case 0x13:
        //Read channel 2 voltage
        V2_Value = analogRead(Voltage2);
        //Pack the data into parameter1 & parameter2 for sending it to the host PC
        parameter1 = highByte(V2_Value);
        parameter2 = lowByte(V2_Value);
        break;
      case 0x14:
        //Write Digital Outputs
        parameter1 = parameter1 << 4;  //shift left 4 times to put the bits in the upper nibble
        PORTD = parameter1;    // the outputs are in the upper 4 bits of port D
        parameter1 = parameter1 >> 4;  //shift it back the other direction to display to host
        break;
      case 0x15:
        //Read Digital Inputs
        parameter1 = PINC;  //Read the inputs
        parameter1 = parameter1 >> 2;  //shift right twice so the lower 4 nibbles contains the pin status
        break;                        
      default: 
        // Send FF to indicated unknow commands
        command = 'f';
        parameter1 = 'f';
        parameter2 = 'f';
        parameter3 = 'f';
        parameter4 = 'f';
    } // switch 
    // Send data to host PC
    SerialOut[0] = command;
    SerialOut[1] = parameter1;
    SerialOut[2] = parameter2;
    SerialOut[3] = parameter3;
    SerialOut[4] = parameter4;
    Serial.write(SerialOut, 5); 
       
} //loop

Every command I send to the Arduino Uno Board, I expect the board send 5 bytes of data back. I receive and process the command properly from the PC, but the Serial.write does not always write back. I have a USB traffic sniffer, I see the USB OUT, but no USB IN. Am I using Serial.write correctly?

Serial.write is not your problem. You check for Serial.available being less than 1, delay 10 ms and check again.

Suppose you receive the first of the five bytes immediately after the check. At that point, you are still in the delay(10), in fact, you may have just begun the delay. Over the next 10 ms, the rest of the bytes arrive (probably in about 5 ms). So far, so good. You check again, and go to read 5 bytes. Still just fine. Serial.write reports back a successful packet.

But what happens if, during the delay, the first byte comes in when there is only 1 ms left in the delay? Well, you check again, find that at least 1 byte has arrived, and, ignoring the fact that it might ONLY be 1, or 2, or 3, or 4 byte,s you proceed to read 5 bytes. Ooops!

Using a delay to manage serial input is almost never the right answer.

If you need to wait until there are five bytes available, wait until there are five bytes available.

Given that serial communications are imperfect and may occasionally lose a byte, you need to have some scheme to get the sender and receiver back in sync. How to do this would depend on how your incoming messages are encoded, but the encoding ought to support some scheme for the receiver to know when each messages starts and ends.

Thanks for helping me out. Serial read is not my problem, but I take your guys suggestion. I have changed the code for waiting for 5 bytes to:
//Wait for host PC to send data to board
while (Serial.available() < 5) {
}

The problem I have is if I send different commands, the second command’s response, serial write, will not write. I don’t see any USB traffic of the Uno board sending data to the PC.
For exmaple:
I send 0x14 as the command byte with some parameters. Uno board got the message and turn on LED’s. Uno board response to the 0x14 command and send 5 bytes back to the PC - So far so good.

I then send 0x15 as the next command byte. Uno board got the message but do not send back 5 bytes as acknowledge (no USB Traffic that I can see with the USB sniffer).
I then send 0x15 again. This time, the Uno board got the message and do respond with 5 bytes as acknowledge.
If I send another 0x15 again, the Uno board with respond back to the PC with 5 bytes - good.
If I change the command to 0x14, I can see the LED got change properly, but there’s no 5 bytes send back to PC as acknowledge. I do not understand why everytime I change to a different command, It does not do serial write.

case 0x14:
//Write Digital Outputs
parameter1 = parameter1 << 4; //shift left 4 times to put the bits in the upper nibble
PORTD = parameter1; // the outputs are in the upper 4 bits of port D
parameter1 = parameter1 >> 4; //shift it back the other direction to display to host
break;
case 0x15:
//Read Digital Inputs
parameter1 = PINC; //Read the inputs
parameter1 = parameter1 >> 2; //shift right twice so the lower 4 nibbles contains the pin status
break;

How are you sending the serial data to the Arduino?

I use LabView Visa app that I create for communication. I use BusHound for USB traffic monitoring. Also, the serial monitor from the Arduino IDE also don't show any data received. I'm scratching me head on this one.

I have used LabView with FTDI chips for many projects and do not have any problems. I'm a PIC Micro guy just starting to use Arduino, so I don't fully understand Arduino yet and need some guidance. Thanks in advance for all who are trying to help me.

I loaded your code into my Uno, changed the commands from 0x10-0x15, to 0x31-0x35. It ran just fine. I did notice one anomaly. if I sent a command of '4' (0x34), followed by 1234, I got back "4 1234" (missing parameter1), but I did see that you change parameter1, probably to a non-printable character.

Anyway, if I then send a '5' (0x35), it works fine as well. I can switch back and forth between those commands at will, and it works well.

Does the LabView send anything other than the 5 bytes? CR? LF?

I'm now curious, so I think I'll write a little VB.net program to send the same data you're sending. It might help if you could supply me with a sample of command 0x14 and 0x15, along with tha parameters, to see if I can duplicate the failure.

LabView can send CR or LF if you want. In my case, I disabled it. USB traffic also indicate only 5 bytes are being sent, so no CR or LF. Here are the meanings for command 0x14 and 0x15

Command - Byte0 = 0x14 -> Set ouptus ON/OFF
Parameter1 - Byte1 = See Bit Mapping below
Outputs Bit Mapping: x = don't cares
Bit 7 = x
Bit 6 = x
Bit 5 = x
Bit 4 = x
Bit 3 = Out4
Bit 2 = Out3
Bit 1 = Out2
Bit 0 = Out1
Parameter2, 3, 4 - Not used, set to 0.

Example of 0x14 usage:
There are 4 output bits that can be turn ON or turn OFF. Set Outputs: 0 = OFF, 1 = ON.
Example: to set Output 1 ON, you send:
Send -> 0x14, B00000001, 0x00, 0x00
Receive -> 0x14, B00000001, 0x00, 0x00 as acknowledgement.

Set all Outputs ON, you send:
Send -> 0x14, B00001111, 0x00, 0x00
Receive -> 0x14, B00001111, 0x00, 0x00 as acknowledgement.

Set all Outputs OFF, you send:
Send -> 0x14, B00000000, 0x00, 0x00
Receive -> 0x14, B00000000, 0x00, 0x00 as acknowledgement.

Command - Byte0 = 0x15 -> Read digital inputs
Parameter1, 2, 3, 4 - Not used, set to 0.

Example:
Send -> 0x15, 0x00, 0x00, 0x00, 0x00
Receive -> 0x15, Digital Input State, 0x00, 0x00

What I did to test 0x14 and 0x15 is that I hook up the inputs to the outputs. So the bit I set in 0x14 will get read back with 0x15.

Thanks again for looking into this.

If you want to know whether the Arduino is processing the message correctly, get it to turn some leds on and off. That should help you to determine whether the problem is with the incoming message or the outgoing message.

michinyon:
If you want to know whether the Arduino is processing the message correctly, get it to turn some leds on and off. That should help you to determine whether the problem is with the incoming message or the outgoing message.

Incoming is OK, outgoing is the problem. Sometimes it goes, and sometimes not. I did hooked up LEDs as indicators. It is processing incoming data fine. Thank you for your suggestion though.