Skocz do zawartości

Sterowanie silnikiem z Arduino


pietrasek

Pomocna odpowiedź

Nie do końca. Miałeś napisać dwie osobne funkcje, przypomnę: jedną wczytującą stan wskazanego przycisku i drugą ustawiającą stan jednej z trzech diodek wg otrzymanego stanu przycisku. To nie było od czapy, takie podziały w programie robi się po to, by późniejsze zmiany (lub np. poszukiwanie błędów) ograniczały się do dobrze zdefiniowanych, zamkniętych obszarów/funkcji. Teraz, gdy powinieneś przejść krok dalej i np. diodki zamienić na linie sterowania kierunkiem silników, musisz zmienić wszystko. Gdybyś napisał dwie osobne funkcje, wystarczyłoby zmienić tylko tę  odpowiedzialną za wyjścia. Ta pierwsza byłaby gotowa, sprawdzona i wciąż użyteczna. Pamiętaj, że masz przed sobą większy program, w którym gdzieś w końcu znajdzie się wiele różnych funkcji robiących masę drobnych rzeczy.

EDIT: Acha, i setup() jest za krótki, używasz znacznie wiecej pinów. 

Edytowano przez marek1707
  • Lubię! 1
Link do komentarza
Share on other sites

po zmianie na #define pojawił się błąd error: expected primary-expression before '=' token tylko nie wiem co zrobiłem źle.

#define LED1A = 52;
#define LED1B = 50;
#define LED1C = 48;
#define LED2A = 46;
#define LED2B = 44;
#define LED2C = 42;
#define LED3A = 40;
#define LED3B = 38;
#define LED3C = 36;
#define SW1A = 13;
#define SW1B = 12;
#define SW2A = 11;
#define SW2B = 10;
#define SW3A = 9;
#define SW3B = 8;

void setup() {
  pinMode(LED1A, OUTPUT); //Dioda jako wyjście
  pinMode(LED1B, OUTPUT); //Dioda jako wyjście 
  pinMode(LED1C, OUTPUT); //Dioda jako wyjście
  pinMode(LED2A, OUTPUT); //Dioda jako wyjście
  pinMode(LED2B, OUTPUT); //Dioda jako wyjście 
  pinMode(LED2C, OUTPUT); //Dioda jako wyjście
  pinMode(LED3A, OUTPUT); //Dioda jako wyjście
  pinMode(LED3B, OUTPUT); //Dioda jako wyjście 
  pinMode(LED3C, OUTPUT); //Dioda jako wyjście
  pinMode(SW1A, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(SW1B, INPUT_PULLUP);
  pinMode(SW2A, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(SW2B, INPUT_PULLUP);
  pinMode(SW3A, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(SW3B, INPUT_PULLUP);

  digitalWrite(LED1A, LOW);
  digitalWrite(LED1B, LOW);
  digitalWrite(LED1C, LOW);
}
 
void loop(){
 ledy( LED1A , LED1B , LED1C , SW1A , SW1B );
 ledy( LED2A , LED2B , LED2C , SW2A , SW2B );
 ledy( LED3A , LED3B , LED3C , SW3A , SW3B );
  }

  void ledy(int L1, int L2, int L3, int S1, int S2){
  if (digitalRead(S1) == LOW) {
    digitalWrite(L1, HIGH);
    digitalWrite(L2, LOW);
    digitalWrite(L3, LOW);
  } else 
    
     if (digitalRead(S2) == LOW){
       digitalWrite(L1, LOW);
       digitalWrite(L2, LOW);
       digitalWrite(L3, HIGH);
     } else{
        digitalWrite(L1, LOW);
        digitalWrite(L2, HIGH);
        digitalWrite(L3, LOW);  

 

Link do komentarza
Share on other sites

Philip:

" używaj dyrektywy #define"

Z tym #define to ja bym uważał. Już kilka razy pisałem pietraskowi o:

const int LED1=7;

ale jakoś nie podłapał. Czy nie uważasz, że coś pozwalającego na kontrolę typów to jednak lepszy sposób?

pietrasek:

Warrto czasem sięgnąć do opisu języka żeby nie wyjść na dzieciaka kalkującego rysunek Myszki Miki z książki. W tym akurat przypadku powinieneś zajrzeć do opisu dyrektyw preprocesora, bo #define nie jest prostym zamiennikiem deklaracji zmiennej int. Jest czymś kompletnie, zupełnie innym. Linia powinna wyglądać tak:
#define LED1B 50

Żadnych znaków "=" ani średników. Zostawiam Ci komfort odkrycia dlaczego tak jest i jak to działa, a warto to wiedzieć pisząc dla Arduino.

  • Lubię! 1
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

const int LED1A = 52;
const int LED1B = 50;
const int LED1C = 48;
const int LED2A = 46;
const int LED2B = 44;
const int LED2C = 42;
const int LED3A = 40;
const int LED3B = 38;
const int LED3C = 36;
const int SW1A = 13;
const int SW1B = 12;
const int SW2A = 11;
const int SW2B = 10;
const int SW3A = 9;
const int SW3B = 8;
int sygnal;
void setup() {
  pinMode(LED1A, OUTPUT);
  pinMode(LED1B, OUTPUT);
  pinMode(LED1C, OUTPUT);
  pinMode(LED2A, OUTPUT);
  pinMode(LED2B, OUTPUT);
  pinMode(LED2C, OUTPUT);
  pinMode(LED3A, OUTPUT);
  pinMode(LED3B, OUTPUT);
  pinMode(LED3C, OUTPUT);
  pinMode(SW1A, INPUT_PULLUP);
  pinMode(SW1B, INPUT_PULLUP);
  pinMode(SW2A, INPUT_PULLUP);
  pinMode(SW2B, INPUT_PULLUP);
  pinMode(SW3A, INPUT_PULLUP);
  pinMode(SW3B, INPUT_PULLUP);

  digitalWrite(LED1A, LOW);
  digitalWrite(LED1B, LOW);
  digitalWrite(LED1C, LOW);
}

void loop() {
  wyjs(SW1A , SW1B);
  ledy( LED1A , LED1B , LED1C );
  wyjs( SW2A , SW2B );
  ledy( LED2A , LED2B , LED2C );
  wyjs( SW3A , SW3B ); 
  ledy( LED3A , LED3B , LED3C );
  }

  void wyjs(int S1, int S2){
  if (digitalRead(S1) == LOW) {
   sygnal = 1;
  } else {
     if (digitalRead(S2) == LOW) {
      sygnal = 2;
     } else{
       sygnal = 3;
  }
 }


  void ledy(int L1, int L2, int L3){
  if (sygnal = 1) {
    digitalWrite(L1, HIGH);
    digitalWrite(L2, LOW);
    digitalWrite(L3, LOW);
  }
    
  if (sygnal = 2) {
    digitalWrite(L1, LOW);
    digitalWrite(L2, LOW);
    digitalWrite(L3, HIGH);
     } 
  if (sygnal = 3) {
    digitalWrite(L1, LOW);
    digitalWrite(L2, HIGH);
    digitalWrite(L3, LOW); 
  }
 }
}

podzieliłem końcówkę na 2 części 1 odpowiada za odczytanie stanu przełącznika a 2 za zapalenie diody.

ale pojawiły się takie błędy. Niestety nie wiem skąd się wzięły

In function 'void loop()':

przycisk:41: error: 'ledy' was not declared in this scope

   ledy( LED1A , LED1B , LED1C );

                               ^

In function 'void wyjs(int, int)':

przycisk:60: error: a function-definition is not allowed here before '{' token

   void ledy(int L1, int L2, int L3){

                                    ^

przycisk:76: error: expected '}' at end of input

  }

  ^

 

Link do komentarza
Share on other sites

W pisaniu programów chodzi nie tylko o to by zapisać jakiś algorytm, ale żeby zrobić to tak, by każdy czytający mógł go pojąć w lot. No, a przynajmniej przy minimalnym koniecznym wysiłku. Po to właśnie są języki programowania takie jak C czy Python. Przecież gdy tylko chodziło o sam algorytm, to można używać asemblera lub nawet Turing-zupełnego Brainfucka (nie ja tę nazwę wymyśliłem) - swoją drogą polecam, bo w odróżnieniu od C składnię całego języka można pojąć w 2 minuty. Tutaj, w C (a nawet C++) masz ogromną szansę zapisywania swoich wysiłków na wiele sposobów, ale niewiele z nich jest naprawdę jasnych dla czytających. Twój ostatni program będzie pewnie działał - nie sprawdzałem pod tym względem, nie mam czasu, przepraszam, ale rzuciła mi się w oczy jedna ważna rzecz. Wyobraź sobie, że za pół roku Ty sam otwierasz plik źródłowy i w celu zorientowania się co napopisałeś oglądasz główną pętlę. A tam masz 6 wywołań funkcji: trzy wyjs() i trzy ledy(). Zachęcony domyślasz się, że wyjs() to pewnie jakieś operacje na wyjściach(?) a ledy() to pewnie coś z diodkami. Przypominasz sobie na szczęście, że jednak wyjs() to paradoksalnie wczytywanie stanu przycisków i przypływie dobrego nastroju postanawiasz pogrupować te funkcje tak, by operacje czytania były na początku - niech wykonują się w tym samym czasie. Przestawiasz kilka linii i masz coś takiego: 

  wyjs(SW1A , SW1B);
  wyjs( SW2A , SW2B );
  wyjs( SW3A , SW3B ); 

  ledy( LED1A , LED1B , LED1C );
  ledy( LED2A , LED2B , LED2C );
  ledy( LED3A , LED3B , LED3C );

Oczywiście od razu okazuje się, że program przestaje działać. Co jest źle? Okazuje się, że Twoje fukcje wyjs() są dziwne, bo faktycznie wczytują coś z przycisków, ale robią z tym potem jakąś magię - wynik podziewa się gdzieś w czeluściach programu. Mówimy, że mają efekty uboczne:

https://pl.wikipedia.org/wiki/Skutek_uboczny_(informatyka)

Co gorsza z tego efektu korzystają funkcje ustawiania wyjść. Na pierwszy rzut oka (zanim zajrzysz do ich kodu) nie rozumiesz na jakiej podstawie tymi wyjściami manipulują. Przecież widać, że dostają tylko numery wyjść więc skąd wiedzą, co mają zrobić? No i zaczyna się drążenie w treściach funkcji. To jest złe.

Nie wiem czy rzuciło Ci się w oczy, że funkcje mogą oddawać pewne wartości. Tak jak sin(x) oddaje wartość funkcji sinus dla przekazanego jej kąta wyrażonego w radianach, tak wczytaj_switch() może oddać stan przycisku temu kto ją wywołał. Gdybyś napisał (te funkcje) tak, by interakcje między nimi były oczywiste już na poziomie najwyższym, od razu byś wiedział (i każdy kto zajrzy do Twojego kodu) co się dzieje - przynajmniej na poziomie algorytmu:

  stan_switcha1 = wczytaj_switch(SW1A , SW1B);
  stan_switcha2 = wczytaj_switch(SW2A , SW2B);
  stan_switcha3 = wczytaj_switch(SW3A , SW3B);

  ledy( stan_switcha1, LED1A , LED1B , LED1C );
  ledy( stan_switcha2, LED2A , LED2B , LED2C );
  ledy( stan_switcha3, LED3A , LED3B , LED3C );

albo nawet - jeśli nie potrzebujesz już nigdzie indziej stanu przełączników - prościej:

  ledy( wczytaj_switch(SW1A , SW1B), LED1A , LED1B , LED1C );
  ledy( wczytaj_switch(SW2A , SW2B), LED2A , LED2B , LED2C );
  ledy( wczytaj_switch(SW3A , SW3B), LED3A , LED3B , LED3C );

W tym albo w poprzednim przykładzie każdy widzi, że masz funkcję coś robiącą z ledami, która wciąga stan przełącznika i dostaje wskazanie na trzy diodki. Nie powinna ona chcieć niczego więcej do działania. Staraj się nie używać dziwnych dróg obchodzących typowe przekazywanie parametrów do funkcji i wyciąganie z nich wyników - to jest mechanizm dwukierunkowy i bardzo sprawnie pokazuje "interfejs" do rzeczy dziejących się pod spodem. Dopiero teraz - gdy już widać jak funkcje współpracują ze sobą - można zajrzeć do ich kodu, ale tylko w celu poznania konkretów działania a nie odkrywania magii "w jaki sposób ona wie co ma robić?".

Kolejna rzecz: w funkcji ledy() masz trzy sprawdzenia wielkości wykluczających się i każde z nich robisz za każdym razem a co gorsza if-y sugerują, że trzeba przejrzeć każdy warunek, bo może któryś kod wykonywany jest w kilku przypadkach. Nie od razu widać, że tu masz 1, tu 2 a tu 3. Do obsługi takich sytuacji masz elegancką konstrukcję switch(), której samo użycie sugeruje osobne przypadki:

switch(sygnal) {
  case 1:
    digitalWrite(L1, HIGH);
    digitalWrite(L2, LOW);
    digitalWrite(L3, LOW);
    break;
  case 2:
    digitalWrite(L1, LOW);
    digitalWrite(L2, LOW);
    digitalWrite(L3, HIGH);
    break;
  case 3:
    digitalWrite(L1, LOW);
    digitalWrite(L2, HIGH);
    digitalWrite(L3, LOW);
    break;
  default:
    digitalWrite(L1, LOW);
    digitalWrite(L2, LOW);
    digitalWrite(L3, LOW);
    break; }

Pomijam już fakt, że Twoje if-y nie zadziałają (a jednak), bo nie tak wygląda operator porównania..

No dobra, chyba potrzebujemy kolejnej wersji kodu. Brawa za const int - kiedyś uchroni Cię to przed poważnymi kłopotami.

BTW: Już chyba jest jasne, że w zasadzie nie masz pojęcia o pisaniu programów i problemem podstawowym wcale nie jest obsługa tych paru silniczków. No ale robisz postępy. Mam nadzieję, że za jakiś czas napisanie ładnego, jasnego i dobrze działającego kodu nie będzie dla Ciebie trudne. Zawsze czytaj go po napisaniu tak, jakbyś widział go pierwszy raz w życiu. Jeśli coś wtedy jest nieoczywiste i wymaga posiadania jakiejś wiedzy dodatkowej niewidocznej na ekranie, będzie tym bardziej trudne lub tajemnicze dla innej osoby lub dla Ciebie samego za rok. A przecież nie chcesz tego, prawda?

Edytowano przez marek1707
Literówki, literówki..
  • Lubię! 2
Link do komentarza
Share on other sites

const int LED1A = 52;
const int LED1B = 50;
const int LED1C = 48;
const int LED2A = 46;
const int LED2B = 44;
const int LED2C = 42;
const int LED3A = 40;
const int LED3B = 38;
const int LED3C = 36;
const int SW1A = 13;
const int SW1B = 12;
const int SW2A = 11;
const int SW2B = 10;
const int SW3A = 9;
const int SW3B = 8;
int sygnal;
int stan_switcha1;
int stan_switcha2;
int stan_switcha3;
void setup() {
  pinMode(LED1A, OUTPUT); //Dioda jako wyjście
  pinMode(LED1B, OUTPUT); //Dioda jako wyjście 
  pinMode(LED1C, OUTPUT); //Dioda jako wyjście
  pinMode(LED2A, OUTPUT); //Dioda jako wyjście
  pinMode(LED2B, OUTPUT); //Dioda jako wyjście 
  pinMode(LED2C, OUTPUT); //Dioda jako wyjście
  pinMode(LED3A, OUTPUT); //Dioda jako wyjście
  pinMode(LED3B, OUTPUT); //Dioda jako wyjście 
  pinMode(LED3C, OUTPUT); //Dioda jako wyjście
  pinMode(SW1A, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(SW1B, INPUT_PULLUP);
  pinMode(SW2A, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(SW2B, INPUT_PULLUP);
  pinMode(SW3A, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(SW3B, INPUT_PULLUP);

  digitalWrite(LED1A, LOW);
  digitalWrite(LED1B, LOW);
  digitalWrite(LED1C, LOW);
}

void loop() {
  stan_switcha1 = wczytaj_switch(SW1A , SW1B);
  stan_switcha2 = wczytaj_switch(SW2A , SW2B);
  stan_switcha3 = wczytaj_switch(SW3A , SW3B);

  ledy( stan_switcha1, LED1A , LED1B , LED1C );
  ledy( stan_switcha2, LED2A , LED2B , LED2C );
  ledy( stan_switcha3, LED3A , LED3B , LED3C );
  }

  void wczytaj_switch(int S1, int S2){
  if (digitalRead(S1) == LOW) {
   sygnal = 1;
  } else {
     if (digitalRead(S2) == LOW) {
      sygnal = 2;
     } else{
       sygnal = 3;
  }
 }
}

  void ledy(int sygnal, int L1, int L2, int L3){
switch(sygnal) {
  case 1:
    digitalWrite(L1, HIGH);
    digitalWrite(L2, LOW);
    digitalWrite(L3, LOW);
    break;
  case 2:
    digitalWrite(L1, LOW);
    digitalWrite(L2, LOW);
    digitalWrite(L3, HIGH);
    break;
  case 3:
    digitalWrite(L1, LOW);
    digitalWrite(L2, HIGH);
    digitalWrite(L3, LOW);
    break;
  default:
    digitalWrite(L1, LOW);
    digitalWrite(L2, LOW);
    digitalWrite(L3, LOW);
    break; }
   }

wersja prawie następna  tylko że znowu mam problem (za każdym razem jak mam problem najpierw staram się znaleźć odp. w internecie)

przycisk:43: error: void value not ignored as it ought to be

   stan_switcha1 = wczytaj_switch(SW1A , SW1B);

                 ^

przycisk:44: error: void value not ignored as it ought to be

   stan_switcha2 = wczytaj_switch(SW2A , SW2B);

                 ^

przycisk:45: error: void value not ignored as it ought to be

   stan_switcha3 = wczytaj_switch(SW3A , SW3B);

                 ^

 

Link do komentarza
Share on other sites

Żeby skorzystać z wartości oddawanej przez funkcję:

stan_switcha1 = wczytaj_switch(SW1A , SW1B);

musisz tak tę funkcję napisać, by tę wartość oddawała. To samo się nie zrobi. Słowo void przed nazwą funkcji w jej nagłówku oznacza właśnie, że niczego nie oddajesz. Ono tam nie jest tak sobie. I nie pisz proszę tych banałów o szukaniu i nieznajdowaniu w sieci, bo to dziecinne. Wystarczyło znaleźć stronę o języku C i wszystko masz w jednym miejscu:

https://pl.wikibooks.org/wiki/C

Przecież to pierwszy lub drugi wynik wyszukiwarki na pytanie "język C". Czytasz podstronę pt. "Funkcje" i zaczynasz kumać. Nie wspominając już o tym, że przywoływany już tu artukuł z naszego kursu:

https://forbot.pl/blog/kurs-arduino-czujnik-odleglosci-hc-sr04-funkcje-id4290

mówi właśnie o przekazywaniu parametrów do funkcji i o tworzeniu funkcji mających/oddających wartość. Jeśli potrzebujesz wskazania palcem, to rozdział "Funkcje zwracające wynik". Zajrzałeś tam w ogóle czy marnowałeś czas pytaniami "jak napisać funkcję wczytywania stanu przycisku"?

Kompilator w swoim komunikacie próbuje Ci powiedzieć, że chcesz skorzystać (w instrukcji podstawienia czyli tej ze znakiem "=") z wartości której funkcja nie oddaje bo jest typu void. Skup się, jesteś całkiem blisko. Zmień wczytaj_switch() tak by nie chowała wyniku swojej pracy do zmiennej globalnej (bleee, tego nie lubimy) tylko oddawała go przez return. Czy chciałbyś, by w Twoim samochodzie każdorazowe naciśnięcie sprzęgła powodowało (oprócz wysprzęglenia silnika) załączenie spryskiwacza tylnej szyby? Nie? No widzisz, czyli tamci konstruktorzy jakoś to opanowali. Twoje funckje także mają robić tylko to czego od nich wymagamy. Nie powinny grzebać w jakichś dziwnych zmiennych dostępnych dla wszystkich, które każdy może nadpisać i umieścić w nich cokolwiek (szczególnie gdy zmienna nazywa się sygnal).

  • Lubię! 1
Link do komentarza
Share on other sites

const int LED1A = 52;
const int LED1B = 50;
const int LED1C = 48;
const int LED2A = 46;
const int LED2B = 44;
const int LED2C = 42;
const int LED3A = 40;
const int LED3B = 38;
const int LED3C = 36;
const int SW1A = 13;
const int SW1B = 12;
const int SW2A = 11;
const int SW2B = 10;
const int SW3A = 9;
const int SW3B = 8;
int stan_switcha1;
int stan_switcha2;
int stan_switcha3;
void setup() {
  pinMode(LED1A, OUTPUT); //Dioda jako wyjście
  pinMode(LED1B, OUTPUT); //Dioda jako wyjście 
  pinMode(LED1C, OUTPUT); //Dioda jako wyjście
  pinMode(LED2A, OUTPUT); //Dioda jako wyjście
  pinMode(LED2B, OUTPUT); //Dioda jako wyjście 
  pinMode(LED2C, OUTPUT); //Dioda jako wyjście
  pinMode(LED3A, OUTPUT); //Dioda jako wyjście
  pinMode(LED3B, OUTPUT); //Dioda jako wyjście 
  pinMode(LED3C, OUTPUT); //Dioda jako wyjście
  pinMode(SW1A, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(SW1B, INPUT_PULLUP);
  pinMode(SW2A, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(SW2B, INPUT_PULLUP);
  pinMode(SW3A, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(SW3B, INPUT_PULLUP);

  digitalWrite(LED1A, LOW);
  digitalWrite(LED1B, LOW);
  digitalWrite(LED1C, LOW);
}

void loop() {
  stan_switcha1 = wczytaj_switch(SW1A , SW1B);
  stan_switcha2 = wczytaj_switch(SW2A , SW2B);
  stan_switcha3 = wczytaj_switch(SW3A , SW3B);

  ledy( stan_switcha1, LED1A , LED1B , LED1C );
  ledy( stan_switcha2, LED2A , LED2B , LED2C );
  ledy( stan_switcha3, LED3A , LED3B , LED3C );
  }

  int wczytaj_switch(int S1, int S2){              // void na int
  if (digitalRead(S1) == LOW) {
   return 1;                                      // zmienna na return
  } else {
     if (digitalRead(S2) == LOW) {
      return 2;
     } else{
       return 3;
  }
 }
}

  void ledy(int sygnal, int L1, int L2, int L3){
switch(sygnal) {
  case 1:
    digitalWrite(L1, HIGH);
    digitalWrite(L2, LOW);
    digitalWrite(L3, LOW);
    break;
  case 2:
    digitalWrite(L1, LOW);
    digitalWrite(L2, LOW);
    digitalWrite(L3, HIGH);
    break;
  case 3:
    digitalWrite(L1, LOW);
    digitalWrite(L2, HIGH);
    digitalWrite(L3, LOW);
    break;
  default:
    digitalWrite(L1, LOW);
    digitalWrite(L2, LOW);
    digitalWrite(L3, LOW);
    break; }
   }

działa. wydaje mi się że można nazwać to wersją 2.0

7 godzin temu, marek1707 napisał:

mówi właśnie o przekazywaniu parametrów do funkcji i o tworzeniu funkcji mających/oddających wartość. Jeśli potrzebujesz wskazania palcem, to rozdział "Funkcje zwracające wynik". Zajrzałeś tam w ogóle czy marnowałeś czas pytaniami "jak napisać funkcję wczytywania stanu przycisku"?

czytałem

Link do komentarza
Share on other sites

OK, brawo, doszedleś niniejszym do bardzo ogólnego schematu programu, który na podstawie stanu trzech kompletów wejść równolegle obsługuje trzy kanały wyjściowe. Przyznam, że jestem miło zaskoczony Twoimi postępami, bo z dnia na dzień kod był coraz lepszy. Mam nadzieję, że Ty też umiesz docenić przejrzystość osiągniętą dzięki podziałowi na funkcje. Dzięki takiej strukturze będzie można teraz w miarę płynnie rozszerzać ten kod o kolejne mechanizmy.

Zacznijmy od potencjometru. Dopisz funkcję czytającą jego położenie i oddającą je w postaci jakiejś liczby. Wymyśl czy ma to być np. 0 do 100 czy jakiś inny zakres. Przy okazji mam wątpliwość co do pewnej funkcjonalności urządzenia. Otóż mając jeden potencjometr jesteś skazany na jedną wspólną prędkość wszystkich silników, ale dysponując trzema przełącznikami możesz niezależnie decydować o kierunkach. Czy to oznacza, że silniki niesterowane akurat pilotem będą poruszały się z tymi samymi PWMami, ale w różne strony? Nie wiem co to będzie za sprzęt więc nie oceniam czy to dobrze czy źle, ale np. nie możesz w takiej konfiguracji zatrzymać dowolnego "ręcznie", z gałki. A może po prostu napisz co będziesz tym sterował, wszystkim będzie prościej wyobrażać sobie następstwa pewnych działań procesora.

Oddane przez funkcję położenie potencjometru zachowuj w zmiennej globalnej bo jest to jeden z ważnych stanów programu. Wywołanie funkcji dopisz do pętli głównej, dzięki czemu w każdym "obrocie" pętli będziesz dysponował kompletem danych: wychyleniem potencjometru i stanem trzech przełączników.

Możesz  też, idąc za ciosem, zmodyfikować funkcję wyjściową tak by zamiast załączania jednej z trzech diodek LED wystawiała stany na dwie linie sterowania kierunkiem silnika. Oczywiście to wymaga przedefiniowania wielu pinów wyjściowych, ale i tak trzeba to kiedyś zrobić a będzie to już prawie docelowa konfiguracja linii I/O. Niech linie sterowania mostkami na razie bazują tylko na otrzymanym przez funkcję stanie odpowiedniego przełącznika.

  • Lubię! 1
  • Pomogłeś! 1
Link do komentarza
Share on other sites

 

1 godzinę temu, marek1707 napisał:

OK, brawo, doszedleś niniejszym do bardzo ogólnego schematu programu, który na podstawie stanu trzech kompletów wejść równolegle obsługuje trzy kanały wyjściowe. Przyznam, że jestem miło zaskoczony Twoimi postępami, bo z dnia na dzień kod był coraz lepszy. Mam nadzieję, że Ty też umiesz docenić przejrzystość osiągniętą dzięki podziałowi na funkcje. Dzięki takiej strukturze będzie można teraz w miarę płynnie rozszerzać ten kod o kolejne mechanizmy.

Bardzo jestem wdzięczny za pomoc. Program jest dużo bardziej przejrzysty , zauważyłem że trochę mniej pamięci zajmuje

1 godzinę temu, marek1707 napisał:

Zacznijmy od potencjometru. Dopisz funkcję czytającą jego położenie i oddającą je w postaci jakiejś liczby. Wymyśl czy ma to być np. 0 do 100 czy jakiś inny zakres. Przy okazji mam wątpliwość co do pewnej funkcjonalności urządzenia. Otóż mając jeden potencjometr jesteś skazany na jedną wspólną prędkość wszystkich silników, ale dysponując trzema przełącznikami możesz niezależnie decydować o kierunkach. Czy to oznacza, że silniki niesterowane akurat pilotem będą poruszały się z tymi samymi PWMami, ale w różne strony? Nie wiem co to będzie za sprzęt więc nie oceniam czy to dobrze czy źle, ale np. nie możesz w takiej konfiguracji zatrzymać dowolnego "ręcznie", z gałki. A może po prostu napisz co będziesz tym sterował, wszystkim będzie prościej wyobrażać sobie następstwa pewnych działań procesora.

Tak ogólnie to buduję makietę kolejową i są 3 sekcje torów . Mają być 3 potencjometry po 1 do każdej sekcji

w pozycji środkowej przełącznika ma przejść na sterowanie za pomocą pilota

 

Link do komentarza
Share on other sites

No jasne, ale ze mnie d. wołowa, przecież pisałeś o makietach. Ale te silniki to chyba nie w lokomotywach, prawda? Albo na osobnych, izolowanych od siebie torach. To bardziej jakieś karuzele na makiecie czy coś? Bo jeśli w ruchu to może powinieneś pójść w DCC?

Acha, czyli 3 potencjometry. Jakoś zrozumiałem, że jeden wspólny. No dobra, to trzy piny analogowe, trzy gałki, jedna funkcja oddająca wartość wskazanego potencjometru i trzy zmienne globalne przechowujące odczyty. Do roboty.

BTW: Czy wymyśliłeś już sposób sterowania tymi silnikami przez podczerwień? Jaki to pilot? Masz już upatrzony? Bo trzeba a) znać protokół przesyłania kodów - a jest kilka różnych, b) obmyślić sposób wybierania  silnika i regulacji jego prędkości. Może to być np. wciśnięcie jednego z 10 przycisków cyfrowych - wtedy masz tylko(?) 10 różnych prędkości ale za to szybkie reakcje, mogą to być przyciski "w górę/w dół" po troszeczku zmieniające prędkość (plus ew. jakiś awaryjny STOP) itp. Jeśli masz to jakoś przemyślane, napisz, bo to wszystko już za niedługo będzie musiał odbierać, interpretować i wykonywać Twój program.

  • Lubię! 2
Link do komentarza
Share on other sites

(edytowany)
3 godziny temu, marek1707 napisał:

No jasne, ale ze mnie d. wołowa, przecież pisałeś o makietach. Ale te silniki to chyba nie w lokomotywach, prawda? Albo na osobnych, izolowanych od siebie torach. To bardziej jakieś karuzele na makiecie czy coś? Bo jeśli w ruchu to może powinieneś pójść w DCC?

akurat na razie do lokomotyw. wiem o DCC (myślę o tym na przyszłość). aktualnie buduję makietę w analogu i wymyśliłem sobie że zrobię cały pulpit sterowniczy niestety  chińskie regulatory napięcia się popaliły.  w poszukiwaniu regulatorów natknąłem się na sterownik silników do arduino i postanowiłem zbudować na arduino.  oczywiście tory są od siebie odizolowane

3 godziny temu, marek1707 napisał:

BTW: Czy wymyśliłeś już sposób sterowania tymi silnikami przez podczerwień? Jaki to pilot? Masz już upatrzony? Bo trzeba a) znać protokół przesyłania kodów - a jest kilka różnych, b) obmyślić sposób wybierania  silnika i regulacji jego prędkości. Może to być np. wciśnięcie jednego z 10 przycisków cyfrowych - wtedy masz tylko(?) 10 różnych prędkości ale za to szybkie reakcje, mogą to być przyciski "w górę/w dół" po troszeczku zmieniające prędkość (plus ew. jakiś awaryjny STOP) itp. Jeśli masz to jakoś przemyślane, napisz, bo to wszystko już za niedługo będzie musiał odbierać, interpretować i wykonywać Twój program.

pilota mam kody do przycisków też mam

#include <IRremote.h>
#define irPin 11
IRrecv irrecv(irPin);
decode_results results;
 
int jasnosc = 0;

void setup() {
   Serial.begin(9600);
   irrecv.enableIRIn();
}
 
void loop() {
   if (irrecv.decode(&results)) {
      
      switch (results.value) {
        case 0xE318261B:
            Serial.println("CHM");
            break;
 
         case 0x511DBB:
            Serial.println("CH")
            break;
 
         case 0xEE886D7F:
            Serial.println("CHP");
            break;
 
         case 0x52A3D41F:
            Serial.println("PREV");
            break;
 
         case 0xD7E84B1B:
            Serial.println("NEXT");
            break;
            
         case 0x20FE4DBB:
            Serial.println("PP");
            break;
 
         case 0xF076C13B:
            Serial.println("VOLM");
            break;
 
         case 0xA3C8EDDB:
            Serial.println("VOLP");
            break;
 
         case 0xE5CFBD7F:
            Serial.println("EQ");
            break;
 
         case 0xFF6897:
            Serial.println("0");
            break;
         
         case 0x97483BFB:
            Serial.println("100");
            break;
 
         case 0xF0C41643:
            Serial.println("200");
            break;
 
         case 0x9716BE3F:
            Serial.println("1");
            break;
 
         case 0x3D9AE3F7:
            Serial.println("2");
            break;
 
         case 0x6182021B:
            Serial.println("3");
            break;

         case 0x8C22657B:
            Serial.println("4");
            break;
 
         case 0x488F3CBB:
            Serial.println("5");
            break;
 
         case 0x449E79F:
            Serial.println("6");
            break;
                     
         case 0x32C6FDF7:
            Serial.println("7");
            break;
 
         case 0x1BC0157B:
            Serial.println("8");
            break;

         case 0x3EC3FC1B:
            Serial.println("9");
            break;
         }
   irrecv.resume();
   }
}

itd.thumb.png.b6cbd9e0ec5337a863a889b7ea7bb948.png

zapomniałem jeszcze że zdecydowałem się na arduino bo brakowało mi spowolnienia w ruszaniu i zatrzymywaniu.

sterowanie silnikami😆

const int m1A = 38;
const int m1B = 40;
const int pwm1 = 0;
const int m2A = 42;
const int m2B = 44;
const int pwm2 = 1;
const int m3A = 46;
const int m3B = 48;
const int pwm3 = 2;
const int SW1A = 13;
const int SW1B = 12;
const int SW2A = 11;
const int SW2B = 10;
const int SW3A = 9;
const int SW3B = 8;
const int ang1 = 0;
const int ang2 = 1;
const int ang3 = 2;
int stan_switcha1;
int stan_switcha2;
int stan_switcha3;
int po1;
int po2;
int po3;

void setup() {
  pinMode(m1A, OUTPUT); //Dioda jako wyjście
  pinMode(m1B, OUTPUT); //Dioda jako wyjście 
  pinMode(pwm1, OUTPUT); //Dioda jako wyjście
  pinMode(m2A, OUTPUT); //Dioda jako wyjście
  pinMode(m2B, OUTPUT); //Dioda jako wyjście 
  pinMode(pwm2, OUTPUT); //Dioda jako wyjście
  pinMode(m3A, OUTPUT); //Dioda jako wyjście
  pinMode(m3B, OUTPUT); //Dioda jako wyjście 
  pinMode(pwm3, OUTPUT); //Dioda jako wyjście
  pinMode(SW1A, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(SW1B, INPUT_PULLUP);
  pinMode(SW2A, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(SW2B, INPUT_PULLUP);
  pinMode(SW3A, INPUT_PULLUP); //Przycisk jako wejście
  pinMode(SW3B, INPUT_PULLUP);
}

void loop() {
   po1 = analogRead(ang1);
   po2 = analogRead(ang2);
   po3 = analogRead(ang3);
   
  stan_switcha1 = wczytaj_switch(SW1A , SW1B);
  stan_switcha2 = wczytaj_switch(SW2A , SW2B);
  stan_switcha3 = wczytaj_switch(SW3A , SW3B);

  ledy( stan_switcha1, m1A , m1B , pwm1, po1 );
  ledy( stan_switcha2, m2A , m2B , pwm2, po2 );
  ledy( stan_switcha3, m3A , m3B , pwm3, po3 );
  }

  int wczytaj_switch(int S1, int S2){
  if (digitalRead(S1) == LOW) {
   return 1;
  } else {
     if (digitalRead(S2) == LOW) {
      return 2;
     } else{
       return 3;
  }
 }
}

  void ledy(int sygnal, int M1, int M2, int Mpwm, int pot){

switch(sygnal) {
  case 1:
    digitalWrite(M1, HIGH);
    digitalWrite(M2, LOW);
    analogWrite(Mpwm, map(pot, 0, 1023, 0, 255));
    break;
  case 2:
    digitalWrite(M1, LOW);
    digitalWrite(M2, LOW);
    analogWrite(Mpwm, 0);
    break;
  case 3:
    digitalWrite(M1, LOW);
    digitalWrite(M2, HIGH);
    analogWrite(Mpwm, map(pot, 0, 1023, 0, 255));
    break;
  default:
    digitalWrite(M1, LOW);
    digitalWrite(M2, LOW);
    analogWrite(Mpwm, 0);
    break; }
   }
Edytowano przez pietrasek
Link do komentarza
Share on other sites

Dobrze. Czy programy które tu wrzucasz jakoś weryfikujesz na sprzęcie? Bo wiesz, możemy gapić się na program przez cały dzień (ja tego nie robię), gadać o jakichś wycudowanych rzeczach a mogą tam siedzieć babole zupełnie podstawowe. Warto więc to kompilować, ładować do Arduino i sprawdzać funkcjonalnie. Masz jakiś model tego sprzętu? Te wszystkie przełączniki, mostki, silniki itd? Bo jeśli nie, to już czas by to zbudować.

A teraz o programie. Do tej pory Twój kod "nie widział" czasu. Była jakaś pętla której czas wykonania nie miał znaczenia, obracała się w kółko i tak jak mogła najszybciej (najczęściej?) wykonywała sekwencję czytania tego i owego, sterowała wyjściami itd. Gdy zaczynasz mówić o opóźnieniach czy szybkości zmian pewnych sygnałów (tutaj: wysterowania silników) musisz zacząć zauważać upływający czas. Mikrokontrolery mają wiele mechanizmów to wspomagających - począwszy od sprzętowych timerów, poprzez moduły zegarów RTC na systemie przerwań kończąc. Twój program wygląda na prosty - nawet w swojej ostatecznej formie może nadal wyglądać jak prosta pętla więc na razie spróbujemy zabazować na zwykłym opóźnieniu. To nie jest w ogólności polecany mechanizm, bo zamula procesor i w przypadku dużych opóźnień robionych funkcją delay() zamienia skomplikowane CPU w cegłę. Można tu z pewnością dyskutować jak to zrobić najładniej, bo w Arduino są np. biblioteki do okresowego wołania funkcji czy obsługi timerów bez wnikania w szczegóły sprzętu, ale moim zdaniem nie jesteś jeszcze gotowy na problemy synchronizacji, zmienne współużywane i takie tam. W miarę rozwoju będziesz miał (nomen omen) czas na zgłębianie tych zagadnień. Zatem moja rada: pętla wykonywana (w przybliżeniu) co stały odcinek czasu. Makieta kolejowa to nie apteka i nawet jeśli metoda wprowadzenia stałego opóźnienia nie zapewnia rzeczywście stałej częstotliwości wywoływania funkcji, wydaje się że tu wystarczy. Wstawiasz zatem na końcu pętli loop() wywołanie delay(50). Ponieważ cała reszta rzeczy wykonywanych w pętli jest szybka, dodadzą one niewiele własnego opóźnienia do postulowanych 50ms i z dobrym przybliżeniem możesz uznać, że od tej pory jeden przebieg pętli głównej w Twoim programie wykonuje się 20 razy na sekundę. Wstaw to i sprawdź, czy widzisz istotną różnicę w działaniu swojego dotychczasowego programu.

A teraz druga ważna rzecz: skoro silniki mają być sterowane "miękko", z powolnym narastaniem czy opadaniem prędkości musisz zerwać ich bezpośrednie połączenie z potencjometrami. Powinieneś wprowadzić do programu kolejny poziom przetwarzania sygnałów, bo do tej pory miałeś tylko jeden: odczyt z potencjometru był zarazem prędkością silnika.

1. Na pierwszym poziomie będziesz teraz wczytywać sygnał z potencjometru - od tej pory jest to wartość.. hm, tylko pożądana (docelowa). Musisz ją pamiętać np. w zmiennej pot_target_speed z odpowiednim numerkiem kanału. Acha, przy okazji: staraj się nie wiązać wielkości przetwarzanych w programie z ich sprzętowymi cachami. Wczytujesz wysterowanie z potencjometru i akurat w przypadku tego procesora masz 10-bitowy ADC więc dostajesz liczby 0..1023. Nie powinieneś jednak tego przekazywać dalej, bo za chwilę cały program będzie posługiwał się takim dziwnym zakresem, któyry wynika tylko i wyłącznie z cechy tego konkretnego ADC. Spróbuj mapować już w funkcji odczytującej potencjometr wartość wyjściową tak, by była w zakresie np. 0..100. W lokomotywie nie potrzebujesz większej precyzji niż 1% więc strata dokładności nie zaboli, a od tej pory masz fajny zakres liczb. Zauważ też, ze za chwilę będziesz odbierał dane z pilota a tam w ogóle nie ma odniesienia do ADC, jego 10-bitowości i zakresu 1024 wartości. Ukrywając więc potencjometr i ADC przed resztą kodu dość wcześnie uwalniasz się od sprzętu i masz komfort pracy z arbitralnie dobranym zakresem, tutaj: prędkości.

2. Na kolejnym poziomie będziesz miał prędkość aktualną silnika czyli to możesz pokazywać na wyświetlaczu w lokomotywie 🙂 Musisz zatem dopisać funkcję (np. get_motor_speed()) , która będzie otrzymywać prędkość "docelową" a oddawać prędkość "aktualną" - także w zakresie 0..100, która podąża w kierunku tej docelowej z pewną, ograniczoną szybkością zmian. Poradzisz sobie? Pomyśl jak chcesz wykonać to "dopędzanie" prędkości zadanej, bo od tego będzie zależała ch-ka przyspieszenia lokomotywy. Dwa najczęstsze przypadki to nadążanie ze stałą prędkością zmian (czyli za każdym razem dodajesz/odejmujesz tyle samo do/od prędkości aktualnej - tak przyspiesza masa ciągnięta stałą siłą) lub nadążanie z prędkością zależną do różnicy obu prędkości (czyli dodajesz/odejmujesz tym więcej im jesteś dalej od docelowej - tak ładuje się kondensator lub stygnie piekarnik).

Na razie mamy tylko prędkość dodatnią, ale w połączeniu ze zmianami kierunku przełączników zacznie być ciekawie, prawda? Acha, no i oczywiście funkcja ustawiająca fizyczny PWM będzie teraz dostawać prędkość aktualną 0..100 więc powinna już we własnym zakresie mapować (znów ukrywamy sprzęt/timer jak najgłębiej) tę wielkość na wysterowanie 0.255 wyjścia PWM.

  • Lubię! 2
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.