Skocz do zawartości
Zaloguj się, aby obserwować  
sobal44

[c][atmega128]problem z przerwaniem

Pomocna odpowiedź

Zobacz moje artykuły o PWM: https://www.forbot.pl/forum/topics20/kurs-programowania-arm-cz7-pwm-vt3926.htm

i https://www.forbot.pl/forum/topics20/kurs-programowania-arm-cz8-pwm-cd-vt3948.htm

Poza początkiem, który dotyczy sprzętowego PWM i jest inny dla ARM i AVR, dalej jest dokładnie to co robisz - programowy PWM.

Wystarczy że zmienisz stałą czasową na 10µs, okres PWM na 20ms i gotowe.

Udostępnij ten post


Link to post
Share on other sites
mog123, to jaka jest wg. Ciebie najlepsza w takiej sytuacji?

Taka jak w pierwszym poście(ale bez delay_ms bo te funkcje są brzydkie), bo wywłaszczasz czas do procesora i dokładnie możesz wyliczyć kiedy główna funkcja dostanie z powrotem nad nim kontrolę - to jest praca w czasie rzeczyiwstym

W ogóle kto używając timer'y stosuje delay_ms?😋

masz jakąś inną metode obsługi serw, to sie podziel.

Ja bym napisał sobie zegar rtc w oparciu o działające już timery i utworzył strukture czasu(godziny, minuty, sekundy, mili, nano). Utworzył jedna instancje tej struktury jako znacznik i tym odmierzał czas.

Udostępnij ten post


Link to post
Share on other sites
Wystarczy że zmienisz stałą czasową na 10µs, okres PWM na 20ms i gotowe.

przcież mam tak zrobione

Udostępnij ten post


Link to post
Share on other sites

W Twoim rozwiązaniu trzymasz procesor w pętli podczas przerwania. To bardzo zły pomysł pod prawie każdym względem.

Zamiast tego wywołuj przerwanie co 10µs (lepiej trochę rzadziej). I w tym wywołaniu sprawdzaj, czy liczniki PWM wymagają zmiany stanu - przykład znajdziesz w moim artykule.

Ja używam przerwań co 100µs, ale to można oczywiście zmienić.

[ Dodano: 10 Sie 10 02:19 ]

Coś pomieszane jest w zmiennych, ja bym to napisał tak:

SIGNAL(SIG_OUTPUT_COMPARE1A)//Przerwanie obsługi serw)
{
 static unsigned int counter = 0;

 if (++counter>=2000) { // 20ms / 10µs
   counter = 0;
   PORTC = 0xff;
 }

 if (C0==counter) {PORTC &= 0b11111110;}
 if (C1==counter) {PORTC &= 0b11111101;}
 if (C2==counter) {PORTC &= 0b11111011;}
 if (C3==counter) {PORTC &= 0b11110111;}
 if (C4==counter) {PORTC &= 0b11101111;}
 if (C5==counter) {PORTC &= 0b11011111;}
 if (C6==counter) {PORTC &= 0b10111111;}
 if (C7==counter) {PORTC &= 0b01111111;}
}

Udostępnij ten post


Link to post
Share on other sites
Zamiast tego wywołuj przerwanie co 10µs (lepiej trochę rzadziej). I w tym wywołaniu sprawdzaj, czy liczniki PWM wymagają zmiany stanu - przykład znajdziesz w moim artykule.

Ja używam przerwań co 100µs, ale to można oczywiście zmienić.

SIGNAL(SIG_OUTPUT_COMPARE1A)//Przerwanie obsługi serw)
{


spr1++;
if(!(spr1)){PORTC = 0xFF;}


	if(C0==spr1){PORTC &= 0b11111110;}
	if(C1==spr1){PORTC &= 0b11111101;}
	if(C2==spr1){PORTC &= 0b11111011;}
	if(C3==spr1){PORTC &= 0b11110111;}
	if(C4==spr1){PORTC &= 0b11101111;}
	if(C5==spr1){PORTC &= 0b11011111;}
	if(C6==spr1){PORTC &= 0b10111111;}
	if(C7==spr1){PORTC &= 0b01111111;}

if(spr1>180){spr1 = -6; PORTC = 0x00;}
}

mam coś takiego zaraz sprawdze czy działa

[ Dodano: 10 Sie 10 02:28 ]

NO FAKT NIE MAM W TYM SWOIM PRZERWANIU TYCH 20MS

[ Dodano: 10 Sie 10 02:30 ]

SIGNAL(SIG_OUTPUT_COMPARE1A)//Przerwanie obsługi serw)

{

static unsigned int counter = 0;

if (++counter>=2000) { // 20ms / 10µs

counter = 0;

PORTC = 0xff;

}

if (C0==counter) {PORTC &= 0b11111110;}

if (C1==counter) {PORTC &= 0b11111101;}

if (C2==counter) {PORTC &= 0b11111011;}

if (C3==counter) {PORTC &= 0b11110111;}

if (C4==counter) {PORTC &= 0b11101111;}

if (C5==counter) {PORTC &= 0b11011111;}

if (C6==counter) {PORTC &= 0b10111111;}

if (C7==counter) {PORTC &= 0b01111111;}

}

A W TYM TWOIM PRZERWANIU co rozpoczęcie przerwania nie bedzie zmienna counter przyjmować wartości 0 ??

[ Dodano: 10 Sie 10 02:33 ]

tak żle napisałeś. w twoim przypadku PORTC bedzie sie zerował zanim zostanie wstawiona na niego jedynka,

[ Dodano: 10 Sie 10 02:39 ]

SIGNAL(SIG_OUTPUT_COMPARE1A)//Przerwanie obsługi serw)
{


static int spr1 = (-2000);
   spr1++;

if(!(spr1)){PORTC = 0xFF;}
if(spr1>5)
{
	if(C0==spr1){PORTC &= 0b11111110;}
	if(C1==spr1){PORTC &= 0b11111101;}
	if(C2==spr1){PORTC &= 0b11111011;}
	if(C3==spr1){PORTC &= 0b11110111;}
	if(C4==spr1){PORTC &= 0b11101111;}
	if(C5==spr1){PORTC &= 0b11011111;}
	if(C6==spr1){PORTC &= 0b10111111;}
	if(C7==spr1){PORTC &= 0b01111111;}
}	
if(spr1>180){spr1 = (-2000); PORTC = 0x00;}

}

teraz mam coś takiego i jakoś nie działa

Udostępnij ten post


Link to post
Share on other sites
tak żle napisałeś. w twoim przypadku PORTC bedzie sie zerował zanim zostanie wstawiona na niego jedynka,

A dlaczego ma się zerować?

Udostępnij ten post


Link to post
Share on other sites
Cytat:

tak żle napisałeś. w twoim przypadku PORTC bedzie sie zerował zanim zostanie wstawiona na niego jedynka,

A dlaczego ma się zerować?

to ma wyglądać tak :

przez 20 ms ma być "0"na PORTC, pożniej przez 60us ma byc "1" na wszystkich wyjściach PORTC, pożniej sprawdzć zmienne C0,C1...C7 jeśli np. C1(serwo1) ma być w położeniu 180stopni to jedynka ma być przez 2.4ms, jeśli w położeniu 0 stopni , tylko przez te minimalne 0.6ms

Udostępnij ten post


Link to post
Share on other sites

Coś przekombinowujesz. Mój program na Cn x 10µs wystawia logiczne 1 na wyjściu. Czyli jak chcesz obrócić w jedną stronę wykonujesz kod:

C0 = 6;

I dostajesz impuls 60us.

Jak potrzebujesz w przeciwną stronę, to piszesz:

C0 = 240;

I impuls wynosi 2.4ms.

[ Dodano: 10 Sie 10 02:56 ]

a co do zerowania, to:

static int counter=0;

Będzie działać poprawnie. Zmienna jest zadeklarowana jako statyczna, więc przypisanie zera zostanie wykonane tylko raz, przy pierwszym wejściu w zasięg zmiennej.

Udostępnij ten post


Link to post
Share on other sites

ale i tak musi przyjmować wartość od 0 do 180 ma być odzwierciedleniem kąta położenia serwa, inaczej bym musiał zmieniać wszystkie wzory kinematyki odwrotnej

Udostępnij ten post


Link to post
Share on other sites

To chyba łatwiej napisać funkcję, która przeliczy kąt na wartość PWM niż modyfikować działanie PWM.

Możesz nawet dodać takie przeliczanie przy resetowaniu licznika, będziesz miał od razu z głowy rejestry cienie (shadow registers). Bo bez tego serwa mogą szarpać.

Udostępnij ten post


Link to post
Share on other sites

Wlasicwie, to dlaczego nie skorzystasz ze sprzetowego PWM ktory jest w atmedze?

Udostępnij ten post


Link to post
Share on other sites

a teraz czy timer dobrze ustawiłem ?

TIMSK = (1<

OCR1A = 0x00A0;

TCCR1B = (1<

[ Dodano: 10 Sie 10 03:14 ]

Wlasicwie, to dlaczego nie skorzystasz ze sprzetowego PWM ktory jest w atmedze?

niestety w atmedze nie ma 20 PWM

[ Dodano: 10 Sie 10 03:18 ]

SIGNAL(SIG_OUTPUT_COMPARE1A)//Przerwanie obsługi serw)

{

static int counter = (-6);

if (C0==counter) {PORTC &= 0b11111110;}

if (C1==counter) {PORTC &= 0b11111101;}

if (C2==counter) {PORTC &= 0b11111011;}

if (C3==counter) {PORTC &= 0b11110111;}

if (C4==counter) {PORTC &= 0b11101111;}

if (C5==counter) {PORTC &= 0b11011111;}

if (C6==counter) {PORTC &= 0b10111111;}

if (C7==counter) {PORTC &= 0b01111111;}

if (++counter>=1994) { // 20ms / 10µs

counter = (-6);

PORTC = 0xff;

}

}

jeszcze bym prosił o sprawdzenie tego przerwania, w tym wypadku jeśli wstawie na Cn 0 to powinien mieć impuls o długości 60us?

Udostępnij ten post


Link to post
Share on other sites

Chyba będzie miał 70us, ale nie jestem pewien. Najlepiej oscyloskop podłączyć i sprawdzić.

Udostępnij ten post


Link to post
Share on other sites
Najlepiej oscyloskop podłączyć i sprawdzić.

jak bym taki miał, to bym sprawdził 🙂

Udostępnij ten post


Link to post
Share on other sites

Moim zdaniem wychodzi 70us, ale to chyba nie robi różnicy. Ogólnie powinno działać. Natomiast aktualizacja zmiennych C0 itd. będzie powodować błędy. Czasem pojawią się impulsy o długości ponad 20ms. Zmiana zmiennych C0 itd. jest "bezpieczna" tylko podczas zerowania licznika głównego. Dlatego stosuje się dodatkowe zmienne, tzw. cienie, które są kopiowane podczas zerowania.

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

Zaloguj się, aby obserwować  

×
×
  • Utwórz nowe...