0

So I'm using a Visual Studios Windows form to create a GUI in order to send data to an Arduino. I've been testing how to receive data on the Arduino side, and I can't seem to find an explanation on how the data is being sent. I've been using port.Write() to send the buffer.

port.Write Information from the Microsoft page

The Arduino Serial Monitor reads ASCII Characters but since I'm using the GUI to communicate to the Arduino I'm not exactly sure how the data is being transmitted. In the Arduino Serial Monitor, I enter the data and press enter. This means if I input all my data and press enter, it's reading all the data as 1 byte. By entering the the data individually followed by enter it's a byte being read and the terminated by a newline.

  1. How exactly is the data being transferred? From the MS page since it says that it "writes a specified number of bytes to the serial port using data from a buffer", I'm assuming it sends all the bytes at the same time and not individually.

    i.e If I send the data as port.Write(new byte[] { b0, b1, b2, b3, b4, b5, b6, b7}, 0, 8); is it basically sending all 8 bytes at once, or is it sending each element individually,if so what is the termination between bytes? I would assume it's the first since it asks for the number of bytes to write(count) so its sending 8 bytes from the array.

  2. What terminates between bytes during transmission? The comma separates the array data but in transmission, does it even send the commas to terminate or is it just a stream of data?

    ie. In my Serial Monitor with the code runs, I enter each byte individually, followed by the newline character. The Arduino then reads the byte until it encounters the newline character

  3. On the Arduino in C++ you can use Serial.print or Serial.println to have it automatically apply a new line. On the MS page, WriteLine method only writes a string and doesn't have any overloads, so I assume that means there's no way to use byte with this command?

  4. If I try to use a for loop to print an individual array, it says cannot convert from byte to char[]. Why is it saying it's a char array when I defined it as a byte array? I was previously using the //port.Write(sendbyte, 0, 8); to send the whole array and was getting some of the data.

Code to send from Windows Form GUI:

//bytes declared and data stored earlier
byte[] sendbyte = new byte[] { b1, b2, b3, b4, b5, b6, b7, b8};
            
port = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
port.Open();
//port.Write(sendbyte, 0, 8);

port.Write(new byte[] { b1, b2, b3, b4, b5, b6, b7, b8}, 0, 8);
/*for( int x = 0; x <=7; x ++)
{
    port.Write( sendbyte[x], 0, 1);
} 
*/
port.Close();

Code to read the incoming bytes

void recvBytesWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    byte startMarker = 42;
    byte endMarker = 24;
    byte rb;
    byte comp;

    while (Serial.available() > 0 && newData == false) 
    {
        rb = Serial.read();
        if (recvInProgress == true) 
        {
            if (rb != endMarker)
            {
                receivedBytes[ndx] = rb;
                ndx++;
                if (ndx >= numBytes) 
                {
                    ndx = numBytes - 1;
                }
            }
            else 
            {
                receivedBytes[ndx] = ','; // terminate the string
                recvInProgress = false;
                numReceived = ndx;  // save the number for use when printing
                ndx = 0;
                newData = true;
            }
        }
        else if (rb == startMarker) 
        {
            recvInProgress = true;
        }
    }
}
Community
  • 1
  • 1
j.yang29
  • 65
  • 9
  • 1
    A _serial_ port writes one byte at a time. – 001 Sep 19 '18 at 21:31
  • *I'm assuming it sends all the bytes at the same time and not individually* The write goes into a buffer somewhere and from that buffer into the hardware maybe in a small block or maybe byte by byte depending on the hardware. The hardware then writes the data to the wire one byte at a time along with some extra control bits. – user4581301 Sep 19 '18 at 21:35
  • At the bottom of the MS page it says "By default, SerialPort uses ASCIIEncoding to encode the characters. ASCIIEncoding encodes all characters greater than 127 as (char)63 or '?'. To support additional characters in that range, set Encoding to UTF8Encoding, UTF32Encoding, or UnicodeEncoding." So I'm assuming that's why it's char. going to look at the other support information – j.yang29 Sep 19 '18 at 21:37
  • @user4581301 when you say "the write goes into a buffer somewhere" I'm assuming you do mean that the write function doesn't necessarily always start at the beginning of the buffer? Do you happen to know where I could read more about the control bits? I'm assuming that's what I'm after. What do you mean by hardware? Isn't the write technically in the buffer in the software so it could be written to the hardware? – j.yang29 Sep 19 '18 at 21:44
  • When I use the default Serial Monitor, I enter the data followed by new line, so I'm assuming the new line is the control bit? How exactly are each bytes separated when being written? – j.yang29 Sep 19 '18 at 21:46
  • I was trying to say that somewhere in memory there is likely a buffer containing all of the data the program wrote but has not yet been sent by the serial hardware. Say you have two large writes in close proximity in the code. You write in a block of data and only part of it can be sent by the time the second write hits. The new data will be added to the end of the buffer or placed in another buffer that is chained to the first. There are many strategies to handle the fact that the computer can queue up data possibly millions of times faster than the serial hardware can send the data. – user4581301 Sep 19 '18 at 21:54
  • The control bits... When you set up the port you may have had to set stop bits and parity bits parameters. this is what I mean by control bits. You send a 7-bit ASCII character and you will actually send those 7 bits, one or more stop bits and a possibly a parity bit. – user4581301 Sep 19 '18 at 21:56
  • If you send a wide character, that wide character is going to hacked up into bytes and sent byte by byte, however big a byte is to your comm hardware. – user4581301 Sep 19 '18 at 21:58
  • @user4581301 I see. That's an issue I had earlier, Since I was sending the whole array at once, there was too much data in the buffer and the code wasn't executing properly. When I send the data element by element with a newline in-between, the code ran smoothly. Correct, I set start and end marker. I didn't set up a parity bit though (Parity.None) I don't think I need one since for my application. With the stop bit VS says Serialport doesn't support no stop bits so I said 1 because I had to. With the wide char I assume you mean if i send a char outside 0-127? – j.yang29 Sep 20 '18 at 00:32
  • You should probably find some good articles. You won't get an in-depth explanation here - that's not how SO works. Maybe this: [Serial Communication](https://learn.sparkfun.com/tutorials/serial-communication). Or [Universal asynchronous receiver-transmitter](https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter) – 001 Sep 20 '18 at 13:10
  • @JohnnyMopp Thanks for the first article. I know that but I was looking for clarification. I am really interested in understanding how the data is being transmitted. The article helped with understanding how the frame was constructed. I was really just confused on the wide character. My goal is to not be sending ASCII characters but to send numeric values. the issue is that I might need to use int16 which needs 2 bytes which would then affect my array I think? If I have 8 int16 elements in my array, my array is should now be 16 bytes. My worry is that the stream is too large like a wide char – j.yang29 Sep 20 '18 at 17:17
  • If you want to send 16-bit values, you need to split into 2 8-bit values, send those, then reassemble as 16-bit on the receiving side....Or convert to string, send the string, and convert back to int on rcv side. The benefit of the 2nd way is you don't need to worry about endianess. – 001 Sep 20 '18 at 18:01
  • I think I might be in a catch 22 with what I'm trying to do. Since all I wanted to do was to see information from the Serial so that I was sure the data is being sent correctly. I chose to try and display the byte so I can see what's I'm receiving. Since my data is being stored in as a byte, 'Serial.print()' is defined to print bytes as a single character. So my data being sent over the Serial could be correct, but it would be impossible to display it since 'print()' prints bytes as characters and not as the numeric value? – j.yang29 Sep 20 '18 at 18:06
  • Since I can type store {1,1,1,1,1,1,1,1} into the array so the elements in the array are {1,1,1,1,1,1,1,1}, so when I use the 'print' function it displays (49,49,49,49,49,49,49,49) which means it's displaying the char for the associated byte. The only thing that doesnt make sense is about this theory is, if the array is of byte 1, isn't the value techinally (LSB)10000000 and therefore it should be displaying null? I do remember reading somewhere the Serial Monitor is defaulted to read ASCII so When I use the serial monitor, I'm really sending in the char 1 and it's displaying the ASCII# – j.yang29 Sep 20 '18 at 18:08
  • I definitely think that storing it as a string would be much simpler. Because I originally planned to use a byte for each number, I would be able to do what your first article mentioned, include a start, the data, and end bit, to create a 10 bit block to send. This seemed like the easiest way to do it. This way I could just use my array prototype (marker, data, marker). Since I do need numeric values from 1-1000 the byte method won't work since it'll be >255. So using strings may be the way I have to do it? The only thing about this is I need to understand if I need encoding. – j.yang29 Sep 20 '18 at 18:25

1 Answers1

2
  1. Serial ports are usually buffered, but the Microsoft documentation leads me to believe it writes the entire buffer all at once to the wire, as it can throw a timeout exception. However, if you write 1000 bytes from the windows at a time, you are not guaranteed to read the same number of bytes in each loop on the arduino.

  2. No delimiter between individual bytes. The comma that separates array bytes is really only the syntax of your programming language, ie. it only exists in your code file. Bytes are always laid out sequentially in memory.

  3. Not unless you cast a byte array to a string value. How convert byte array to string

  4. try port.Write( &sendByte[x], 0, 1 );

Kaelan Mikowicz
  • 345
  • 2
  • 12
  • 1. I know the Serial communication between The Arduino and GUI is much slower than the computing speed. So the write command will send data, and the processor is running the data much faster than it is receiving it. How come I wouldn't be guaranteed to read the same number of bytes in each loop? Is it due to the timeout? i.e GUI will send the bytes over, and the Arduino will process the data quicker than the data is incoming. but since I have both start and end markers, Isn't it guaranteed to read all the data? It'll keep reading data until both markers are received. – j.yang29 Sep 20 '18 at 00:07
  • 2. So If I sent {1,1,1} the data being sent is still 000000010000000100000001 but the program is still only reading 8 bits at a time? 3. Yeah, I was thinking I would like to not cast it into a string and then recast back to the numeric value since I'm actually interested in the numeric value. I.e bit 1 could represent number of times a loop is run. Converting it to "1" and then having the Arduino cast it back into a byte/int seems like it makes it more difficult. – j.yang29 Sep 20 '18 at 00:14
  • 4. It gives me error CS0212 [link](https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0212) I enabled allow unsafe code. I never used a fixed statement, other than declaring the array to be a fixed number of elements. The byte array is not fixed (since there is no size in the []) and since the sendbye[x] is not fixed, aren't i trying to take the address of an unfixed expression inside of a fixed statement? – j.yang29 Sep 20 '18 at 00:20
  • 1. I meant that as a general rule. But you solved this problem using delimiters. 2. Yes because you call Serial.read() to read one at a time. 3. That's normal 4. Sorry can't help you with this one. – Kaelan Mikowicz Sep 20 '18 at 15:41
  • 1
    I'm a little confused about the delimiter. This is my understanding When I run the Serial Monitor and input data,The Serial Monitor is designed to interpret ASCII Char so I enter a char and press send/enter. It is writes what I typed to the Arduino. The read function then reads the 8bit ASCII I sent, and writes it into the array and then runs the rest of the code. and then prints the DEC of the char 1. Pressing the send/enter does nothing to add to the array? My input is the 8 bit char that is sent, and it doesn't read the next byte until I enter something else and send it via the Serial? – j.yang29 Sep 20 '18 at 21:24
  • 1
    So If I enter A [SEND] A [SEND] It's really only reading 'A' 'A' and not 'A' '/0' 'A' '/0'? – j.yang29 Sep 20 '18 at 21:26