我使用Arduino Uno rev2设备作为永久连接的设备,有时会向PC发送信号(Windows 7 x64)。使用arduino.cc的Arduino 1.0软件编译的代码
arduino.cc主题, Arduino stops sending data to Serial after a long time period
它运行良好但有时候,经过很长一段时间后,PC停止从Arduino设备接收数据。它不是PC软件问题,因为所有软件(putty,telnet等)的行为都相同 - 我可以将数据发送到Arduino(设备响应命令);我只是无法收回它。
Serial communication stops after long periods. 中描述了类似的问题,但没有提出解决方案。
断开/连接设备暂时解决了问题,但这不是一个解决方案,因为该设备应该永久性地全自动使用。
使用重置程序& amp;它的所有价值都没有帮助。 PC不会开始接收数据。
注意:
使用Arduino 1.0软件在Arduino Uno板上无法重现millis()翻转错误 - 我想这是固定的,而且millis()现在只在50天内完成翻转,就像在文档中说的那样。除了代码millis() independent code之外没有响应。
在向PC发送数据期间闪烁的LED仍然闪烁。
使用字符串会增加内存使用量,但是这个程序太小而不能成为问题。程序运行10个小时后没有使用额外的内存,所以我不打算用其他东西替换Strings,因为串口问题更为重要。
如果您认为问题出在arduino程序错误中,请考虑如何解释TX闪烁&重置没有帮助。
答案 0 :(得分:2)
也许解决问题,让软件重置你的问题。
我运行了以下代码,以确定软件重置是否会重置时钟,从而重置millis()
函数:
void setup()
{
Serial.begin(9600);
Serial.println("Will start sending millis values in 5 seconds...");
delay(5000);
}
void loop()
{
Serial.println(String(millis()));
if (Serial.available() > 0)
{
if (Serial.read() == '@')
{
Serial.println("Rebooting. . .");
delay(100); // Give the computer time to receive the "Rebooting. . ." message, or it won't show up
void (*reboot)(void) = 0; // Creating a function pointer to address 0 then calling it reboots the board.
reboot();
}
}
}
如代码中所述,要使软件重新启动,只需创建一个指向地址0的函数指针并调用它。 事实上,我的结果令人满意:
Will start sending clock values in 5 seconds...
5000
5000
5000
5001
5001
5001
5002
5002
5002
. . .
6804
Rebooting...
Will start sending millis value in 5 seconds...
5000
5000
5000
5001
5001
5001
5002
5002
5002
5003
5003
. . .
我希望这能解决你的问题:)
答案 1 :(得分:0)
如果您经常轮询Arduino,那么作为一种解决方法,您可以在Arduino中实现一个看门狗,如果它长时间没有输出数据到PC,它将重置Arduino。您可以监视Arduino TX引脚,将其引入另一个输入引脚,使用中断......重点是在每次TX活动后重置看门狗。
答案 2 :(得分:0)
时钟可能会折叠。
previousclock = millis()可能会在折叠前陷入高值。您可以扩展测试以包括(currentmilis< previousmillis)加/减一些软糖因子的情况。
BTW它使用了ignas的源代码(OP源代码在没有注册的情况下无法读取,我不想注册)编辑:我从wakkerbot复制了下面的片段,并对其进行了一些编辑。它只是为了 演示了如何使你的last_action时间戳停留在int间隔的顶部(如果bump值不是int_max的除数) 您可以稍微简化上面/下面的逻辑,因为您只对内部/外部间隔测试感兴趣。 Stamp的typedef当然应该适应millis()(unsigned long?)的类型,并删除fakemillis(),并用millis()替换它的引用。
#include <stdio.h>
#define STAMP_INSIDE 0
#define STAMP_BELOW -1
#define STAMP_ABOVE 1
#define STAMP_BEYONDO -1
/* Intentionally very small, for fast wraparound
** Intentionally signed to stress test the logig.
*/
typedef signed char Stamp;
/* fake clock, returns incrementing value, but folds around
*/
Stamp fakemillis(void)
{
static Stamp ticker =0;
return ticker++;
}
/* Check if "test" is inside or above/below the interval {low,high}
** low and high may have been wrapped around zero (--> low > high)
** return
** 0 := "test" inside interval
** 1 := "test" below interval
** -1 := "test" above interval (but wrapped)
** The two impossible cases return -2.
*/
static int check_interval(Stamp low, Stamp high, Stamp test)
{
switch (4 *(high >= low)
+2 *(test >= low)
+1 *(test > high)
) {
case 0: return STAMP_INSIDE; /* inside (wrapped) */
case 1: /* outside (wrapped) */
return ((Stamp)(low - test) < (Stamp)(test - high)) ? STAMP_BELOW : STAMP_ABOVE;
case 2: break; /* impossible */
case 3: return STAMP_INSIDE; /* inside (wrapped) */
case 4: /* all below */
return ((Stamp)(low - test) < (Stamp)(test - high)) ? STAMP_BELOW : STAMP_ABOVE;
case 5: break; /* impossible */
case 6: return STAMP_INSIDE; /* inside normal case */
case 7: /* all above) */
return ((Stamp)(low - test) < (Stamp)(test - high)) ? STAMP_BELOW : STAMP_ABOVE;
}
return STAMP_BEYONDO;
}
/* Get new clock value, test if it is inside interval {*old, *old+width)
** iff inside: return STAMP_INSIDE;
** iff above (or below) return STAMP_ABOVE or STAMP_BELOW
** and UPDATE *old
*/
static int test_or_set(Stamp *old, Stamp width)
{
Stamp tick;
int diff;
tick = fakemillis();
diff = check_interval( *old, *old+width, tick);
if (!diff) return 0;
*old = tick;
return diff;
}
int main(void) {
Stamp goodlast=0;
Stamp tick=0;
Stamp badlast=0;
int goodtest;
int badtest;
unsigned uu;
for (uu = 0; uu < 260; uu++) {
tick= fakemillis();
if (tick > badlast+10) { badlast=tick; badtest=1; } else {badtest =0;}
goodtest = test_or_set ( &goodlast, 10);
printf("%x:Tick=%x bad=%x, badtest=%d good=%x goodtest=%d\n"
, uu, (unsigned) tick
, (unsigned) badlast, badtest
, (unsigned) goodlast, goodtest
);
}
return 0;
}
如果您在“普通”计算机上编译并运行上述程序,您可以看到badlast和badtest卡住了。这就是你的arduino上发生的事情,恕我直言。
更新:绝对溢出/翻转。 (GIYF) http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1200662708
Update2:不相关但编码不好的做法:
#define CMD_SET_SPEED "S"
...
/* Internal configuration */
if(buffer.substring(0,1)==CMD_SET_SPEED) {
updateSpeed(buffer.substring(1));
}
您在这里比较两个字符串。 (这可能是按照c ++的意图处理的,但在C中它只是完全错误。我还建议用一个巨大的switch语句替换重复的if(...){...},这至少会避免调用substr()函数重复。(或内联?)
UPDATE 20111211:这是一个无包装的比较和设置函数,它需要一个指针来比较和设置的值,以及预期间隔的宽度:
int test_and_set_if_beyond( unsigned long *pprev, unsigned long width )
{
unsigned long tick, low,high;
low = *pprev;
high = low+width;
tick = millis();
if (low < high) {
if (tick >= low && tick < high ) return 0; /* normal case */
}
else { /* interval is wrapped , clock could have wrapped */
if (tick >= low || tick < high) return 0;
}
*pprev = tick;
return 1;
}
此函数在loop()部分中使用如下:
if (test_and_set_if_beyond ( &lightTimer, lightnessCheckPeriod)) {
int newLightness = analogRead(brightnessPin);
if(newLightness-lightness > LIGHT_TRESHOLD) {
say(RESPONSE_FLASH);
}
lightness = newLightness;
}
if (test_and_set_if_beyond ( &pingTimer, pingTimerPeriod)) {
say(RESPONSE_PING);
}
if (test_and_set_if_beyond ( &pingLEDTimer, pingTimerPeriod*2)) {
digitalWrite(failPin, HIGH);
}
feed();
最后:恕我直言,RESET不起作用的原因是,并非所有全局变量都在setup()函数中初始化。另外:我认为你应该摆脱String thingies(在运行时是否有GC?)并使用普通的字符缓冲区。
答案 3 :(得分:-2)
Arduino几小时后无法用Arayks和TX 900执行命令,但重启后Arduino已启用。