在 Serial.write(buf, len) 发出的 UART 传输完成后,我想执行一些代码(比如切换标志变量)。
我尝试了几件事都没有成功。有人可以建议最好的方法吗?
谢谢。米
在 Serial.write(buf, len) 发出的 UART 传输完成后,我想执行一些代码(比如切换标志变量)。
我尝试了几件事都没有成功。有人可以建议最好的方法吗?
谢谢。米
根据 Arduino 存储库上的代码(您可以在此处查看,尤其是HardwareSerial
和Stream
类Print
),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()
;如果您只想测试它(然后做其他事情),请测试上面报告的两位。
尝试这个:
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.
}