Изменение глобальной переменной в C
Я запускаю программу C на чипе AVR. Всякий раз, когда слышен последовательный сигнал, он запускает ISR последовательного прерывания (USART_RX_vect). В этом методе должно быть включено изменение = 1;
, Тогда в моей главной while
цикл, он должен очистить ЖК-дисплей и отобразить его, а затем установить change = 0
снова.
Это сделано для того, чтобы он постоянно выполнял вычисления и отображал результат на ЖК-дисплее миллион раз в минуту.
Однако, когда метод прерывания меняет переменную изменения на 1, он, похоже, не меняет ее "глобально", а в основном методе это всегда 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);
}
}
3 ответа
Вам нужно объявить об изменении, используя ключевое слово volatile:
volatile int change;
Это говорит двум "потокам" (основной цикл выполнения и ваш код ISR) не "кэшировать" значение в регистре, а всегда извлекать его из памяти.
Редактировать: есть другая проблема с кодом - в вашем основном цикле к тому времени, когда вы установили значение 0, у вас, возможно, уже было другое прерывание, которое должно было запустить ваш цикл для повторного запуска. Простое, но не гарантированное исправление состоит в том, чтобы сразу же установить значение 0 сразу после его проверки. Правильным способом было бы использовать блокировку - но в зависимости от вашей ситуации может подойти первый вариант.
Сделайте объявление переменной энергозависимым, чтобы гарантировать, что измененное значение будет немедленно записано в переменную в памяти.
Объект, совместно используемый обработчиком прерываний и кодом приложения, должен быть квалифицирован как volatile
в декларации.
Без квалификатора реализация может предполагать, что объект не может неожиданно измениться в коде приложения, и может кэшировать переменную (например, в регистре) для оптимизации при выполнении кода приложения.