Arduino锁定

jip*_*pie 3 c++ embedded arduino

以下程序的目的是定期输出串行数据帧.周期由定时中断定义,每秒一次.

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

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

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

#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() {
};
Run Code Online (Sandbox Code Playgroud)

Cli*_*ord 7

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

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

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

stateLED并且frame是共享变量(在中断和主要上下文之间),因此应该声明为volatile.

在您的片段中未显示frame更新的方式和位置,但由于中断将异步发生,因此任何更新frame都应位于关键部分 - 至少禁用timer1中断.


更新

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

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


A.H*_*.H. 6

1.0 的发行说明告诉你:

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

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

我觉得很惊讶,也参考页Serial没有提到这个问题.