Arduino锁定

时间:2012-05-12 16:07:26

标签: c++ embedded arduino

以下程序的目的是定期在串行上输出数据帧。周期由定时中断定义,每秒钟。

代码适用于Arduino IDE版本0022,但在1.0上我无法正常工作。使用计时器例程并将maxFrameLength设置为0x40或更高时,控制器将锁定。当使用0x39或更低时,程序继续运行(由闪烁的LED指示)。

这里出了什么问题,为什么?这是一个错误吗?我做错了吗?

我在Mega1280上使用http://code.google.com/p/arduino-timerone/downloads/detail?name=TimerOne-v9.zip作为计时器例程。

#include "TimerOne.h"

#define LED 13
#define maxFrameLength 0x40

boolean stateLED = true;
byte frame[ maxFrameLength ];

void sendFrame() {
  digitalWrite( LED , stateLED );
  stateLED = !stateLED;
  Serial.write( frame, maxFrameLength ); // ptr + bytes to send
}

void setup() {
  pinMode( LED , OUTPUT );
  Timer1.initialize( 1000000 );  // initialize timer1 with 1 second period
  Timer1.attachInterrupt( sendFrame );
  Serial.begin( 9600 );
};

void loop() {
};

2 个答案:

答案 0 :(得分:7)

有许多问题可能会或可能不会导致问题,但在任何情况下都应该修复。这些评论是一般性的;我并不熟悉Arduino或其库。

在中断处理程序(ISR)中发出Serial.write()调用几乎肯定是不合适的。如果Serial对象是中断驱动的,它将具有相关的缓冲区。如果该缓冲区不足以占用所有数据,则该函数可能阻塞,这是中断处理程序中的 no no 。此外,如果定时器中断的优先级高于串行中断,则Serial.write()阻塞时会导致死锁。 0x40(64字节)似乎是串行输出的可能缓冲区大小,因此这可能是主要原因。如果您可以增加可能使其工作的缓冲区大小,但在ISR中执行可能的阻塞操作仍然是一个坏主意。

即使串行输出被轮询而不是中断驱动,你的中断处理程序也会花费相当长的时间,这也是一个坏主意,但在这种情况下可能不是问题,但在 9600,n,8,1 ,64个字符需要67毫秒才能清除发送寄存器。

stateLEDframe是共享变量(在中断和主要上下文之间),因此应声明为volatile

您的片段中未显示更新frame的方式和位置,但由于中断将异步发生,因此frame的任何更新都应位于 critical section < / em> - 至少禁用了timer1中断。


<强>更新

根据A.H.的回复,我下载了源代码并看了一眼。 Serial是\ arduino-1.0 \ hardware \ arduino \ cores \ arduino \ hardwareSerial.cpp / .h中定义的类HardwareSerial的静态对象。发送缓冲区长度确实是64字节,如果缓冲区已满,HardwareSerial::write()函数会“忙等待”。您需要修改并重新构建源以扩展缓冲区或添加write()的非阻塞版本。

然而这肯定是锁定的原因 - 缓冲区永远不会为空,因为在timer1中断运行时无法处理发送中断。

答案 1 :(得分:6)

1.0的

The release notes告诉你:

  • 串行传输现在是异步的 - 即调用 Serial.print()等将数据添加到传输的传出缓冲区 在后台。此外,Serial.flush()命令已被重新调整用途 等待传出的数据传输,而不是丢弃 接收到的数据。

因此,您的代码在1.0之前工作,因为HardwareSerial::write(uint8_t)(这是所有输出的基础)没有缓冲区,只有在传输完字节后才返回。

我觉得这令人惊讶,Serial {{1}}没有提到这种行为。