Qt到Arduino串口通信和解析

时间:2018-03-28 12:08:26

标签: qt arduino

我正在尝试使用带有DMX Shield的Qt和Arduino创建一个软件照明桌。我已经能够在这两者之间建立通信,并且可以将命令发送到Arduino Mega(此时通信只进行一种方式)。我定期(每200毫秒)将11个推子的值作为字符串发送给Mega。

例如:A123 B234 C050 ... J222 M255

上面字符串中的值是基于滑块位置的变量,应该用于调整保存在Mega侧的每个推子上的光强度值。每个部分中的字母标识相应的推子。 A = fader1,B = fader2,......为了清楚起见:我可以以特定的强度调出一个光/秒 - >然后将这些强度分配给推子,当推子移动时,我希望调整这些值并将其发送到实际的灯/调光器。计算工作正常但我的Mega最终会变得没有反应。

我认为我的问题是解析传入的字符串。我试过strtok()方法和readStringUntil()无济于事。在串行监视器中监视传入的字符串也很困难,因为它用于与Qt进行通信。

很高兴能得到任何帮助。如果有任何不清楚的地方,请提问。

编辑:

这是我尝试解决方案之一

const char delim[2] = " ";
char *token;

if(Serial.available())
{
    //incomingMessage = Serial.readString();
    incomingMessage = Serial.readStringUntil("\n");     // read the whole string until newline
    //Serial.println(incomingMessage);
    const char* str = incomingMessage.c_str();          // convert it to a C String terminated by a null character "\0"
    //Serial.println(str);
    token = strtok(str, delim);                         // first part is a first section until delimiter occurs "-space- "

    //Serial.println(token);
    LX_Rated.commandLineResolve(token);                 // resolve it

    while( token != NULL ) {                            // continue splitting and resolving the incoming message until it reaches the end
      token = strtok(NULL, delim);
      LX_Rated.commandLineResolve(token);
    }


}

EDIT2:

我已经确认我收到了Qt发送的整个字符串。当我尝试使用strtok()函数对其进行标记并打印出第一个标记时,我返回整个字符串,其他标记为空。我的代码中没有看到任何错误。我甚至试图减慢从Qt到每5秒发送一个字符串的速度。有谁知道发生了什么事?我不明白为什么这个标准功能没有按预期工作。请参阅下面的修改代码。

if(Serial.available()) {
        incomingMessage = Serial.readStringUntil("\n");
        Serial.println("ok");
        Serial.flush();

        char* nullTerminatedIncomingMessage = incomingMessage.c_str();
        const char delimiter = " ";
        char* token;
        char* token1;
        char* token2;
        //char* secondToken;

        token = strtok(nullTerminatedIncomingMessage, delimiter);
        token1 = strtok(NULL, delimiter);
        token2 = strtok(NULL, delimiter);
        Serial.println(token);              // print the first section
        //Serial.println(incomingMessage);
        Serial.flush();
        Serial.println(token1);
        Serial.flush();
        Serial.println(token2);
        Serial.flush();
        //while(token != NULL)
        //    secondToken = strtok(NULL, delimiter);

        //Serial.println(secondToken);
        //Serial.flush();
        incomingMessage = "";

    }

2 个答案:

答案 0 :(得分:0)

至于监控通信的困难,您可以(在Qt中)将您读取的所有内容转储到控制台中,并对写入串口的所有内容执行相同的操作。它将显示在QtCreator的控制台选项卡中

#include <QDebug>
...
qDebug() << "whatever" << endl;

Aso用于解析您从串口读取的数据,看看这个,看看如何轻松split将滑块信息转换为单个字符串(QRegExpHow Can I Split a String According To Delimiters in Qt?

我不可能猜到为什么没有代码你的arduino会没有反应。

编辑: 当您在Qt中生成字符串时,是否可以通过 space 之外的其他内容分隔标记?也许tab(&#34; \ t&#34;)或其他什么? strtok在分隔符字符串中接受多个分隔符,可能需要尝试。 如果不是这种情况,则strtok(...)函数出现问题的可能性很小(顺便说一句,它修改了原始字符串,这本身就是一个问题)。此外,strtok可能会返回一个NULL指针,你似乎无法处理这种情况(一些错误的输入 - 打印一条消息)。您可以尝试将其作为普通strtok的替代方法:

/**
 * @brief custom strtok replacement with the same interface
 * It does not modify the original string
 * Token length is limited to 63 characters
 * @param ptr pointer to the string or NULL
 * @param delim delimiting character(only the first character will be used)
 */
const char * my_strtok(const char * ptr, const char * delim) {
    // Persistent variables, it will remember pointer to the processed string
    static const char * src;
    static char buffer[64]; // Token is limited to 63 characters

    if(ptr) { // Remember the pointer, if a new one was supplied
        src = ptr;
    }

    if(src == NULL || *src == '\0')// Invalid / empty string / no next token - return NULL
        return NULL;

    char i = 0;
    for(i = 0; i < 63 && *src != delim[0]; i++) {// Copy token until delimiter or end of buffer
        buffer[i] = *(src++);
    }

    if(*src == delim[0]) // Skip over the delimiter to the begining of the next token
        ++src;

    buffer[i] = '\0'; // Any returned string must be terminated
    return buffer;
}

#include <cstdlib>
#include <cstring>
#include <cassert>
void test() {
    const char * str1 = "123 456 asdf jkl;";
    assert(strcmp("123", my_strtok(str1, " ")) == 0);
    assert(strcmp("456", my_strtok(NULL, " ")) == 0);
    assert(strcmp("asdf", my_strtok(NULL, " ")) == 0);
    assert(strcmp("jkl;", my_strtok(NULL, " ")) == 0);
    assert(NULL == my_strtok(NULL, " "));
    assert(NULL == my_strtok(NULL, " "));
    assert(strcmp("123", my_strtok(str1, " ")) == 0);

}

答案 1 :(得分:0)

你的错误 - 至少 - 是假设所有输入在你预期时都可用。您需要推迟处理,直到整个生产线组装完毕。 Serial.readStringUntil阻止,直到整行可用,并且这不是您所期望的。您基本上需要将Serial.available()替换为Serial.lineAvailable(),但后者未实现。

This answer包含完整的问题解决方案 - 包括Qt和Arduino代码 - 以及Arudino仿真层。这可能是一个很好的起点,尤其是您可以在一个应用程序中轻松地共同调试Qt和Arduino项目并使用一个调试器!