Skocz do zawartości

Wielozadaniowość w C


Krawi92

Pomocna odpowiedź

A moze by tak zrobic cos analogicznie do millis()?...ustawiasz sobie timer na przerwanie powiedzmy co 1ms i w tym przerwaniu inkrementujesz tylko jedna zmienna...pozniej w kodzie glownym na samej gorze w ATOMIC BLOCK() przepisujesz sobie ta aktualna zmienna do drugiej zmiennej, bo zapewne beda musialy byc 4-bajtowe jesli bys uzywal dlugich interwalow...a w if'ach to juz standardowo czyli..

if (aktualnyczas - staryczas >= interval)  {
  staryczas = aktualnyczas;
  //twoj kod...
  }

Wtedy odpada ewentualny blad podczas sprawdzania warunku i wystapienia w tym czasie przerwania i zmiany ktoregos bajtu ktory jeszcze nie zostal sprawdzony wlasnie z powodu wystapienia tego przerwania...

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

Dobra jeśli chodzi o podstawowe działanie timerów programowych to myślę, że ogarnąłem o co chodzi. Program migający 2 ledami plus klawisz, który przy PRESS zmienia stan leda.

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

#define LED1 (1<<PB0)
#define LED2 (1<<PB1)
#define LED3 (1<<PD7)
#define KEY (1<<PD6)

volatile uint8_t timer1;
volatile uint8_t timer2;
volatile uint8_t timer3;

uint8_t key_lock; // zmienna pomocnicza do obslugi klawisza

int main () {



	DDRB |= LED1|LED2; // wyjscia LED
	DDRD |= LED3; // wyjscie LED
	PORTD |= KEY; // podciagniecie do vcc klawisza

	TCCR0A |= (1<<WGM01); // CTC Timer8bit
	TCCR0B |= (1<<CS00)|(1<<CS02); // Prescaler 1024
	OCR0A = (F_CPU / 1024UL) / 100UL;	//10ms - 100Hz
	TIMSK0 |= (1<<OCIE0A); // Zezwolenie na przerwanie Compare Match
	sei(); // zezwolenie na globalne przerwania

	while (1){

		if (!timer1) { // jesli timer1 = 0
			PORTB ^= LED1; // zmien stan na przeciwny
			timer1 = 100;
		}

		if (!timer2) {
			PORTB ^= LED2;
			timer2 = 10;
		}

		if (!timer3) {

			if (!key_lock && !(PIND & KEY)) { // jesli klawisz wcisniety
				key_lock = 1; //zapamietaj ten stan
				PORTD ^= LED3; // zmien stan LED3
			}else if (key_lock && (PIND & KEY)) { // jesli klawisz nie jest wcisniety
				key_lock++; // zmienna pomocnicza inkrementuje sie do momentu przekrecenia
							// taka eliminacja efektu drgania styków.					

			}
		}






	}
}
ISR(TIMER0_COMPA_vect){ // procedura obslugi przerwania
	if(timer1) timer1--;
	if(timer2) timer2--;
	if(timer3) timer3--;

}

I o ile wykonywanie jakiś prostych czynności nie sprawia problemu, to teraz próbuje rozwiązać problem, z którym borykałem z UARTem. Powiedzmy dla przykładu, że chcę po naciśnięciu klawisza włączyć funkcje rozjaśniania i ściemniania LED za pomocą PWM. I teraz nie przychodzi mi nic innego do głowy jak zapętlić to czyli w 1 pętli for zwiększać wypełnienie a w drugiej zmniejszać. Problem, że nie mogę już z tej pętli wyjść. I na razie nie wiem jak do tego podejść programowo.

Link do komentarza
Share on other sites

Nie potrzebnie komplikujesz 😉 tutaj:

				key_lock++; // zmienna pomocnicza inkrementuje sie do momentu przekrecenia
							// taka eliminacja efektu drgania styków.

przecież masz te drgania ogarnięte już w momencie kiedy swCount doliczy do wartości kiedy ma się spełnić if.

2) na tej zasadzie bardzo łatwo jest napisać funkcję repeat. Kombinuj 😉

 

11 minut temu, Krawi92 napisał:

Powiedzmy dla przykładu, że chcę po naciśnięciu klawisza włączyć funkcje rozjaśniania i ściemniania LED za pomocą PWM.

jednego? w sensie jedno naciśnięcie i przytrzymanie zwiększamy pwm, kolejne zmniejszamy itd? 

if(dir){
 pwm++ 
}else{
  pwm--
  }

spaghetti 😉

Link do komentarza
Share on other sites

Nie, analogia sprowadza się do tego, że w wiatraku chcę zaprogramować funkcje, żeby gdy wcisnę odpowiedni klawisz, servo zacznie sie obracać powoli w lewo,potem w prawo, tak jak klasyczne wiatrak. Wciśniecie innego klawisza lub tego samego(to w tym momencie bez różnicy) ma wyjść z tej funkcji. Zaraz coś spróbuje napisać i wkleję kod to się wyjaśni, gdzie leży mój problem. 

Link do komentarza
Share on other sites

No dobrze, masz narazie trzy timery programowe. Jednym z nich obsługujesz przycisk, jeśli skompilowałeś mój przykład to powinieneś zauważyć że zaświeca i gasi on diodę, a gdyby tak zamiast diody zapisywać coś do zmiennej która to uruchamiałaby twoje serwo? Szybkość zmian położenia serwa może być regulowana w obsłudze innego timera programowego. Co o tym myślisz? A jeśli serwo ma pracować tylko wtedy gdy klawisz przytrzymany? Zacytuję siebie...

24 minuty temu, _LM_ napisał:

2) na tej zasadzie bardzo łatwo jest napisać funkcję repeat. Kombinuj 😉

Weź popatrz na ten program w taki sposób: nic (umownie) go nie blokuje, zmienne są dostępne cały czas, pętla pędzi na pełnej k... no szybkości, tylko raz na ruski rok wskakuje w obsługę funkcji które są pod if-ami

Edytowano przez _LM_
Link do komentarza
Share on other sites

Wrzucam moją propozycję bo chcę jeszcze coś pokazać, już można zauważyć że zamiast kombinować z wieloma nazwami lepiej użyć tablicy timerów.

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



#define  TMRCOUNT 3 // po co wymyslac nazwy?
volatile uint8_t tmrTab[TMRCOUNT];

uint8_t swCount;
int8_t dir = 1; // kierunek kręcenia 
uint8_t pwm;

int main(void){

	DDRC|= (1<<PC1)|(1<<PC2)|(1<<PC3); // wyjscia
	PORTB|=(1<<PB1); // przycisk


	TCCR0A |= (1 << WGM01);					// tryb CTC
	TCCR0B |= (1 << CS02) | (1 << CS00);	// preskaler = 1024
	OCR0A = (F_CPU / 1024UL) / 100UL;		// 100ms - 100Hz
	TIMSK0 |= (1 << OCIE0A);				// przerwanie Compare Match
		// przerwanie Compare Match

	uint8_t start_pwm = 0;


sei();
	for(;;){

		if(!tmrTab[0]){ // proces 1
			PORTC^= (1<<PC1);
			tmrTab[0] = 200;
		}
		
      if(!tmrTab[1]){ // proces 2
			PORTC^= (1<<PC2);
			tmrTab[1] = 20;

			if(start_pwm){


				// tu warunki dla zmiany kierunku pwm kiedy pwm max lub min  (dir = 1 lub dir = -1)
				pwm+=dir;
			}
	}



		if(!tmrTab[2]){ // proces 3

			if(!(PINB & (1<<PB1)) && swCount < 30){

				if(++swCount == 5){
					PORTC^= (1<<PC3);
				start_pwm^=1; // tog
				}

			}else if(PINB & (1 << PB1))swCount = 0;


			tmrTab[2] = 5;
		}
	}
}



ISR(TIMER0_COMPA_vect){

	for(uint8_t i = 0; i < TMRCOUNT; i++){
		if(tmrTab[i])tmrTab[i]--;
	}
}

 

Link do komentarza
Share on other sites

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


#define LED1 (1<<PD7)
#define LED2 (1<<PD6)
#define KEY (1<<PB0)

uint8_t licznik;
uint8_t key_lock;
int main() {

void migaj ();



	DDRB |= (1<<PB1);
	DDRD |= LED1|LED2;
	PORTB |= KEY;

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

	    while (1){


	    if (!key_lock && !(PINB & KEY)) {
	    	key_lock=1;
	    	licznik++;
	    }else if(key_lock && (PINB & KEY)){
	    	key_lock++;
	    }

	    switch (licznik){

	    case 1 :
	    	PORTD |= LED1;
	    	break;
	    case 2:
	    	PORTD &=~LED1;
	    	migaj();

	    	break;
	    case 3:
	    	PORTD |= LED2;
	    	break;
	    }







	}
}

void migaj () {
		for (uint8_t i=0; i<255;i++){
		OCR1A = i;
		_delay_ms(10);
		if (licznik !=2) break;
	}
	for (uint8_t i=255; i>0;i--){
		OCR1A = i;
		_delay_ms(10);
		if (licznik !=2) break;
	}


	}

Gdzie tu robię błąd w podejściu, że nie mogę już wyjść z funkcji ? 

Link do komentarza
Share on other sites

brakuje sei() przerwania nie są wykonywane, sorki za lakoniczne odpowiedzi ale jeszcze jeden ostatni przykład przygotowuję aaa i gdzie konfiguracja przerwań timera?

EDIT czekej czekej może się rozpędziłem z tymi przerwaniami ale... co to 

if (licznik !=2) break;

niby robi?

Edytowano przez _LM_
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.