12/2005 kurs C

Jeżeli masz jakieś uwagi dotyczące bieżącego lub archiwalnych numerów "Elektroniki dla wszystkich" lub zauważyłeś błędy czy nieścisłości to jest to odpowiednie miejsce aby o tym napisać.
ODPOWIEDZ
nirix
-
Posty: 1
Rejestracja: 25 lis 2006, 11:25

12/2005 kurs C

Post autor: nirix » 25 lis 2006, 11:51

Witam w w/w artykule jest moduł delay.h i makro

Kod: Zaznacz cały

#define delayus8(t)\
	{asm volatile( \
		"delayus8_loop%=: \n\t"\
		"nop \n\t"\
		"dec %[ticks] \n\t"\
		"brne delayus8_loop%= \n\t"\
	: :[ticks]"r"(t) );}
następnie makro jest wywołane w funkcji (plik delay.c)

Kod: Zaznacz cały

void delay100us8(uint8_t t)
{  
	while(t>0)
	{    
		delayus8(100); 
		--t; 
	}
}
Problem występuje w tym że wywołanie funkcji np

Kod: Zaznacz cały


delay100us8(2); 

dla zegara 4 MHz powinno dawać opóźnienie ok 200 us
Pod AVRStudio 4.11 daje znacznie więcej po prostu makro

Kod: Zaznacz cały

 delayus8(100)
jest wywoływane wartością 100 tylko podczas pierwszego wywołania
dalej jest to wartość zdaje się 255

Czy można to jakoś ładnie poprawić,
czy może jest to błąd WinAvr20050516

Awatar użytkownika
Koppel
Użytkownik
Posty: 500
Rejestracja: 24 lip 2005, 18:05
Lokalizacja: Gliwice

Post autor: Koppel » 25 lis 2006, 15:27

Witam
W makrze rzeczywiście jest błąd. Chodzi o to, że kompilator uznaje, że jeśli podajemy [ticks] jako parametr wejściowy, to nie zmieniamy jego wartości. Z problemem można poradzić sobie na kilka sposobów:
1. Zamiast makra użyć funkcji rozwijalnej (static inline) a parametr podać jako parametr wyjściowy odczytywalny (zamiast "=" - "+". Według dokumentacji kompilator tego nie obsługuje, ale sprawdziłem praktycznie, że nie jest to prawdą, taka skłądnia działa. Wygląda to jak poniżej:

Kod: Zaznacz cały

static inline void delayus8(uint8_t t)
{
	asm volatile(
		"delayus8_loop%=: \n\t"
		"nop \n\t"
		"dec %[ticks] \n\t"
		"brne delayus8_loop%= \n\t"
		:[ticks]"+r"(t)
		:
	);
}
Drugą możliwością, jeśli koniecznie chcemy aby opóźnienie było realizowane jako makro jest zapis jak niżej:

Kod: Zaznacz cały

#define delayus8(us)\
	{ \
	uint8_t t = us; \
	asm volatile( \
		"delayus8_loop%=: \n\t"\
		"nop \n\t"\
		"dec %[ticks] \n\t"\
		"brne delayus8_loop%= \n\t"\
		:[ticks]"+r"(t) \
		: \
	);}
Konieczne jest wykrzystanie zmiennej pomocniczej, ponieważ inaczej nie będzie możliwości wywołania makra przy podaniu stałej wartości opóźnienia (stała nie może być parametrem wyjściowym. Nie działa natomiast prawidłowo sposób wykorzystany w makrach z pliku util/delay.h - może jeszcze coś przeoczyłem ;/

ODPOWIEDZ