Arduino“SerialEvent”示例代码无法在我的 Arduino Nano 上运行。我无法接收串行数据。为什么?

2024-01-22

我正在按照教程进行操作串行事件 https://www.arduino.cc/en/Tutorial/BuiltInExamples/SerialEvent我正在尝试这段代码:

然而,当我发送我的Arduino 纳米 https://en.wikipedia.org/wiki/List_of_Arduino_boards_and_compatible_systems#Official串口数据,好像没有收到。当我通过串行向它发送消息时,它应该将其打印回 Arduino 串行监视器(串行控制台),但事实并非如此。为什么?我究竟做错了什么?

更多细节:

我需要从我的 PC 到 Arduino 进行实时通信。因此,我不能使用delay()在我的 Arduino 循环中。该项目包括从计算机发送消息toArduino并在Arduino中接收和解析它。这个示例代码看起来很完美,因为它没有使用delay()功能。不幸的是,它不起作用。我通过串口将文本字符串从计算机发送到 Arduino,但 Arduino 不会在串口监视器上打印任何内容。我的 Arduino 是 Nano ATmega328。

另外,我没有看到这个示例代码调用serialEvent()随时随地发挥作用。我该打电话到哪里serialEvent()?或者,它如何运行并被调用?

这是从上面的示例复制粘贴的代码:

String inputString = "";         // A string to hold incoming data
boolean stringComplete = false;  // Whether the string is complete

void setup() {
  // Initialize serial:
  Serial.begin(9600);

  // Reserve 200 bytes for the inputString:
  inputString.reserve(200);
}

void loop() {
  // Print the string when a newline arrives:
  if (stringComplete) {
    Serial.println(inputString);

    // Clear the string:
    inputString = "";
    stringComplete = false;
  }
}

/*
  SerialEvent occurs whenever a new data comes in the
  hardware serial RX.  This routine is run between each
  time loop() runs, so using delay inside loop can delay
  response.  Multiple bytes of data may be available.
 */
void serialEvent() {
  while (Serial.available()) {

    // Get the new byte:
    char inChar = (char)Serial.read();

    // Add it to the inputString:
    inputString += inChar;

    // If the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

你需要一个\n在通过串口发送到 Arduino 的任何字符串的末尾:

注意这部分serialEvent()功能:

// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
} 

正如你所看到的,它正在寻找\n(换行)字符表示已收到完整字符串。那么你must包括换行符 (\n) 在您发送到 Arduino 的字符串末尾。

教程(https://www.arduino.cc/en/Tutorial/BuiltInExamples/SerialEvent https://www.arduino.cc/en/Tutorial/BuiltInExamples/SerialEvent)还指出(强调):

这个例子演示了使用serialEvent()功能。该函数在结束时自动调用loop()当缓冲区中有可用串行数据时。在这种情况下,找到的每个字符都会添加到字符串中直到找到换行符。然后打印该字符串并将其设置回 null。

If using the Arduino Serial Monitor, be sure to choose the "Newline" option from the dropdown at the bottom. Then, whenever you type something in the bar at the top and press Enter, it will automatically append a \n to the end of your string to the Arduino when you send it. enter image description here

如果通过串口将数据从 C、C++、Python、Java 或其他程序发送到 Arduino,请再次确保包含\n在你的字符串末尾到Arduino。

如何serialEvent()无论如何都会被打电话吗?

回答这个问题:

另外,我没有看到这个示例代码调用serialEvent()随时随地发挥作用。我该打电话到哪里serialEvent()?或者,它如何运行并被调用?

简而言之,您定义的事实serialEvent()功能at all使其被 Arduino 核心代码自动调用。如果你不定义它,它不会被调用。如果你定义它,它就会。这是因为你的定义serialEvent()是强大的并且超越weak one 在 HardwareSerial.cpp 中声明 https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/HardwareSerial.cpp#L45:

// SerialEvent functions are weak, so when the user doesn't define them,
// the linker just sets their address to 0 (which is checked below).
// The Serialx_available is just a wrapper around Serialx.available(),
// but we can refer to it weakly so we don't pull in the entire
// HardwareSerial instance if the user doesn't also refer to it.
#if defined(HAVE_HWSERIAL0)
  void serialEvent() __attribute__((weak)); // <======
  bool Serial0_available() __attribute__((weak));
#endif

所以,如果你定义一个serialEvent()函数,这使得该函数的地址非零(而如果它只是 gccweak声明,它将保持为零),使得这个if陈述正确,所以serialEvent()被叫到在 - 的里面serialEventRun()功能: https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/HardwareSerial.cpp#L67

void serialEventRun(void)
{
#if defined(HAVE_HWSERIAL0)
  if (Serial0_available && serialEvent && Serial0_available()) serialEvent();
  // ...
#endif
}

并且,这又被称为在Arduino中main()在这里发挥作用 https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/main.cpp#L47:

for (;;) {
    loop();
    if (serialEventRun) serialEventRun();
}

那么,让我们再回顾一下这个问题。如果你不定义serialEvent(),那么它唯一的声明是这样的:

void serialEvent() __attribute__((weak));

这是一个弱声明,因此它只会为函数提供一个程序空间内存地址0(零)如果它从未被定义。这意味着这if陈述是错误的,所以serialEvent()内部从未被调用过serialEventRun():

if (Serial0_available && serialEvent && Serial0_available()) serialEvent();

如果是这样的话,那么serialEventRun()不包含任何内容,并且显然还给出了程序空间地址0(零)因为它无关。这使得这个if中的声明main()函数为假,并且serialEventRun()也永远不会被调用:

for (;;) {
    loop();
    if (serialEventRun) serialEventRun();
}

不要使用serialEvent() at all

就我个人而言,我认为你不应该使用serialEvent根本不。只需将逻辑添加到loop()直接运行,就像这样。您可以获得完全相同的效果,并且可以自己手动控制。请注意,only我所做的改变是:

  1. 我重命名了serialEvent()功能为readSerial().
  2. 我添加了readSerial()呼叫您的顶部loop()功能。

就是这样!这是包含这些更改的代码。我刚刚在基于 ATmega328 的 Pro Mini 上进行了测试,它工作正常,可以正确打印出任何换行符(\n我发送给它的以 ) 结尾的字符串,也与此示例中未修改的代码相同。

String inputString = "";         // a String to hold incoming data
bool stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inputString.reserve(200);
}

void loop() {
  readSerial();
  // print the string when a newline arrives:
  if (stringComplete) {
    Serial.println(inputString);
    // clear the string:
    inputString = "";
    stringComplete = false;
  }
}

void readSerial() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag so the main loop can
    // do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

为什么他们让弱者serialEvent()当您只需要手动控制它时,它还能发挥作用吗?我不知道。这可能是一件方便的事情:如果你这样做的话,它可以节省你几行代码(覆盖weak函数调用)用于多个串行事件调用,例如serialEvent(), serialEvent1(), serialEvent2(), and serialEvent3()。然而,为了更明显的控制,我只需手动创建自己的函数并在loop()相反,就像我上面所做的那样。

其他参考资料:

  1. gcc weak功能属性:https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Function-Attributes.html https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Function-Attributes.html(关于此的最新 gcc 文档现在在这里:https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-weak-function-attribute https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-weak-function-attribute):

    weak

    The weak属性导致声明作为弱符号而不是全局符号发出。这主要用于定义可以在用户代码中覆盖的库函数,尽管它也可以与非函数声明一起使用。 ELF 目标支持弱符号,使用 GNU 汇编器和链接器时 a.out 目标也支持弱符号。

  2. From my eRCAGuy_hello_world https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world回购协议,这是我的check_addr_of_weak_undefined_funcs.cpp https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/cpp/check_addr_of_weak_undefined_funcs.cpp我向自己证明的文件weak已声明但未定义的函数确实具有等于 nil 的地址(即:零,或0).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Arduino“SerialEvent”示例代码无法在我的 Arduino Nano 上运行。我无法接收串行数据。为什么? 的相关文章

随机推荐