Skocz do zawartości

[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.

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.

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;}
}
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

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

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.

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

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ć.

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?

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.

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...