使用中断处理程序时如何避免全局变量?

vin*_*i_i 8 c embedded global-variables microchip

我大多是用C自学的。我对嵌入式微控制器进行编程。(例如,dsPIC33fj128gp804)我通常使用全局变量,而我曾经读过的所有内容都使用全局变量来谴责,因为它们就像瘟疫一样。我一直在努力减少使用,但是有一种情况我不知道如何不使用全局变量。

微控制器配有中断。中断是硬件外部触发的事件。触发中断后,将停止执行主代码,保存当前工作变量,执行预分配的功能,然后从停止的地方重新开始选择主代码。由于中断是一个独立的函数,可以随时触发,因此无法传入或传出任何函数。

例如,当UART硬件接收到一个字节的数据时,该数据需要先移出硬件缓冲区,然后才能被覆盖。

void __attribute__((interrupt, no_auto_psv)) _U2RXInterrupt(void)
{
    GlobalVariable = U2RXREG; // Move data to global variable
    IFS4bits.U2RXIF = 0; // Clear the UART2 Receive Interrupt Flag
}
Run Code Online (Sandbox Code Playgroud)

有没有全局变量的方法吗?还是这是例外?

Cli*_*ord 7

您应该区分具有外部链接的全局变量和文件范围静态变量。您可以使用后者解决您的问题。

static volatile int shared_variable ;

int getShared(){ return shared_variable ; }

static void isr_handler()
{
    shared_variable++ ;
}
Run Code Online (Sandbox Code Playgroud)

因此,在上面的示例中,对转换单元外部共享变量的唯一访问是通过访问功能getShared()。这种方法当然依赖于使用单独的编译,但是出于许多原因,这并不是一件坏事。

有关避免全局变量的其他技巧以及为什么要这样做的说明,请参阅杰克·甘斯尔(Jack Ganssle)的“全球人群痘”

要考虑的另一件事,以及在这种情况下全局变量特别有问题的原因是,共享变量必须是原子变量或必须在关键部分访问。例如,在16位dsPIC上,32位访问不是原子访问,在这种情况下,可以在访问功能中放置必要的保护,而如果是全局访问,则必须分别保护每个访问:

例如:

static volatile uint32_t shared_variable ;

int getShared()
{ 
    uint32_t ret ;

    _disable_interrupts() ;
    ret = shared_variable ;
    _enable_interrupts() ;

    return ret ;
}
Run Code Online (Sandbox Code Playgroud)


bas*_*142 6

尽可能使用静态全局变量,以便变量仅在该特定源文件的范围内。使用在使用它们的函数中声明的静态变量以获得更好的隔离。

对中断例程和主代码循环中使用的所有变量使用 volatile。

请注意,易变并不意味着您“安全地”在 ISR 和主代码之间共享此变量。不能保证是原子访问,即使用单个 CPU 指令访问变量时。例如,8 位微型计算机上的 16 位变量将需要多个读取指令来读取值。如果中断在两者之间触发,您将损坏 16 位数据,因为仅读取了一半的变量。ISR 之前的第一个 8bit 和 ISR 之后的其他 8bit 返回。这是坏数据,如果涉及指针而不是仅传递 ADC 数据值,则可能会导致巨大问题。这可能会导致计算器溢出。

一个简单的访问应该快速禁用中断、读取值并重新启用它们以确保序列化访问。

在我看来,使用静态全局变量的小型嵌入式系统是一个很好的方法,只要您将其保持在最低限度并直截了当!还可以使用结构将全局变量进一步分解为 less。

全局变量只有在您拥有太多文件并且通过多个文件来回访问它们时才是“邪恶的”。它只会变得非常混乱,您可以轻松创建另一个与另一个现有全局同名的变量。不好。