0
votes

What I want is using visual studio to read and write to arduino UNO using a bluetooth device HC-05. In the previous step, I am able to communicate using visual studio c++ and Arduino directly through usb port. The code I am using is basically same as arduino and visual studio c++, 2 way serial communication. In arduino, I have command as:

void setup() {
    // put your setup code here, to run once:
    Serial.begin(9600);
    }


void loop() {
    // put your main code here, to run repeatedly:
    if (Serial.available() > 0) {
        char c = Serial.read();
        if (c == '1') 
          Serial.write("FORW");
        else if (c == '2') 
          Serial.write("LEFT");
        else if (c == '3') 
          Serial.write("RIGTH");
        else if (c == '4') 
          Serial.write("BACK");
        else if (c == '5') 
          Serial.write("STOP");
        else
        Serial.write("Invalid");
    }

and my/output is (using arduino usb directly):

Connection established!!!
Enter your command: 1
arduino: FORW
Enter your command: 2
arduino: LEFT
Enter your command: 3
arduino: RIGTH
Enter your command: 6
arduino: Invalid
Enter your command:

When I added a bluetooth Module HC-05 with it. Using serial monitor can get same output, but when I used visual studio, the first input never gives back a output, while for the following output, it always gives a previous output not a current one, as following:

Connection established!!!
Enter your command: 1
arduino:
Enter your command: 2
arduino: FORW
Enter your command: 1
arduino: LEFT
Enter your command: 4
arduino: FORW
Enter your command: 6
arduino: BACK
Enter your command: 2
arduino: Invalid
Enter your command:

I don't know if following steps may give error:

  1. bluetooth is supplied with 5v
  2. I cross connected bluetooth TX RX with Arduino Uno
  3. bluetooth HC-05 is in default mode, I didn't change anything about it.
  4. When bluetooth is connected with PC, it shows two ports: COM4 'DEV-B' & COM5,so I just changed the code in visual studio to make it connect to COM4.
  5. Bound rate is set to be 9600 on Arduino also indicated in visual studio.

So any idea why this would happen?

1

1 Answers

0
votes

Most probably the problem is that in 10ms the previous communication can't reach you.

Now, I don't have much experience in programming with plain C++ and visual studio (I usually use the managed C++ extensions and the event loop) but when I have to deal with serial ports I usually use either events or parallel threads.

When using events, I use the SerialPort class and its DataReceived event. Since you are using Visual C++ this is the method I suggest you to use. Just let VS create a base skeleton for you by creating a managed console application instead of an empty one and see how events work.

If you want to use multiple threads, just use one thread to check for the input and the other to check for the serial. I'm afraid I can't help you on how to start and handle the threads (you have to use some OS or library functions, maybe pthread's ones), but the two threads functions can be something like this:

void thread1()
{
    while (1)
    {
        std::cout << "Enter your command: ";
        std::cin.get(command, 2);     //input command 
        int msglen = strlen(command);
        if (port->WriteData(command, msglen));   //write to arduino
        printf("\n(writing success)\n");
    }
}

void thread2()
{
    while (1)
    {
        int n = port->ReadData(data, 4);
        if (n != -1){
            data[n] = 0;
            cout <<"arduino: " data << endl;
        }
        Sleep(10);
    }
}

The third solution is to check the input and the serial only when some data is there:

std::cout << "Enter your command: ";

while(1)
{
    if (_kbhit())
    {
        std::cin.get(command, 2);     //input command 
        int msglen = strlen(command);
        if (port->WriteData(command, msglen));   //write to arduino
        printf("\n(writing success)\n");
        std::cout << "Enter your command: ";
    }

    //read from arduino output
    n = port->ReadData(data, 4);
    if (n != -1)
    {
        data[n] = 0;
        cout <<"arduino: " data << endl;
    }
    Sleep(10);
}

These are the solutions if you want to send multiple commands (i.e. make the program wait for the input, send it and then wait for another input).

If you want to just use it for one command and then exit, just wait for some data:

std::cout << "Enter your command: ";
std::cin.get(command, 2);     //input command 
int msglen = strlen(command);
if (port->WriteData(command, msglen));   //write to arduino
printf("\n(writing success)\n");

while ((n = port->ReadData(data, 4)) <= 0)
    Sleep(10);

data[n] = 0;
cout <<"arduino: " data << endl;

The easiest but most unsuggested solution is to just increase the sleep period (e.g. to 50 ms) to allow the packets to be sent and received.

One more thing, since sooner or later you will face this problem. Usually with communication (be it serial, ethernet, ...) you don't have control on how often the driver tells you when it received the data. When you receive "FORW", you usually receive it as a block, but sometimes you receive a block with "FOR" and another with "W", or "FO" "RW", or "F" "ORW". Or you can receive two consecutive messages, for instance "FORWLEFT". Consequently you should either

  1. decide a "terminator" character, for instance #. The sending function sends FORW#, the receiving tests each received character until it finds the terminator and then processes all it received till that moment. For instance, it receives "FO". Append to the buffer (FO). No terminator, no processing. Then it receives "RW". Append to the buffer (FORW). No terminator, no processing. Then it receives "#LEFT#". Append to the buffer (FORW#LEFT#). The first terminator is at position 5, so analyze the first 5 bytes (FORW#) and remove them from the buffer (which now contains LEFT#). Still a terminator, analyze. If you don't like #, you can use a carriage return (\n), a space, a string terminator (\0); every character you are NOT using in the strings is fine.
  2. make each command exactly the same length (for instance 4 chars). Then read every byte until the buffer is longer or equal to 4 chars, and process the first n bytes.