以下问题:我目前正在为NUCLEO F207ZG编写一个小程序,该程序通过串行端口为其他服务提供接口。我程序的目标是使用?variable
之类的命令公开数据,并使用!variable <value>
设置值(例如?threshold
返回1400,而!threshold 1234
将阈值设置为1234)。另外,程序中的变量与EEPROM同步以保留数据。
在整个过程中,我得到了一个包含SerialCommands.h库的代码库。
主要问题是,如果设置后立即执行其他命令,则设置值会占用过多时间并破坏串行缓冲区(或类似的东西)。我用python(使用pyserial
)编写了一些单元测试,这些单元测试尽可能完美地执行 get 请求(例如?threshold
)。但是,如果我执行 set 命令(例如!threshold 1400
),则我需要等待至少四秒钟,然后再发出任何其他请求,否则串行接口/缓冲区似乎丢失了一些数据。如果我尝试在Arduino串行监视器上发出任何 set -> get 请求,也会发生同样的事情。这是一个简短的示例:
?threshold
=>返回'1400'!threshold 1234
?threshold
=>什么都没发生?threshold
=>什么都没发生?threshold
=>返回“无法识别的命令???threshold
”(有关此功能,请参见我的代码)编辑:重要的事情我忘了提。程序恢复后(在第5步之后),可以正确查询该值。
?threshold
=>返回'1234'我还有一个闪烁的状态LED(以500毫秒为步长),如果设置了某些内容,闪烁会明显停止约一秒钟。
这是我的代码库的(不起作用的)简化示例:
#include <SimpleTimer.h> // https://github.com/marcelloromani/Arduino-SimpleTimer
#include <SerialCommands.h> // https://github.com/ppedro74/Arduino-SerialCommands/
#include <EEPROM.h>
#include "EEPROMAnything.h"
char serial_command_buffer_[64];
SerialCommands serial_commands_(&Serial, serial_command_buffer_, sizeof(serial_command_buffer_), "\r\n", " ");
SimpleTimer timer;
int filter_threshold;
void cmd_unrecognized(SerialCommands* sender, const char* cmd) {
sender->GetSerial()->print("Unrecognized command [");
sender->GetSerial()->print(cmd);
sender->GetSerial()->println("]");
}
void set_arg(SerialCommands* sender, int& injectedVar) {
char* temp = sender->Next();
injectedVar = atoi(temp);
}
void set_arg(SerialCommands* sender, int& injectedVar, int address) {
set_arg(sender, injectedVar);
EEPROM_writeAnything(address, injectedVar);
}
void echo(SerialCommands* sender, int var) { sender->GetSerial()->println(var); }
void echo(SerialCommands* sender, String var) { sender->GetSerial()->println(var); }
void get_pressure_threshold(SerialCommands* sender) { echo(sender, filter_threshold); } //?threshold
void set_pressure_threshold(SerialCommands* sender) { set_arg(sender, filter_threshold, ADDR_THRESHOLD); } //!threshold <int>
void main_timer() {
mock_changes();
}
SerialCommand cmd_getpressthreshold("?threshold", get_pressure_threshold);
SerialCommand cmd_setpressurethreshold("!threshold", set_pressure_threshold);
void add_serial_commands() {
serial_commands_.SetDefaultHandler(cmd_unrecognized);
serial_commands_.AddCommand(&cmd_getpressthreshold);
serial_commands_.AddCommand(&cmd_setpressurethreshold);
}
void setup() {
pinMode(PB0, OUTPUT);
pinMode(PB7, OUTPUT);
pinMode(PB14, OUTPUT);
Serial.begin(9600);
timer.setInterval(500, main_timer);
add_serial_commands();
}
void loop() {
serial_commands_.ReadSerial();
timer.run();
}
由于我已经确认它不是缓慢/不可预测行为的根源,因此我基本上省略了覆盖EEPROM功能的代码。
所以主要的问题似乎与设置过程的时间有关,因为如果我做得足够慢,它就会起作用。我已经尝试对代码库的所有部分进行计时,但我无法解释设置任何内容时的延迟以及将来请求所需的延迟。设置EEPROM值最多需要75毫秒,ReadSerial()
是如此之快,以至于我几乎无法在10 ^ -3秒内对其进行测量。
在这一点上,我非常确定我在读取/写入串行缓冲区/接口时做错了什么。我尝试过在每次 set 调用后flush()
都执行此操作,但此操作无济于事。
我还认为也许我的PC串行接口(usb端口)以某种方式引起了此问题,因为这可以解释为什么代码库的任何部分都不会占用很多时间。但是,这与loop()
延迟并且LED停止闪烁这一事实并不合适。
对我来说,关于整个问题最奇怪的事情之一是,串行接口在对cmds进行几次垃圾邮件处理之后如何接收它们。 cmd_unrecognized(...)
函数不会收到?threshold?threshold?threshold
,而会收到???threshold
,这对我来说毫无意义。
我知道这篇文章已经很长了,但是我希望我对我的问题有一个比较清晰的了解,希望大家都知道如何解决这个耗时的问题。
EDIT2:在SerialCommands.h
调试模式下试玩之后,快速进入!pidp 10
然后进入?pidp
时,我得到以下输出:
Read: bufLen=63 bufPos=0 termPos=0 ch=[!]
Read: bufLen=63 bufPos=1 termPos=0 ch=[p]
Read: bufLen=63 bufPos=2 termPos=0 ch=[i]
Read: bufLen=63 bufPos=3 termPos=0 ch=[d]
Read: bufLen=63 bufPos=4 termPos=0 ch=[p]
Read: bufLen=63 bufPos=5 termPos=0 ch=[ ]
Read: bufLen=63 bufPos=6 termPos=0 ch=[1]
Read: bufLen=63 bufPos=7 termPos=0 ch=[0]
Read: bufLen=63 bufPos=8 termPos=0 ch=#13
Read: bufLen=63 bufPos=9 termPos=1 ch=#10
Received: [!pidp 10]
Matched #30
Read: bufLen=63 bufPos=0 termPos=0 ch=[?]
这似乎有点像完整的?pidp
不适合缓冲区,但是,有一条buffer full
消息却没有显示。
答案 0 :(得分:0)
听起来可能是您的Python程序引起的。您还记得在\0
整数后面添加一个空终止符(1234
)吗?串行命令通常需要字符串,该字符串必须以空终止符结尾。如果不是这样,您的Arduino可能会继续等待终止程序,并且仅在发生超时或看门狗导致复位(可能为4秒)时才停止。那可以解释这种坚持。
答案 1 :(得分:0)
最终,我还没有真正发现/理解串行缓冲区的问题,但是我设法实现了一个基本的解决方法。而不是总是写入EEPROM(因此最多需要75ms),我只将串行输入设置为各个变量(最多需要3ms)。为了保留更改,我添加了一个!commit
命令来保存所有值。进行此更改后,如果程序花费的时间太长,我就会集中与串行接口混淆的问题,因此,我将不得不在调用串行接口的实例中处理此问题。
据我所知总结问题:如果在将任何命令发送到串行接口时我的代码正在阻塞/正在工作,则串行缓冲区将以一种奇怪的,不可预测的方式填充(而不是按预期方式对缓冲区输入进行排队) )。最后,我只需要避免这种情况。这绝对不是完美的,但可以。感谢任何人的帮助。