我最近在玩ATmega2560时遇到了一个问题,我真的不明白这是怎么回事。
这是我的代码。
主要:
#include "Definitions.h"
int main(void) {
Initialization();
while (1) {
//_delay_ms(1); // or printf...
//wait for RXC flag
if (RxFlag) {
//wait for new byte in
//PORTB &= ~(1 << PB7);
PORTB |= (1 << PB7);
rxcount = 0;
UDR0 = 'R';
RxFlag = false;
TxFlag = false;
}
}
}
IRQ:
#include "Definitions.h"
ISR(USART0_RX_vect) {
while(!(UCSR0A & (1 << RXC0)))
//wait for RXC flag
;
/* Loop-back test */
//PORTB |= (1 << PB7);
//test_data = UDR0;
TxFlag = true;
//enableUDRI0();
//PORTB &= ~(1 << PB7);
//PORTB |= (1 << PB7);
RxBuffer[rxcount++] = UDR0;
if(!(rxcount < RX_BUF_SZ)) {
//rxcount = 0;
PORTB |= (1 << PB7);
RxFlag = true;
}
}
ISR(USART0_UDRE_vect) {
while(!(UCSR0A & (1 << UDRE0)))
//wait for udr to be empty
;
/* Loop-back test */
UDR0 = 0x30 + rxcount;
disableUDRI0();
}
问题是,当我从USART接收到一些数据时,我试图设置一个RxFlag,它可以在主循环中激活if语句。但是,直到我在if语句之前取消注释该函数(直到它可能是_delay_ms()或printf())之后,它才起作用。
这没有道理。我记得的是,我不需要那些功能,它仍然可以设置全局变量来影响主循环。还是我错过了任何细节?请给我一些线索以弄清楚,我很困惑。
最佳答案
不可能确定,但是我认为这可以解释您的问题,因此很可能是错误。
您没有包括RXFlag
的声明,但是我想您不是在声明volatile
。除非您这样做,否则允许编译器假定它知道该变量将发生的一切。特别是,它知道,除非main()
调用任何其他函数,否则RxFlag的值永远不会改变。因此,它可以通过将if
表达式移到循环外来优化它。实际上,它是在更改您的代码,如下所示:
#include "Definitions.h"
int main(void)
{
register bool x;
Initialization();
x = RxFlag;
while (1)
{
//wait for RXC flag
if (x) //wait for new byte in
{
//PORTB &= ~(1 << PB7);
PORTB |= (1 << PB7);
rxcount = 0;
UDR0 = 'R';
RxFlag = false;
TxFlag = false;
}
}
}
但是,如果
main()
调用另一个函数,则编译器将放弃通过该调用将RxFlag保留在寄存器中的尝试。另一个函数可能会更改保存RxFlag的寄存器。它将不得不将其压入堆栈或其他东西。再次读取它在代码和时间上都比较便宜,因此每次循环时都会读取它。此错误的正确解决方案是将在主线程和ISR之间共享的所有变量声明为
volatile
。关于c - ATmega2560使用UART中断来控制全局标志,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41549624/