Skocz do zawartości

Wielozadaniowość w C


Pomocna odpowiedź

Pokombinowałem trochę ze zmiennymi, żeby zapamiętać po wyjściu stan OCR1A, servo po zatrzymaniu i ponownym uruchomieniu wznawia ruch od miejsca zatrzymania, jednak działa to tylko w jedną stronę. Wszystko jest dla mnie zrozumiałe dlaczego, ponieważ funkcja rozpoczyna się od zwiększania wartości, dlatego obojętnie w którym miejscu wyjdę z funkcji, jej ponownie wywołanie spowoduje zwiększanie się wypełnienia. Ja główkowałem jak to zrobić, aby po wyjściu z funkcji w momencie zmniejszania się wypełnienia, gdy servo obraca sie w lewo, po ponownym jej wywołaniu kontynuować ten ruch w lewo, czyli jakby funkcja musiała się zacząć od środka(Wiem, namieszałem i sam widzę że to głupio brzmi) Dlatego zastanawiam się, czy w tak napisanym programie, w takiej formie jestem w stanie to zrobić.

Link to post
Share on other sites

Nie musisz kopiować stanu OCR gdyż nie zmienia się on samoczynnie, stan OCR można traktować jako zmienną statyczną więc po wejściu do funkcji możesz jeśli trzeba skopiować do zmiennej lokalnej. Z resztą te zmienne pwm również nie są Ci potrzebne, w taki sam sposób możesz działać na rejestrze OCR czyli OCR1A++ i OCR1A--

Link to post
Share on other sites
14 minut temu, Krawi92 napisał:

jednak działa to tylko w jedną strone

Bo...

 

23 godziny temu, farmaceuta napisał:

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

A Ty stosujesz jedna wspolna dla obu for tak?

Link to post
Share on other sites

Za chwilkę wrzucę kod bo jeszcze pracuje nad włączeniem serva tylko w trakcie obrotu silnika itp.. Ale tak, stosuje jedną ponieważ ta druga nie miała sensu, ponieważ funkcja i tak zaczynała od zwiększania. Kombinowałem na początku z dwiema zmiennymi, ale wtedy zaburzony był ruch w lewą stronę. 

Link to post
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

#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 while
uint8_t zmienna1; // zmienna pomocnicza do petli for
uint8_t motor_on; // potwierdzenie wlaczenia silnika

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){
 motor_on=OCR1B; // przypisanie do zmiennej wartosci OCR1B

  if (!(PINB & MOTOR_SLOW)){          // wolne obroty
	  OCR1B = 85;
	  DC_START;
  }else if(!(PINB & MOTOR_MEDIUM)){  // srednie obroty
	  OCR1B = 180;
  }else if(!(PINB & MOTOR_HIGH)){  // szybkie obroty
	  OCR1B = 255;
  }else if(!(PINB & STOP)) {  // zatrzymanie silnika
	  DC_STOP;

  }


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


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

	for (uint8_t i=zmienna1;i<90;i++){

		if (!(PIND & SERVO_OFF)){  // jesli wcisniety klawisz zakoncz dzialanie funkcji
		zmienna1=OCR1A; 
		licznik=0;
		motor_on=0;
		break;
		}
			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;
			  zmienna1=OCR1A;
			  OCR1B=0;
			  DC_STOP;
			  break;
			}
			  OCR1A = i;
			  if (OCR1A < 90) zmienna1=0;
	  _delay_ms(120);
	 }

	for (uint8_t i=90;i>0;i--)	{
		if (!(PIND & SERVO_OFF)){
		zmienna1=OCR1A;
		licznik=0;
		motor_on=0;
		break;
		}
			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;
		    	zmienna1=OCR1A;
		    	OCR1B=0;
		    	DC_STOP;
		    	break;
		    }
	OCR1A = i;

	_delay_ms(120);
   	}
}

 

Link to post
Share on other sites

f

byte lewo = 0
byte prawo = 90
  
for(lewo; lewo<90 lewo++) {
  }
for(prawo; prawo>0 prawo--) {
  }
if (lewo == 90 && prawo == 0) {
  lewo = 0
  prawo = 90
 }

 

Link to post
Share on other sites
6 minut temu, Krawi92 napisał:

 stosuje jedną ponieważ ta druga nie miała sensu, ponieważ funkcja i tak zaczynała od zwiększania.

To nie ma znaczenia z ktorej strony zaczynasz...masz podzielic tak zeby przed ukonczeniem jednego for nie dalo rady wlezdz do drugiego...i dla tego dwie zmienne maja sens...😉

Link to post
Share on other sites
31 minut temu, _LM_ napisał:

Nie musisz kopiować stanu OCR gdyż nie zmienia się on samoczynnie, stan OCR można traktować jako zmienną statyczną więc po wejściu do funkcji możesz jeśli trzeba skopiować do zmiennej lokalnej. Z resztą te zmienne pwm również nie są Ci potrzebne, w taki sam sposób możesz działać na rejestrze OCR czyli OCR1A++ i OCR1A--

Troszkę mnie teraz olśniło. Czyli zamiast zwiększać i zmniejszać wypełnienie w 2 pętlach for mogę to zrobić na timerach programowych i po prostu OCR1A++/-- 

Link to post
Share on other sites
(edytowany)

tak, musisz jedynie pamiętać aby nie przekroczyć zakresu bo zacznie od zera 

 

Edytowano przez _LM_
Link to post
Share on other sites
(edytowany)

No więc posłuchałem i trochę się douczyłem, postanowiłem na nowo napisać "sterownik" do wiatraka. Założenia jak poprzednio, sterowanie silnikiem DC(3 tryby szybkosci) sterowanie servem, obsluga 3 przycisków wlaczajaca silnik,servo, i wylaczajaca wszystko. Teraz użyłem już tylko 3 przycisków wykorzystując zwaną dumnie szumnie maszynę stanów. Rozbiłem projekt na 3 pliki, wykorzystałem strukturę i pola bitowe w ramach testu, jak to działa. Teraz wszystko działa tak jak chciałem. Wrzucam kod, żeby ktoś ocenił, lub nawet dla porównania z poprzednim. Chętnie wysłucham uwag co tu mogłem zrobić lepiej, co spaproszyłem itp. Będę miał jeszcze kilka pytań ogólnych ale to potem. Gdyby coś w kodzie było niejasne to napisze, czemu cos tak rozwiązałem.

main.c

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "pwm.h"
 
uint8_t stan,stan1; // zmienna pomocnicza do petli switch
 
int main () {
        // inicjalizacja pwm i timerow //
        pwmInit();
        timerInit();
        wiatrak.pwm1 = 51; // pozycja srodkowa serva
 
        _delay_ms(1); // Opoznienie,by ustabilizowac stan wysoki na pinie wejsciowym
 
        sei(); // zezwolenie na globalne przerwania
while(1) {
 
        if (!wiatrak.keylock1 && !(PINB & (1<<MOTOR_ON))){ // obsluga przyciski motor_on
        wiatrak.keylock1=1;
        stan1++;
            if (stan1>3)stan1=1;
    }else if (wiatrak.keylock1 && (PINB & (1<<MOTOR_ON)))wiatrak.keylock1++;
 
        if (stan1 && !wiatrak.keylock && !(PINB & (1<<SERVO_ONOFF))){ // obsluga przycisku servo_onoff
                wiatrak.keylock=1;
                stan++;
                if(stan>2)stan=1;
        }else if (wiatrak.keylock && (PINB & (1<<SERVO_ONOFF)))wiatrak.keylock++;
 
        if (!wiatrak.keylock2 && !(PINB & (1<<MOTOR_OFF))){  // obsluga przycisku motor_off
                wiatrak.keylock2=1;
                stan1=0;
                stan=2;
        }else if (wiatrak.keylock2 && (PINB & (1<<MOTOR_OFF)))wiatrak.keylock2++;
 
        switch (stan){ // Stany serva
                case 1:
                 servo_on();
                 break;
                case 2:
                 
                 break;
                }
        switch (stan1){ // stany motoru
                case 1:
             wiatrak.pwm2=85;
                 DC_START;
             break;
                case 2:
                 wiatrak.pwm2=170;
                 break;
                case 3:
                 wiatrak.pwm2=255;
             break;
                default:
                 DC_STOP;
           }
 }
}

pwm.c

#include <avr/io.h>
#include <avr/interrupt.h>
#include "pwm.h"
 
volatile uint8_t timer1,timer2; // timery programowe
 
void pwmInit(){
        PORTB |= (1<<SERVO_ONOFF)|(1<<MOTOR_ON)|(1<<MOTOR_OFF); // pullup start/stop servo
        DDRD |= (1<<PD6)|(1<<PD7)|(1<<WE_A)|(1<<WE_B); // wyjscia pwm i sterowanie silnika
        TCCR0A |= (1<<WGM01); // tryb ctc timer0
        TCCR0B |= (1<<CS00); // prescaler 1
        TIMSK0 |= (1<<OCIE0A); // zezwlenie na przerwanie
        OCR0A = 200;
}
void timerInit(){
        TCCR1A |= (1<<WGM12); // ctc timer1
        TCCR1B |= (1<<CS10);// prescaler 1
        TIMSK1 |= (1<<OCIE1A); //zezwolenie na przerwanie
        OCR1A = 100;
}
 
void servo_on(){
        if(!timer1){
                if(!wiatrak.kierunek){ // jesli kierunek 0
                        wiatrak.pwm1++; // obracaj
                        if(wiatrak.pwm1 == 99)wiatrak.kierunek = 1; // jesli pwm99 zmien kierunek
                }else{
                        if(wiatrak.kierunek){ // jesli kierunek wiekszy od 0
                        wiatrak.pwm1--; // obracaj
                        if(wiatrak.pwm1 == 18)wiatrak.kierunek = 0; // jesli pwm18 zmien kierunek
                        }
                }
                timer1 = 10; // predkosc obracania
        }
}
 
ISR(TIMER0_COMPA_vect){ // Programowe PWMy
        static uint8_t cnt;
 
if (cnt>=wiatrak.pwm1) channel1_off else channel1_on
if (cnt>=wiatrak.pwm2) channel2_off else channel2_on
 
cnt++;
}
 
ISR(TIMER1_COMPA_vect){ // Timery programowe
if(timer1)timer1--;
if(timer2)timer2--;
}

pwm.h

#ifndef PWM_H_
#define PWM_H_
 
#define channel1_on PORTD |= (1<<PD6);   // kanaly pwm
#define channel1_off PORTD &=~(1<<PD6);
#define channel2_on PORTD |= (1<<PD7);
#define channel2_off PORTD &=~(1<<PD7);
 
#define SERVO_ONOFF PB0 // klawisz wlacz/wylacz servo
#define MOTOR_ON PB1 // klawisz wlacz motor
#define MOTOR_OFF PB2 // klawisz wylacz motor
#define WE_A PD3 // pin sterujace motorem
#define WE_B PD4 // pin sterujacy motorem
 
#define DC_START PORTD |= (1<<WE_A); PORTD &=~(1<<WE_B) // wlacz silnik
#define DC_STOP PORTD &=~(1<<WE_A); PORTD &=~(1<<WE_B) // wylacz silnik
 
 
// deklaracje funkcji
 
void servo_on();
void pwmInit();
void timerInit();
 
struct { // Testowa struktura
        volatile uint8_t pwm1; // kanaly pwm
        volatile uint8_t pwm2;
        uint8_t kierunek:1; // kierunek obrotu serva
        uint8_t keylock; // zmienne do obslugi klawiszy
        uint8_t keylock1;
        uint8_t keylock2;
}wiatrak;
 
 
#endif /* PWM_H_ */

 

Edytowano przez Krawi92
  • Lubię! 2
Link to post
Share on other sites

Macra pisz z duzych liter, a tam kilka masz z malych i sie moze mylic ze zmiennymi itp...i takie pytanie, dlaczego uzyles dwoch timerow? Jak bys uruchomil fast pwm to moglbys uruchomic dwa przerwania i jedno zajmowalo by sie pwm a drugie cyklicznie czasem...to tak tylko na marginesie😉

Link to post
Share on other sites

No racja w sumie. Gdybym się uparł to mógłbym napędzać pwmy i timery w jednym przerwaniu, częstotliwosc by się ustawiło. Generalnie chciałem tu spróbować kilku nowych rzeczy które poznałem, wiele rzeczy można by było zrobić prościej. 

Link to post
Share on other sites
18 minut temu, Krawi92 napisał:

No racja w sumie. Gdybym się uparł to mógłbym napędzać pwmy i timery w jednym przerwaniu

Nie nie...mozna ustawic dwa przerwania...jedno od przepelnienia (ktore jest stale/cykliczne) i drugie od porownania w ktorym przelaczasz piny od pwm...wtedy masz regolarne odstepy czasu bez znaczenia na to jakie aktualnie jest twoje wypelnienie pwm...(na marginesie😉)

Link to post
Share on other sites

Ja tak się zastanawiam... mówicie o wielozadaniowości w C, czy może o zmuszeniu atmegi do wykonywania kolejno wykonywania jakiejś funkcji kiedy akurat przyjdzie ba nią czas?

C czy C++ nie wie nic o wielozadaniowości (czyli równoległym wykonywaniu niezależnych procesów) czy wielowątkowości (czyli w miarę równoległym wykonywaniu fragmmentów tego samego programu). Jedyny znany mi język który wspierał wielowątkowość to był Algol69 - a o ile wiem nie powstał nigdy pełny kompilator tego języka.

Biblioteki typu Timers pozwalają na wykonanie jakiejś funkcji kiedy przyjdzie na nią czas. Problemem jest to, że bardzo dobrze działają na atmegach - i tylko na atmegach.

W Linuxach masz pthread lub fork.

W Windows nie ma forka (mechanizm COW chyba jest za skomplikowany), ale multithreading działa.

Na mikrokontrolerach z wyższej półki masz FreeRTOS.

Na Atmegach... może zostawmy atmegi do zadań typu "miganie diodą"? A do wielowątkowości weźmy jakiegoś STM-a czyESP?

Owszem, zaimplementowanie wielowątkowości na atmedze ma swoje plusy. Ale trzeba pamiętać, że rozwiązania typu Timers będą działać na tych historycznych procesorkach.

Tak, widziałem całkiem udane próby zaimplementowania tego na ESP32. Tylko po co - jeśli freeRTOS pozwala na prawdziwą wielowątkowość?

  • Lubię! 1
Link to post
Share on other sites
24 minuty temu, ethanak napisał:

Na Atmegach... może zostawmy atmegi do zadań typu "miganie diodą"?

O przepraszam...na atmedze uruchomilem naraz 5 diod!...ledwo juz dychala, iskry sie sypaly, ale dzialalo...i to o dziwo z roznymi interwalami migaly...😉

A tak na serio to nie kazdy da rade odrazu ogarnac te STM'y i inne ESP bo to juz chyba wyzsza szkola jazdy, a bidula atmega w miare prosta do ogarniecia zwlaszcza dla zaczynajacych, a i na niej cos mozna wyskrobac...

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

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