【问题标题】:Changing a global variable in C在 C 中更改全局变量
【发布时间】:2012-03-02 23:03:51
【问题描述】:

我正在 AVR 芯片上运行 C 程序。每当听到串行信号时,它就会运行串行中断 ISR (USART_RX_vect)。在这种方法中,它应该打开更改为= 1;。然后在我的主 while 循环中,它应该清除 LCD 并显示它,然后再次设置 change = 0

这是为了阻止它继续进行计算,并在一分钟内将结果显示在 LCD 上一百万次..

但是,当中断方法将 change 变量更改为 1 时,它似乎并没有“全局”更改它,并且在 main 方法中它始终为 0..

这里有一些用于调试目的的东西。

/* LCD DEFINES */
#define LED PB5
#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)

/* UART SERIAL DEFINES */
#define F_CPU 16000000UL
#define BAUD 9600
#define MYUBRR F_CPU/16/BAUD-1

#define STARTCHAR 'R'
#define ENDCHAR 'E'

char reading;
char inputBuffer[12];
char readStatus;
uint8_t position;
int change;

char output;
int result;

struct Axis
{
    uint8_t axisNumber;
    uint16_t position;
    uint16_t oldPosition;

} axis1, axis2, axis3;


/* SETUP UART */

void USART_Init( unsigned int ubrr)
{
   /*Set baud rate */
   UBRR0H = (unsigned char)(ubrr>>8);
   UBRR0L = (unsigned char)ubrr;

  /*Enable receiver and transmitter */
   UCSR0B = (1<<RXEN0)|(1<<TXEN0);

   /* Set frame format: 8data, 2stop bit */
   UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}

void USART_Transmit( unsigned char data )
{
    UDR0 = data;
}

unsigned char USART_Receive( void )
{
   return UDR0;
}

/*****************************************************************/

int main(void)
{
    /* INITALISE SERIAL */
    USART_Init(MYUBRR);

    /* Turn on Receive Complete Interrupt */
    UCSR0B |= (1 << RXCIE0);

    /* Turn On GLobal Interrupts */
    sei();

    position = 0;
    change = 0;

    /* Initialise LCD */
    lcd_init(LCD_DISP_ON);  /* Initialize display, cursor off. */
    lcd_clrscr();
    lcd_puts("READY");

    //Turn on LED 13
    set_output(PORTB,LED);
    output_low(PORTB,LED);

    while (1)               /* Loop forever */
    {
        if (change == 1)
        {
            //If not reading, display the result on the LCD display.
            axis1.position  = (inputBuffer[0]<< 8) | inputBuffer[1];
            axis2.position  = (inputBuffer[2]<< 8) | inputBuffer[3];
            axis3.position  = (inputBuffer[4]<< 8) | inputBuffer[5];

            char axis1Printout[12];
            char axis2Printout[12];
            char axis3Printout[12];

            sprintf(axis1Printout,"%u ", axis1.position);
            sprintf(axis2Printout,"%u ", axis2.position);
            sprintf(axis3Printout,"%u ", axis3.position);

            char output[40] = "";
            strcat(output, axis1Printout);
            strcat(output, axis2Printout);
            //strcat(output, axis3Printout);

            lcd_clrscr();  /* Clear the screen*/
            lcd_puts(output);
            _delay_ms(300);
            change = 0;
        }
    }
}

/* INTERRUPTS */

ISR (USART_RX_vect)
{
    change = 1;
    unsigned char input = USART_Receive();

    if (input == 'R')
    {
        readStatus = 0; //Reading
        position = 0;
    }
    else if ((input != 'E') && (position < 12) && (position > -1))
    {
        inputBuffer[position] = input;
        position++;
    }
    else if (input == 'E')
    {
        readStatus = 1; //Stop Reading
        position = -1;
        output_high(PORTB,LED);
    }
}

【问题讨论】:

  • 你确定 ISR 真的被调用了吗?

标签: c avr-gcc


【解决方案1】:

进行变量声明volatile 以确保将更改的值立即写入内存中的变量。

【讨论】:

    【解决方案2】:

    由中断处理程序和应用程序代码共享的对象应在声明中限定为volatile

    没有限定符,实现可以假设对象不会在应用程序代码中发生意外更改,并且可以在执行应用程序代码时缓存变量(例如在寄存器中)以进行优化。

    【讨论】:

      【解决方案3】:

      您需要使用 volatile 关键字声明更改:

      volatile int change;
      

      这告诉两个“线程”(主执行循环和您的 ISR 代码)不要“缓存”寄存器中的值,而是始终从内存中检索它。

      编辑:代码还有另一个问题 - 在您的主循环中,当您将设置更改为 0 时,您可能已经有另一个中断应该触发您的循环再次运行。简单但不保证的解决方法是在您检查后立即设置更改为 0。正确的方法是使用锁 - 但根据您的情况,第一个选项可能会这样做。

      【讨论】:

      • 我会将更改留在最后,并确保中断不会更新值,直到更改为 0。这将防止中断在主例程读取它们时破坏值。跨度>
      • 另一种选择是在中断本身中清除中断标志,并让主程序重新启用中断。我自己不熟悉 AVR,但是处理器通常不会在中断时清除中断标志,并且您需要在中断例程结束时调用 sei() 吗?您可以在完成处理后将其留给主例程 - 在我使用的大多数处理器上,它会在全局中断被禁用时排队中断,因此如果数据在您处理时到达,它将在您重新处理时中断-启用它们。缓冲区长度可能是一个问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-11
      • 1970-01-01
      • 2013-03-09
      • 2013-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多