0

在 Serial.write(buf, len) 发出的 UART 传输完成后,我想执行一些代码(比如切换标志变量)。

我尝试了几件事都没有成功。有人可以建议最好的方法吗?

谢谢。米

4

2 回答 2

0

根据 Arduino 存储库上的代码(您可以在此处查看,尤其是HardwareSerialStreamPrint),Serial类函数没有阻塞:它们使用由 ISR 清空的内部缓冲区。

查看代码,您有两种可能性。

第一个也是最简单的一个是使用内置Serial.flush函数。此函数等待 uC 完成发送,只有在所有内容都发送完毕后才返回。

第二种方法是模仿冲洗行为;如果您不希望程序停止(即执行其他任务)并且只需检查板是否正在发送数据,这就是您所需要的。如果位 UDRIE0(寄存器 UCSR0B)被设置,那么库的队列中有一些数据。但是,最后,您必须等待发送最后一个字节,因此您还必须检查位 TXC0(寄存器 UCSR0A)是否被清除。

为了实现和测试这一点,我编写了这个简单的程序:

unsigned long thisMillis = -1;
unsigned long lastMillis = -1;
char mybuffer[256];

void setup() {
  Serial.begin(9600);
}
bool isSending()
{
  return bit_is_set(UCSR0B, UDRIE0) || bit_is_clear(UCSR0A, TXC0);
}
void loop() {
  int printed = snprintf(mybuffer, 256, "time: %lu\r\n", millis());
  Serial.write(mybuffer, printed);
  // Just enable ONE of the following methods
  //Serial.flush();
  //while(isSending());
  lastMillis = millis();
}

然后我模拟了它。

当刷新和 while 均未启用时,板会缓冲字符串,直到可以为止。然后,当缓冲区变满时,开始等待一些字符消失,然后再次填充它。因此,我们将在前几毫秒看到很多字符串,然后是几乎等间距的字符串(当缓冲区已满时)。实际上程序的输出是这样的:

time: 0
time: 0
time: 1
time: 1
time: 1
time: 1
time: 2
time: 2
time: 7
time: 17
time: 27

但是,当我们取消注释 Serial.flush 函数时,循环将等待所有数据从 uC 中取出,然后再次循环。这导致从一开始就等间隔的时间戳,实际上这是输出

time: 0
time: 9
time: 19
time: 29
time: 39
time: 51

启用 while 循环时,行为完全相同:

time: 0
time: 9
time: 19
time: 29
time: 39
time: 51

所以,总结一下:如果你想等待董事会发送,就去吧Serial.flush();如果您只想测试它(然后做其他事情),请测试上面报告的两位。

于 2016-02-03T22:06:32.820 回答
0

尝试这个:

void setup() {

Serial.begin(9600);

 _SFR_BYTE(UCSR0B) |= _BV(TXCIE0);        //Enable TXCIE0 interrupts

Serial.print("When UART finishes to send this text, it will call the routine ISR(USART0_TX_vect) ");

}


void loop() {


}

  ISR(USART1_TX_vect)
{
//do whatever you want, but as quick as you can.

}
于 2016-09-25T10:28:53.647 回答