[c] Zmiana wartości zmiennej z procedury przerwania

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
Awatar użytkownika
c4r0
Moderator
Posty: 2150
Rejestracja: 13 kwie 2004, 19:56
Lokalizacja: z lasu
Kontakt:

[c] Zmiana wartości zmiennej z procedury przerwania

Post autor: c4r0 » 09 lis 2008, 17:38

Ostatnio zacząłem po części z przymusu programować trochę AVR-y w C. Od jakiejś godziny walczę z bardzo dziwnym problemem. Chodzi o zmianę wartości zmiennej z procedury przerwania generowanego przez odebranie danych z UART. Poniżej kod.

Kod: Zaznacz cały

#define F_CPU 4000000
#define UART_BAUD  9600
const char ADR[2] = "AA";

#define cbi(sfr, bit)   (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit)   (_SFR_BYTE(sfr) |= _BV(bit))

#include <stdio.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#include "uart.c"
#include "MB.c"

FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW); 

char buff[100];
int d = 10;

SIGNAL (SIG_UART_RECV){
	int ret = MB_Read(buff);

	switch (ret){
		case 4:
			sscanf(buff, "%X", &d);
			printf("delay changed to %d\n", d);
			break;
	}
	printf("*** funkcja: %d , dane: %s\n", ret, buff);
}

int main(void)
{
	uart_init();
	sei();

	stdout 	= stdin = &uart_str; 
  
  	DDRB	= 0xFF;
	DDRD	= 0xFF;
	DDRC	= 0x00;
	PORTC	= 0x00;

	TCCR1A 	= _BV(COM1A1)|_BV(COM1A0)|_BV(WGM10)|_BV(WGM11);
	TCCR1B 	= _BV(CS00); 
	OCR1A	= 1023;

	printf("\nHello world!\n");

	while(1){
		sbi(PORTD, 7);
		for(int i = d; i>0; i--) _delay_ms(10);
		cbi(PORTD, 7);
		for(int i = d; i>0; i--) _delay_ms(10);
		//printf("%d", d);
	}
    return(0);
}
W pętli while(1) stan jednego pinu (podpięty LED) zmienia się co czas wyznaczony przez zmienną d. Gdy przyjdą odpowiednie dane na UART wartość zmiennej d ma się ustawić na np. 100, po czym program wyrzuca na UART komunikat "delay changed to 100" - to działa, dostaję w komunikacie wartość taką jak powinna być. Problem w tym, że LED wcale nie zmienia prędkości migania... Po "uruchomieniu" komendy printf w pętli while(1), która wyrzuca na UART wartość zmiennej d, wszystko zaczyna działać jak należy, czyli LED zaczyna migać wolniej, ale dodatkowo odstaję co chwila wartość d w terminalu. Bez tego printf program zachowuje się tak, jakby główna procedura pamiętała wartość zmiennej d sprzed zadziałania przerwania. Powiedzcie proszę co to za chocki klocki bo ja się już pogubiłem...

Przy okazji jeszcze jedno pytanie. Korzystam z funkcji _delay_ms(), jeśli podam jako argument stałą liczbę (np. 10 tak jak w programie) to jest ok, ale jak podam jako argument zmienną to wszystko ładnie się kompiluje ale objętość programu wzrasta dwukrotnie i nie mieści się już w pamięci. Dlaczego tak się dzieje?

Awatar użytkownika
radzio
Użytkownik
Posty: 573
Rejestracja: 07 gru 2004, 23:06
Lokalizacja: Sosnowiec
Kontakt:

Post autor: radzio » 09 lis 2008, 17:52

Każda zmienna, na której są wykonywane operacje w przerwaniach musi być typu volatile.

Awatar użytkownika
c4r0
Moderator
Posty: 2150
Rejestracja: 13 kwie 2004, 19:56
Lokalizacja: z lasu
Kontakt:

Post autor: c4r0 » 09 lis 2008, 18:18

Pomogło - DZIĘKI :mrgreen:

ODPOWIEDZ