你需要一个\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.
如果通过串口将数据从 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我所做的改变是:
- 我重命名了
serialEvent()
功能为readSerial()
.
- 我添加了
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()
相反,就像我上面所做的那样。
其他参考资料:
-
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 目标也支持弱符号。
-
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
).