Skocz do zawartości

[c][atmega128]problem z przerwaniem


sobal44

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.

Link do komentarza
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.

Link do komentarza
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;}
}
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

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

Link do komentarza
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

Link do komentarza
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.

Link do komentarza
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ć.

Link do komentarza
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?

Link do komentarza
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.

Link do komentarza
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.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.