我开始在一些需要UART的项目工作中使用Arduino Due,并且对UART中断和I/O之间的交互感到困惑。
我的第一段代码是一个小例程,用于设置UART,在收到TXBE中断时通过加载传输缓冲区来连续发送数据。我将UART输出连接到示波器上,并将另一个I/O引脚设置为通用输出,该输出将翻转状态,因此在重新加载传输缓冲区时用于触发示波器。问题是我看到了UART数据,它看起来不错,但I/O没有翻转。在这一点上,我的loop()
例程是空的,所以我设置了另一个输出端口,在loop()
中只是切换它的状态作为健全性检查。除了UART之外仍然没有输出。
这是我最终得到的代码:
uint32_t tempo; // 32-bit temporary variable
boolean flag = true;
void UART_Handler(void) {
REG_UART_THR = 0x6DL; // load data into the transmit buffer
if (flag) {
REG_PIOD_SODR = 0x02L; // drive PD1 high
flag = false;
} else {
REG_PIOD_CODR = 0x02L; // drive PD1 low
flag = true;
}
}
void setup() {
// set up the UART I/O
REG_PIOA_IDR = 0x0300L; // disable interrupts on PA8 and PA9
tempo = REG_PIOA_ABSR; // get the current settings of the AB select register
REG_PIOA_ABSR = tempo & 0xFFFFFCFF; // set PA8 and PA9 to peripheral A control
REG_PIOA_PDR = 0x0300L; // disable parallel I/O for PA8 and PA9
NVIC_EnableIRQ(UART_IRQn); // enable UART interrupts in NVIC
// now set up the UART
tempo = REG_PMC_PCSR0; // get the current settings of the peripheral clock register 0
REG_PMC_PCER0 = tempo | 0x0100L; // enable the UART clocks
REG_UART_CR = 0x0CL; // reset UART receiver and transmitter
REG_UART_MR = 0x0800L; // set to normal outputs with no parity
REG_UART_BRGR = 0x89L; // baud rate set to 38400
REG_UART_IDR = 0x1FBL; // disable all UART interrupts
REG_UART_IER = 0x0800L; // enable TXBUFE interrupt
REG_UART_CR = 0x50L; // enable UART receiver and transmitter
// set up the debug outputs
REG_PIOD_IDR = 0x03L; // disable interrupts on PD0 and PD1
REG_PIOD_PER = 0x03L; // enable parallel I/O for PD0 & PD1
REG_PIOD_OER = 0x03L; // set PD0 & PD1 output enabled
REG_PIOD_CODR = 0x03L; // drive PD0 & PD1 low
}
void loop() // run over and over
{
REG_PIOD_SODR = 0x01L; // drive PD0 high
delay(1);
REG_PIOD_CODR = 0x01L; // drive PD0 low
delay(1);
}
作用域输出可以在http://www.iwanczuk.com/temp/scope1.png(没有足够的声誉在这里张贴图片!)。
在盯着事情看了一段时间却没有得到任何见解之后,我通过注释掉REG_UART_IER = 0x0800L; // enable TXBUFE interrupt
行禁用了TXBUFE中断,然后PortD1的切换是可见的,但显然没有UART输出(请参阅http://www.iwanczuk.com/temp/scope2.png)。这两者似乎是相互排斥的,如果这是真的,那就太傻了。我确信我错过了什么,但我看不见或找不到它是什么。
我已经阅读了SAM3X8E数据表,看看是否有我明显遗漏的东西,如果有,我看不见。我还做了我认为相关的网络搜索,但没有找到解决方案。我还尝试过将通用输出用于端口A和端口D上的两个输出,并在两个Arduino Due板上尝试过,结果都相似。
有人知道我可能做错了什么吗?提前谢谢。
好吧,我已经弄清了这个问题的真相。不确定这是最好的答案,但这是一个解决方案。它的长短是为了避免TXBE中断。如果我使用TXEMPTY中断,它可以正常工作。
Atmel数据表第168页上的一行写道(原文如此)"即使被禁用,中断也可以进入挂起状态",所以我想知道TXBE的问题是否是因为我没有在ISR之前甚至内部清除挂起的中断,所以我在ISR开始时以及在启用TXBE中断之前添加了NVIC_ClearPendingIRQ(UART_IRQn);
,但(错误)行为没有改变。
TXEMPTY的操作(对我来说)仍然有点奇怪,因为中断似乎是由传输移位寄存器为空而产生的,而不是当变为空时。如果您在没有加载传输缓冲区的情况下启用中断,您将立即获得中断。有些人可能喜欢这种"自启动"的行为,但它对我来说并不管用。我正在编写我的发送例程,这样在发送器加载了要发送的第一个字节之前,TXEMPTY中断才会启用。
基于Arduino论坛上的这篇帖子:http://forum.arduino.cc/index.php?topic=186388.0我认为USART也有类似的问题。
希望这能帮助其他人。
我刚刚意识到问题根源的真正错误是什么。UART中断寄存器描述在传输缓冲区为空的情况下讨论TXBUFE位,因此我的假设是,当我可以将另一个字节放入传输保持寄存器时,这是告诉我的位。然而,UART状态寄存器描述称TXBUFE位是"来自发射机PDC通道的缓冲区满信号"。后者对这一点的作用提出了完全不同的看法。根据UART状态寄存器的描述,我需要查看的位是TXRDY位!