【问题标题】:ATmega2560 using UART interrupt to control global flagATmega2560使用UART中断控制全局标志
【发布时间】:2017-01-09 13:55:45
【问题描述】:

我最近在玩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()),它才起作用。

这毫无意义。我记得的是我不需要这些函数,它仍然可以设置全局变量来影响主循环。或者我错过了什么细节?请给我一些线索来弄清楚,我很困惑。

【问题讨论】:

  • 请在此处发布您的代码,而不是通过外部链接。
  • 进入 ISR 是更糟糕的主意......永远......我猜你是从非中断驱动代码中复制的。
  • 看起来对中断的工作方式存在一些重大误解。并且缺少代码。阅读How to Ask 并听从建议!
  • @MichaelWalz 抱歉,我是新来的,对如何解释我遇到的事情感到有点紧张。下次我会做得更好。谢谢。
  • @LPs 是的,我确实误解了非中断驱动的示例代码......感谢您的意见!

标签: c arduino uart interrupt-handling atmega


【解决方案1】:

无法确定,但我认为这可以解释您的问题,因此很可能是错误。

您没有包含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

【讨论】:

  • 使用 gcc,一半的 AVR 寄存器是 callee-saved。 gcc 在优化时会利用它,甚至可以在函数调用之间将值保存在寄存器中。函数调用也可以内联,因此对于优化器来说,它甚至不会作为调用发生。
猜你喜欢
  • 2021-12-08
  • 1970-01-01
  • 2012-10-25
  • 1970-01-01
  • 2012-07-26
  • 1970-01-01
  • 2013-08-29
  • 2019-04-26
  • 2018-03-02
相关资源
最近更新 更多