Arduino视觉工作室和蓝牙HC-05

时间:2017-01-04 05:49:51

标签: c++ visual-studio bluetooth arduino serial-port

我想要的是使用visual studio使用蓝牙设备HC-05读取和写入arduino UNO。在上一步中,我可以通过usb端口直接使用visual studio c ++和Arduino进行通信。我使用的代码与arduino and visual studio c++, 2 way serial communication基本相同。在arduino中,我有命令:

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");
    }

和my / output是(直接使用arduino usb):

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:

当我添加蓝牙模块HC-05时。使用串行监视器可以获得相同的输出,但是当我使用visual studio时,第一个输入永远不会返回输出,而对于后面的输出,它总是给出先前的输出而不是当前的输出,如下所示:

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:

我不知道以下步骤是否会出错:

  1. bluetooth提供5v
  2. 我用Arduino Uno交叉连接蓝牙TX RX
  3. 蓝牙HC-05处于默认模式,我没有改变它。
  4. 当蓝牙与PC连接时,它显示两个端口:COM4'DEV-B'& COM5,所以我刚刚更改了visual studio中的代码,使其连接到COM4。
  5. Arduino的绑定率设置为9600,也在visual studio中显示。
  6. 所以知道为什么会这样?

1 个答案:

答案 0 :(得分:0)

最有可能的问题是,在10毫秒内,之前的通信无法联系到您。

现在,我在使用普通C ++和visual studio编程方面没有太多经验(我通常使用托管C ++扩展和事件循环)但是当我必须处理串行端口时,我通常使用事件或并行线程。

使用事件时,我使用SerialPort类及其DataReceived事件。由于您使用的是Visual C ++,因此我建议您使用此方法。让VS通过创建托管控制台应用程序而不是空的应用程序为您创建基础框架,并查看事件的工作方式。

如果要使用多个线程,只需使用一个线程检查输入,另一个线程检查串口。我担心我无法帮助你如何启动和处理线程(你必须使用一些操作系统或库函数,也许是pthread的),但是两个线程函数可以是某种东西像这样:

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);
    }
}

第三种解决方案是仅在存在某些数据时检查输入和串行:

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);
}

如果您想发送多个命令(即让程序等待输入,发送它然后等待另一个输入),这些是解决方案。

如果您只想将它​​用于一个命令然后退出,只需等待一些数据:

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;

最简单但最未提及的解决方案是仅增加睡眠时间(例如,增加到50毫秒)以允许发送和接收数据包。

还有一件事,因为你迟早会遇到这个问题。通常通过通信(无论是串行,以太网......),您无法控制驱动程序在收到数据时告诉您的频率。当您收到&#34; FORW&#34;时,您通常会将其作为一个块接收,但有时您会收到一个带有&#34; FOR&#34;另一个与&#34; W&#34;或&#34; FO&#34; &#34; RW&#34;,或&#34; F&#34; &#34; ORW&#34 ;.或者你可以收到两个连续的消息,例如&#34; FORWLEFT&#34;。因此你应该

  1. 决定&#34;终结者&#34;字符,例如#。发送功能发送FORW#,接收测试每个接收到的字符,直到找到终结符,然后处理收到的所有字符,直到那一刻。例如,它收到&#34; FO&#34;。附加到缓冲区(FO)。没有终结者,没有处理。然后它接收&#34; RW&#34;。附加到缓冲区(FORW)。没有终结者,没有处理。然后它收到&#34; #LEFT#&#34;。附加到缓冲区(FORW#LEFT#)。第一个终结符位于第5位,因此分析前5个字节(FORW#)并将它们从缓冲区中删除(现在包含LEFT#)。仍然是终结者,分析。如果你不喜欢#,你可以使用回车符(\ n),空格,字符串终结符(\ 0);你没有在字符串中使用的每个字符都可以。
  2. 使每个命令的长度完全相同(例如4个字符)。然后读取每个字节,直到缓冲区长于或等于4个字符,并处理前n个字节。