Skocz do zawartości

Wielozadaniowość w C


Pomocna odpowiedź

18 minut temu, Krawi92 napisał:

że nie mogę już wyjść z funkcji ? 

Alez wychodzisz z tej funkcji tylko ze odrazu do niej wchodzisz...😉 nigdzie nie masz zadnego opoznienia wiec z punktu widzenia (oka) wydaje sie ze caly czas jestes w tej funkcji...a zrob tak i zobacz czy cos sie zmienilo...

case 2:
   PORTD &=~LED1;
   migaj();
   licznik++;
   break;

 

Mój kod nie wykorzystuje przerwań, a zmiana wypełnienia w górę i w dół zachodzi w petlach for. Wiem, że powyżej wysłałeś przykład, jednak ja chciałem zrobić coś po swojemu.

Robisz blad ktory juz robiles w innym watku...chxesz sprawdzac stan zmiennej...nawet nie wiem jak to nazwac...jezeli chcesz cos w kodzie zrobic to musisz to...zrobic...😉

Liczysz ze jak wcisniesz guzik to zmienna licznik w cudowny sposob zmieni swoj stan w czesci kodu ktory sie nie wykonuje...no nie da rady..😁 w tych for() licznik zachowuje sie jak stala...nie wazne ze "gdzies tam" prubujesz ja zmienic...nie uda Ci sie to bo obecnie jestes w.......for😉

Może napiszę jak to sobie wyobraziłem, bo domyślam się że pewnie nawaliłem bzdur w kodzie. Otóż wymyśliłem sobie, że wykorzystam instrukcje switch do przełączania się między czynnościami. Powołałem do tego zmienną licznik, która zwiększa swoją wartość o 1, dzięki czemu po każdym kliknięciu przeskakuje między instrukcjami. No i problem oczywiście powstaje, gdy zmienna = 2, a wykonuje się funkcja migania. I juz kolejna instrukcja z kolei nie chcę się wykonać bo wykonuje się w pętli ciągle miganie. Dlatego wymyśliłem dodatkowe warunki w tych pętlach break, że jesli zmienna licznik będzie miała wartość różną od 2 to ma opuścić pętle. Ale no nie działa. 

(edytowany)
  void migaj () {
		for (uint8_t i=0; i<255;i++){
		OCR1A = i;
		_delay_ms(10);
	if ( !(PINB & KEY)) {
	  return;
      }
	}
	for (uint8_t i=255; i>0;i--){
		OCR1A = i;
		_delay_ms(10);
	if ( !(PINB & KEY)) {
	  return;
      }
    }


	}

Moze sie nie pomylilem...😉

Ps..oczywiscie jak chcesz wyjsc z tej funkcji na twoje rzadanie i przejsc do kolejnego case to musisz inkrementowac ten licznik podczas wcisniecia w for

Edytowano przez farmaceuta
(edytowany)

Ok, dziś na spokojnie usiadłem i skleiłem coś, co działa prawie tak jakbym chciał. Nie ma tu programowo wielozadaniowości, ale fizycznie mogę zmieniać prędkość silnika w trakcie obrotu servem itp. Wkleję kod, jak ja to sobie wymyśliłem.

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

#define SERVO_OFF (1<<PD7) // klawisz stop servo
#define SERVO_ON (1<<PB0) // klawisz start servo
#define PWM_SERVO (1<<PB1) // kanal pwm serva
#define PWM_MOTOR (1<<PB2) // kanal pwm do mostka H
#define WE_A (1<<PD5) // wejscie sterujace
#define WE_B (1<<PD6) // wejscie sterujace
#define DC_START PORTD |= WE_A; PORTD &=~WE_B // start silika
#define DC_STOP PORTD &=~WE_A; PORTD &=~WE_B // stop silnika
#define MOTOR_SLOW (1<<PB3) // niskie obroty
#define MOTOR_MEDIUM (1<<PB4) // srednie obroty
#define MOTOR_HIGH (1<<PB5) // maksymalne obroty
#define STOP (1<<PB7) // zatrzymanie pracy
void servo (); // deklaracja funkcji

uint8_t licznik; // zmienna pomocnicza do petli

int main() {

		DDRD |= WE_A|WE_B; // wyjscie wyjsc sterujacych
		DDRB |= PWM_SERVO|PWM_MOTOR; // wyjscie kanalow pwm

		PORTD |= SERVO_OFF; // podciagniecie klawisza do vcc
		PORTB |= SERVO_ON|MOTOR_SLOW|MOTOR_MEDIUM|MOTOR_HIGH|STOP; // podciagniecie klawiszy do vcc

	/*       INICJALIZACJA PWM */
	TCCR1A |= (1<<WGM10)|(1<<COM1B1)|(1<<COM1A1); // tryb 8 bit i kanaly
	TCCR1B |= (1<<WGM12)|(1<<CS12); // prescaler 256

	    while (1){

  if (!(PINB & MOTOR_SLOW)){
	  OCR1B = 85;
	  DC_START;
  }else if(!(PINB & MOTOR_MEDIUM)){
	  OCR1B = 180;
  }else if(!(PINB & MOTOR_HIGH)){
	  OCR1B = 255;
  }else if(!(PINB & STOP)) {
	  DC_STOP;

  }


  if (!(PINB & SERVO_ON)){ // jesli wcisniety klawisz wlacz servo
	   licznik=1;
	   while(licznik)servo();
  }


}
}
void servo () { // definicja funkcji serva

	for (uint8_t i=0;i<90;i++){
		if (!(PIND & SERVO_OFF)){  // jesli wcisniety klawisz zakoncz dzialanie funkcji
		licznik=0;
		return;
		}
			if (!(PINB & MOTOR_SLOW)){       // Zmiana prędkości motoru w trakcie obrotu serva
			  OCR1B = 85;
			  DC_START;
			}else if(!(PINB & MOTOR_MEDIUM)){
			  OCR1B = 180;
			}else if(!(PINB & MOTOR_HIGH)){
			  OCR1B = 255;
			}else if (!(PINB & STOP)){
			  licznik=0;
			  DC_STOP;
			  return;
			}
			  OCR1A = i;
	  _delay_ms(120);
	 }

	for (uint8_t i=90;i>0;i--)	{
		if (!(PIND & SERVO_OFF)){
		licznik=0;
		return;
		}
			if (!(PINB & MOTOR_SLOW)){
			  OCR1B = 85;
			  DC_START;
		    }else if(!(PINB & MOTOR_MEDIUM)){
			  OCR1B = 180;
		    }else if(!(PINB & MOTOR_HIGH)){
			  OCR1B = 255;
		    }else if (!(PINB & STOP)){
		    	licznik=0;
		    	DC_STOP;
		    	return;
		    }
	OCR1A = i;
	_delay_ms(120);
   	}


}

Jest tu dużo microswitchy, ale na razie nie chciałem się bawić w obsługę kilku instrukcji za pomocą jednego klawisza, ale będę starał się to poprawić. Jednak jest problem, za który nie bardzo wiem, jak się zabrać. Po wcisnieciu klawisza servo_on następuje obrót,raz w jedną raz w drugą. Gdy wciskamy servo_off to servo zatrzymuje się w danej pozycji i to jest OK, tak to ma wyglądać. Jednak gdy znowu wcisnę servo_on servo szybko się skręca do pozycji 0 i zaczyna się pętla od nowa. Nie jest to pożądany dla mnie efekt, ale rozumiem czemu tak się dzieje, bo pętla w funkcji liczy od 0 więc nic dziwnego, że się tak dzieje. Tylko teraz pytanie jak to zrobić, żeby po zatrzymaniu serva, pętla zaczeła liczyć od momentu zatrzymania? Tą wartość trzeba by zapamiętać i podstawić do pętli for. Nie bardzo wiem jak tu zakombinować.

Ps. Przepraszam użytkownika @_LM_ , że wczoraj zacząłem wysyłać jakieś swoje bzdurne kody i odszedłem od tematu, gdy on się napracował i próbował mi na swoich przykładach wytłumaczyć pewne rzeczy 😕 

Edytowano przez Krawi92

Twoja strata. Tyle mogę powiedzieć że jak chcesz dobrze wykorzystać małe mikrokontrolery to od przerwań nie uciekniesz, a opracowanie programu wielozadaniowego, czy tam wielowątkowego zaczyna się od poznania timerów programowych bo niestety w AVR sprzętowych zbyt wielu niema, później dobrze jest ogarnąć wskaźniki na funkcje co nie jest zagadnieniem aż tak trudnym jak go się przedstawia. 

  • Lubię! 1
  • Pomogłeś! 1
46 minut temu, Krawi92 napisał:

Tą wartość trzeba by zapamiętać i podstawić do pętli for. Nie bardzo wiem jak tu zakombinować.

Moze zmienna globalna?😉

48 minut temu, Krawi92 napisał:

Ps. Przepraszam użytkownika @_LM_ 

Za pozno...juz sie obrazil i mowil ze nigdy sie do Ciebie nie odezwie...😉(zarciki...😅)

  • Lubię! 1

Tak, pomyślałem o dodatkowej zmiennej globalnej i potem jakoś w funkcji przypisać jej wartość do zmiennej iteracyjnej. Jutro pokombinuje jak to napisać i czy zadziała jak chce. 

3 minuty temu, Krawi92 napisał:

Tak, pomyślałem o dodatkowej zmiennej globalnej i potem jakoś w funkcji przypisać jej wartość do zmiennej iteracyjnej. 

Nic nie musisz przepisywac...robisz 2 zmienne dla dwoch petli i przypisujesz im odpowiednia wartosc na starcie czyli 0/90...po tych dwoch wykonanych petlach dodajesz jeden warunek ze jesli te zmienne sie "przekrecily" to ustaw startowe wartosci zeby cykl sie powtorzyl...dwie zmienne zapobiegna zlemu dzialaniu serwa w takiej postaci ze gdyby sie juz wykonywala druga petla for to po wyjsciu i ponownym wejsciu serwo bedzie kontynuowac ruch a nie zaczynac od nowa...

10 minut temu, Krawi92 napisał:

Ok, wrócę do Twoich przykładów i postaram się to ogarnąć

To są tylko przykłady tak jak ja podszedłbym do problemu, nie mówię że najlepsze i jedynie słuszne 

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