gotowiec 4 - obsługa wątków = koniec z uciążliwym delay !

Zbiór tutoriali związanych z Arduino.
ODPOWIEDZ
Awatar użytkownika
wojtekizk
Starszy majsterkowicz
Posty: 309
Rejestracja: 19 lis 2013, 10:54
Lokalizacja: Bydgoszcz

gotowiec 4 - obsługa wątków = koniec z uciążliwym delay !

Post autor: wojtekizk » 16 mar 2014, 22:23

Witam
Dzisiejszy temat ma wiele wspólnego z flustracją jaka często nas dopada, kiedy chcemy poszerzyć nasz programik o obsługę kolejnej fajnej funkcji i nagle okazuje się, że to nie jest takie proste :-)

Dotąd pisaliśmy programiki gdzie procesor wykonywał w pętli loop() kolejne instrukcje krok po kroku... w niekończącej się pętli (neverending story). Jak chcieliśmy nagle przerwać jakieś działanie to uciekaliśmy się do przerwań (zewnętrznych lub timera).
Co się wtedy dzieje? - procesor zapamietuje stan rejestrów, wykonuje skok do funkcji obsługi przerwania i następnie wraca do miejsca gdzie przerwał naszej pętli loop() działanie.
OK... ale jeśli byliśmy właśnie na przykład w pętli delay(5000) i po 300 ms. wywołaliśmy przerwanie, to po powrocie procesor i tak wykona swoje delay(4700) które pozostało... a tego na przykład nie chcemy.
Problem polega na tym, że nasz procek wykonuje program sekwencyjnie, czyli krok po kroku...
Natomiast nasz Windows, Linux czy Android (to także Linux) swoje programy opiera o tzw. obsługę wątków.
W dużym uproszczeniu system "nasłuchuje" co się dzieje z urządzeniami zarejestrowanymi w systemie i w zależności od tego co się wydarzy podejmuje określone działanie. Jeśli ruszysz myszą... system już wie że to zrobiłeś, gdzie jest myszka... Jeśli klikniesz myszką na ikonkę, system wie co to za ikonka i jakim klawiszem kliknąłeś :-)
To oczywiście duże uproszczenie, zwłaszcza dla API Windows.
W każdym razie system w określonych odstępach czasu (im szybszy procek, tym cześciej) odpytuje wszystkie zarejestrowane składniki i rejestruje zdarzenie, które z kolei potrafi obsłużyć.

W tym tutorialu postaram się przybliżyć nieco to zagadnienie i przedstawić przykład zastosowania tej właśnie techniki w naszych programach. To nie jest wcale takie trudne a jest alternatywą dla obsługi przerwań na przykład.
Nasz kolega v-cu boryka sie jakiś czas z problemem efektywnego połączenia dwóch niezależnych dotąd programów... w jeden... i muszę przyznać, że za długo już trwała nasza wymiana "korespondencji".
Postanowiłem podejść do tego problemu z innej strony - napisać program oparty o obsługę zdarzeń właśnie.
Celem nadrzędnym było zachowanie pełnej funkcjonalności BEZ UŻYCIA w funkcji loop() chociażby jednej funkcji delay()!!!
Nasz kolega projektuje urządzenie - wytrawiarkę płytek drukowanych - czyli połączenie stopera, termostatu i mieszalnika w jedno. Każde z tych urządzeń ma mieć niezależne sterowanie, czyli jeśli np. silnik wykonuje ruch w jedną stronę, to funkcja delay nie może spowalniać stopera i jednocześnie jeśli będę chciał zmienić np . temperaturę zadaną to nie powinienem czekać w kolejce wykonywanych czynności w drzewku loop-a...
To zadanie można zrealizować za pomocą obsługi przerwań ( zewnętrzne lub timera)... ale jeśli za chwilę zapragnę jeszcze niezależnie zmieniać prędkość zmian kierunku ruchu silnika, to co? Kolejne przerwanie?

Proponuję tu zapoznać się z biblioteką Timers (moim zdaniem najlepszą i najprostszą z trzech podobnych - Timer, TimerOne i TimerTree). Ona pozwoli nam na zastosowanie techniki programowania opartej na obsłudze wątków.

Nie chcę tutaj powielać opisu... więc aby nie zanudzać więcej przedstawiam przykładowy kod z obszernym wstępnym komentarzem, który mam nadzieję wyjaśni większość ew. wątpliwości:

Komentarz:
-------------
Przykładowa implemantacja programu opartego na obsłudze zdarzeń. Namiastka aplikacji będąca alternatywą dla programowania sekwencyjnego, krok, po kroku. Ten program nasłuchuje w określonych odstępach czasu informacji o stanie użytych w nim podzespołów (czujników, buttonów, silników itp.) i w zależności od stanu ich samych podejmuje określone działania.
Dzięki takiemu podejściu możliwa jest całkowita eliminacja uciążliwej funkcji delay(). Nie trzeba bowiem czekać aż wykona się czynność ograniczona funkcją delay. Jest to równiez alternatywa dla obsługi przerwań. Przykładowo jeśli uruchomiono silnik na czas 2 sekund, to bez obsługi przerwań (zewnętrznych lub timera) nie było prostego sposobu na wykonanie innego zadania w trakcie ruchu silnika.

Ten program korzysta z biblioteki Timers, która moim zdaniem jest chyba najłatwiejsza do zastosowań i moze być powszechnie używana przez wielu majsterkowiczów i czytelników naszego forum.
Zamieszczony przykład jest softem do projektu "automatycznej wytrawiarki", czyli termostatu z mieszalnikiem.

Projekt umożliwia:
- ustawienie zadanej temperatury procesu wytrawiania płytek drukowanych (tu w zakresie 10-80 st.C)
- automatyczne nadzorowanie grzałki ( włącz - wyłacz) - funkcja termostatu
- dynamiczne, niezależne załączanie lub wyłączanie mieszalnika - funkcja mieszania roztworu metodą wibracyjną
(szybka zmiana kierunku obrotu silnika)
- dynamiczną, niezależną zmianę czasu ruchu silnika w mieszalniku - regulacja czasu ruchu silnika.
- kontrolę czasu trwania procesu - funkcja stopera (tutaj max 60 minut)

To wszystko relizowane jest za pomocą 3 przycisków: UP, DOWN i OK.

Zatem program realizuje kilka jednoczesnych procesów: odlicza czas, mierzy aktualną temperaturę, załącza/wyłącza grzałkę, steruje ruchem mieszalnika i szybkością zmian kierunku obrotów oraz w czasie rzeczywistym umożliwia zmianę parametrów:temperatury zadaniej i prędkości mieszalnika bez opóźnień i wpływu na wykonywanie innych zadań. Niezbędną dotąd funkcję delay i przerwania w programie zastąpiono obsługą osobnych wątków w określonych odstępach czasu.

Program jest przykładem zastosowania biblioteki Timers.

OPIS BIBILOTEKI (skrócony):
----------------------------
Czym biblioteka Timers różni się od biblioteki Timer, TimerOne czy TimerTree?
Przede wszystkim prostotą użycia jej w programie. Zasadniczo korzystamy z 4 wygodnych funkcji składowych klasy Timers:

1) Konstruktor - inicjalizacja obiektu klasy Timers.
Przykład:
Timers <8> akcja; - Powołujemy do życia obiekt klasy Timers o przykładowej nazwie akcja, który może obsłużyć
8 niezależnych wątków (zdarzeń)

2) Funkcja attach(nr wątku, interfał wywołania, funkcja obsługi), gdzie:
- numer wątku, to numer jednego z 8 wcześniej zdefiniowanych w konstruktorze wątków;
- interfał - odstęp czasu w ms. W tych odsępach będzie wywoływana funkcja obsługi
- funkcja obsługi - nazwa funkcji, jak ma być wykonywana.
W tym zakresie funkcja attach jest łudząco podobna do funkcji attachInterrupt.
Przykłady:
akcja.attach(2,5000,pokazTemp); - co 5 sekund wątek 3 (liczymy od 0) wywołuje funkcję pokazTemp()
akcja.attach(0, 1000, pokazCzas); - co 1 sekundę wątek pierwszy wywołuje funkcję pokazCzas()
akcja.attach(1,0,flopKierunek); - definiujemy wątek nr 2, ale nie mamy na razie zamiaru z niego korzystać - interfał =0

UWAGA!!!
Funkca attach musi być zainicjowana w funkcji setup() dla każdego z wątków.
Jeśli nie mamy zamiaru od razu korzystać z danego wątku, to w funkcji attach ustawiamy interfał na 0

3) Funkcja updateInterval(nr wątku, akt interfał), gdzie:
- nr wątku, to numer jednego z 8 wcześniej zdefiniowanych w konstruktorze wątków;
- akt interfał - dynamiczna zmiana czasu wywoływania funkcji, w szczególnym przypadku dla interfał=0 wyłączamy
obsługę wątku.
Przykłady:
akcja.updateInterval(2,0); - zatrzymanie obsługi wątku nr 3
akcja.updateInterval(4,189); - zmiana lub ustawienie dla wątku nr 5 czasu wywoływania funkcji obsługi na 189 ms.

4) funkcja process() - wywoływana w pętli loop, uruchamia globalną obsługę wszystkich zadeklarowanych
w konstruktorze wątków
Przykład:
akcja.process();

W programie sterowanie silnikiem jest realizowane za pomocą 2 pinów cyfrowych, w oparciu o zasadę:
pin A - LOW, pin B - LOW - STOP silnika
pin A - HIGH, pin B - LOW - ruch w lewo
pin A - LOW, pin B - HIGH - ruch w prawo
Zdaję sobie sprawę, że akurat takie sterowanie wymaga specjalnego zabezpieczenia mostka H, który przy dużych
prądach silnika jest niestety wymagany.
Dla celów testowych zamiast silnika do płytki podłączono 2 diody LED połączone równolegle
(przeciwstawnie A-K przez rezystor 220 OHm). Dzięki temu będą zapalały się na przemian symulując pracę silnika.

Ponadto w funkcji pokazTemp() użyto czujnika temperatury podpietego do wejścia A1.
Jeśli posiadasz inny czujnik należy zmodyfikować jego obsługę i wzór przeliczający jednostki
oraz dodać ew. bibliotekę obsługi czujnika.

OBSŁUGA PROGRAMU:
--------------------
Obrazek
Po załączeniu zasilania widzimy ekran powitalny gdzie na wstępie ustawiono zadaną temperaturę roztworu na 40 st.C
Klawiszami DOWN - UP możemy modyfikować tą temperaturę ze skokiem 1 st. C
Klawisz OK zatwierdza zmiany i zostaje uruchomiony proces wytrawiamia (start stopera, start mieszalnika, nagrzewanie)
Co 1 sek. pokazywana jest zmiana czasu, co 5 sekund aktualizowana jest temperatura roztworu,
a ruch silnika w jedną stronę trwa 0,6 sek. (wstępnie zadeklarowana zmienna cz=600)
Klawiszem OK możemy teraz zatrzymać mieszalnik. Ponowne naciśnięcie OK uruchamia nasz mieszalnik.
Naciśnięcie klawisza DOWN lub UP podczas pracy mieszalnika umożliwia zmianę czasu pracy silnika ze skokiem 50 ms.
Naciśnięcie klawisza DOWN lub UP podczas postoju mieszalnika umożliwia zmianę zadanej temperatury ze skokiem 1 st.C

SPIS UZYTYCH PINÓW, płytka Arduino UNO R3:
-----------------------------------
8,9,4,5,6,7 - LCD
0 - klawisz DOWN
1 - klawisz UP
2 - klawisz OK
13 - przekaźnik grzałki
11,12 - piny silnika (do podłączenia mostka H)
A1 - czujnik temperatury

3,10 - wolne piny
-----------------------------------
A oto przykładowy kod wytrawiarki: (...by wojtekizk wk@warcaby.lh.pl)
#include <LiquidCrystal.h> // dołączona biblioteka LiquidCrystal
#include <Timers.h> // dołączona biblioteka Timers (konieczna do poprawnej pracy ... jest w załączniku)
Timers <8> akcja; // na poczatek 8 niezależnych wątków (procesów, zadań, procedur, akcji itp.)
LiquidCrystal lcd(8,9,4,5,6,7); // definiujemy LCD
#define UP 1                     // klawisz UP na pinie 1
#define DOWN 0                   // klawisz DOWN na pinie 0
#define OK 2                     // klawisz OK na pinie 2
#define przekaznik 13            // przekaźnik na pinie 13
#define motor1Pin 12             // motor1Pin na pin 12
#define motor2Pin 11             // motorPin2 na pin 11
volatile boolean kier=false; // kierunek ruchu mieszalnika
volatile boolean startT=false; // start mieszalnika
long czas=0; // czas od chwili startu
long s=0; // chwila startu
int minuty=0, sekundy=0; // chyba jasne :-)
int ustaw=40; // zadana temperatura początkowa
volatile int cz=600; // zadany poczatkowy czas ruchu mieszalnika
// --- funkcje dla ruchu mieszalnika -----------------------------------
void r0(){digitalWrite(motor1Pin,LOW); digitalWrite(motor2Pin,LOW); } // zatrzymanie mieszalnika
void rP(){digitalWrite(motor1Pin,LOW); digitalWrite(motor2Pin,HIGH);} // ruch mieszalnika w lewo
void rT(){digitalWrite(motor1Pin,HIGH);digitalWrite(motor2Pin,LOW); } // ruch mieszalnika w prawo
// --- funkcja ustawienia zadanej temperatury --------------------------
void setTemp() // tylko w tej jedynej funkcji użyłem delay, i tylko dlatego aby zapobiec drganiom styków
                     // oraz aby spowolnić szybkość zwiększania lub zmniejszania wymaganej temperatury.
                     // Ta funkcja jest uruchamiana w setupie zanim w loopie uruchomię obsługę zdarzeń :-)
{
  while(digitalRead(OK)!=LOW) // dopóty nie wcisniemy klawisza OK, ustawiamy wymaganą temperaturę roztworu
  {
    // poniżej inkrementacja (zwiększanie) lub dekremantacja (zmniejszanie) wymaganej temperatury w procesie
    if(digitalRead(UP)==LOW){delay(30);if(digitalRead(UP)==LOW) {ustaw++;if(ustaw>80)ustaw=80;lcd.setCursor(12,1); lcd.print(ustaw);}}
    if(digitalRead(DOWN)==LOW){delay(30);if(digitalRead(DOWN)==LOW) {ustaw--;if(ustaw<10)ustaw=10;lcd.setCursor(12,1); lcd.print(ustaw);}}
    delay(80); // raczej konieczne dla mojego refleksu :-), owo spowolnienie...
  }
  startT=true; // zezwolenie na start mieszalnika
  lcd.clear();lcd.setCursor(0,0);lcd.print("TIME TEMP MOTOR"); // kosmetyka LCD, pierwsza linia
  pokazCzas();pokazTemp(); // a w drugiej linii pokazuję stoper i akt. temperaturę
}  
// --- reakcja na wciśnięty przycisk OK  w pętli loop -------------------
void buttonOK()
{
if(digitalRead(OK)==LOW){startT=!startT;akcja.updateInterval(2,5000);}
// naprzemienne wyłacza lub załącza mieszalnik oraz uruchamia proces pokazywania akt. temperatury
}
// --- reakcja na wciśniety przycisk DOWM w pętli loop ------------------
void buttonDOWN()
{
if(digitalRead(DOWN)==LOW)
  {
  if(startT==true){cz-=50;if(cz<50)cz=50;} // dynamicznie zmniejsza czas ruchu mieszalnika w krokach co 50 ms.
  else
    {
     akcja.updateInterval(2,0); // zatrzymuje proces pokazywania akt. temperatury
     ustaw--;if(ustaw<10)ustaw=10; // dynamicznie zmniejsza wymaganą temperaturę w krokach co 1 st.
     lcd.setCursor(6,1);lcd.print(" ");lcd.setCursor(6,1);lcd.print(ustaw);lcd.print(" C"); // kosmetyka LCD
    } 
  }
}
// --- reakcja na wciśnięty przycisk UP w pętli loop --------------------
void buttonUP()
{
if(digitalRead(UP)==LOW)
  {
  if(startT==true){cz+=50;if(cz>3000)cz=3000;}// dynamicznie zwiększa czas ruchu mieszalnika w krokach co 50 ms.
  else
    {
      akcja.updateInterval(2,0); // zatrzymuje proces pokazywania akt. temperatury
      ustaw++;if(ustaw>80)ustaw=80; // dynamicznie zmniejsza wymaganą temperaturę w krokach co 1 st.
      lcd.setCursor(6,1);lcd.print(" ");lcd.setCursor(6,1);lcd.print(ustaw);lcd.print(" C"); // kosmetyka LCD
    }
  }
}
// --- zmiana kierunku ruchu mieszalnika + kosmetyka LCD ----------------
void flopKierunek()
{
  kier=!kier;r0();lcd.setCursor(11,1);lcd.print(" OFF "); // zatrzymanie mieszalnika
  if(kier==true){rP();lcd.setCursor(11,1);lcd.print(" -->");} // ruch do przodu + kosmetyka LCD
  else {rT();lcd.setCursor(11,1);lcd.print(" <--");} // ruch do tyłu + kosmetyka LCD
}
// --- pokaz czasu pracy ------------------------------------------------
void pokazCzas()
{
  char buf[20]; memset(buf,0,sizeof(buf)); // zamiast pozycjonowania LCD proponuję to właśnie
  czas=(millis()-s)/1000; // czas w sekundach
  minuty=czas/60;sekundy=czas%60;          // obliczamy mniuty i sekundy
  if(minuty>59){minuty=0;sekundy=0;} // po przekroczeniu 60 minut liczymy od nowa
  snprintf(buf,sizeof(buf),"%02d:%02d",minuty,sekundy); // sprytna funkcja (radzę poczytać o niej :-)
  lcd.setCursor(0,1);lcd.print(buf); // kosmetyka LCD
}
// ---  pokaz aktualnej temperatury --------------------------------------
void pokazTemp()
{
  int sensorValue = analogRead(A1); // czujnik temperatury na pin A1
  float temp = sensorValue * 0.48828125;
  //float temp = sensorValue * (5.0 * 100.0/1023.0); // przeliczamy (wzór zalezy od czujnika)
  lcd.setCursor(6,1);lcd.print(" ");lcd.setCursor(6,1);lcd.print((int)temp);lcd.print(" C"); // kosmetyka LCD
  if(temp < ustaw) { digitalWrite(przekaznik,HIGH);lcd.setCursor(5,0);lcd.print("*");} // właczamy grzałkę i gwiazdkę na LCD
  if(temp > ustaw+1){ digitalWrite(przekaznik,LOW); lcd.setCursor(5,0);lcd.print(" ");} // lub nie (histgereza 1 st.C)
}
// --- ekran powitalny ---------------------------------------------------
void kosmetykaLCD()
{
lcd.clear();lcd.setCursor(0,0);lcd.print("<Czarodziej PCB>");
lcd.setCursor(0,1);lcd.print("Temp.roztw.=");lcd.print(ustaw);lcd.print(" C");
}
// ------------------------------------------------------------------------
void setup()
{
  pinMode(motor1Pin,OUTPUT);digitalWrite(motor1Pin,LOW); // stop motor
  pinMode(motor2Pin,OUTPUT);digitalWrite(motor2Pin,LOW); // stop motor
  pinMode(UP,INPUT_PULLUP); // klawisz UP
  pinMode(DOWN,INPUT_PULLUP); // klawisz DOWN
  pinMode(OK,INPUT_PULLUP); // klawisz OK
  lcd.begin(16,2); kosmetykaLCD(); // powitanie :-)
  setTemp();                        // na początku ustawiam wymaganą temperaturę
  s=millis(); // sędzia odpalił na start :-), utrwalamy tę chwilę w zmiennej s
  // Teraz najważniejsze :-)
  akcja.attach(0, 1000, pokazCzas); // Wątek 1: pokazuje czas co 1 sekundę
  akcja.attach(1,0,flopKierunek); // Wątek 2: ruch mieszalnika, 0 oznacza, że na razie zatrzymany ten proces
  akcja.attach(2,5000,pokazTemp); // Wątek 3: pokazuje temperaturę co 5 sek.
  akcja.attach(3,200,buttonOK); // Wątek 4: sprawdza stan klawisza OK dla START-STOP mieszalnika, co np. 200 ms.
  akcja.attach(4,189,buttonDOWN); // Wątek 5: sprawdza stan klawisza DOWN co np. 189 ms.
  akcja.attach(5,211,buttonUP); // Watek 6: sprawdza stan klawisza UP co np. 211 ms.
  // i tu mała uwaga... aby uniknąć sytuacji jednoczesnego uruchamiania kilku wątków dobrze jest używać liczb pierwszych
  // jako drugiego parametru funkcji attach :-) Nie jest to jednak krytyczne.
}
// -------------------------------------------------------------------------
void loop()
{
akcja.process(); // inicjalizacja lub aktualizacja wszystkich procedur(wątków, zdarzeń itp.)
if(startT==true){akcja.updateInterval(1,cz);} // a teraz uruchomiłem ruch mieszalnika ze zmianą co cz [ms]
else {r0();lcd.setCursor(11,1);lcd.print(" OFF ");akcja.updateInterval(1,0);} // 0 oznacza stop akcji (dla ruchu mieszalnika)
}
// =========================================================================
W załączniku biblioteka Timers do zaimportowania (chodzą słuchy, że ta stara nie działa jak trzeba, więc tamtą trzeba usunąć i w to miejsce nowa :-)
Pozdrawiam ...i czekam na ew. sugestie, ten wątek może być przyczynkiem do wielu rzeczowych dyskusji :-)
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Ostatnio zmieniony 26 mar 2014, 18:37 przez wojtekizk, łącznie zmieniany 2 razy.

Co miesiąc do wygrania nagrody o wartości ponad 1600 zł!


przepro
Młodszy majsterkowicz
Posty: 12
Rejestracja: 24 mar 2014, 23:32

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay

Post autor: przepro » 24 mar 2014, 23:39

Hi,
bardzo fajny tutorial. Zainteresowany nim, napisałem program wyświetlający na LCD czas (DS1307) i temperaturę (DS18B20). W "setup" umieściłem:

Kod: Zaznacz cały

akcja.attach(0, 2001,ShowDS18B20); // pokazujemy temperature co 2 s
akcja.attach(0, 1001,ShowClock); // pokazujemy czas co sekunde
w "loop":

Kod: Zaznacz cały

akcja.process();
Na LCD wyświetlany jest wynik działania drugiej z "attach" procedur. Po zamianie ich kolejności to samo. Umieszczone po sobie w "loop" wyświetlane są poprawnie. Może wiesz jak to poprawić?
Pozdrawiam serdecznie.
Mariusz.
przepro
Młodszy majsterkowicz
Posty: 12
Rejestracja: 24 mar 2014, 23:32

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay

Post autor: przepro » 24 mar 2014, 23:43

HI,
całość kodu:

Kod: Zaznacz cały

#include <Wire.h>
#include <LiquidCrystal.h>
#include "RTClib.h"
#include <OneWire.h>
#include <Timers.h> 
Timers <2> akcja; // na poczatek 8 niezależnych wątków (procesów, zadań, procedur, akcji itp.)
RTC_DS1307 rtc;
OneWire  ds(10);  // on pin 10 (a 4.7K resistor is necessary)
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(30, 32, 33, 34, 35, 36);
void ShowClock(){
  // ---------- DS1307 -------------  
  DateTime now = rtc.now();
  // print the number of seconds since reset:
  //lcd.print(millis()/1000);
  lcd.setCursor(0, 0);
  if (now.hour() < 10){
    lcd.print("0");
  }
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  if (now.minute() < 10){
    lcd.print("0");
  }  
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  if (now.second() < 10){
    lcd.print("0");
  }
  lcd.print(now.second(), DEC);
  // -----------------------------
}
void ShowDS18B20(){
  // ------- DS18B20 -------------
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius;
  if ( !ds.search(addr)) {
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }
  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end
  //delay(1000);     // maybe 750ms is enough, maybe not
  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
  }

  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } 
  else {
    byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
  }
  celsius = (float)raw / 16.0;
  lcd.setCursor(0, 1);
  lcd.print(celsius);
  lcd.setCursor(6, 1);
  lcd.print("Celsius");
  // -----------------------------
}
void funkcja(){
  ShowDS18B20();
  ShowClock();
}
void setup () {
  //  // przesuwamy dlugi tekst na ekranie
  //  lcd.clear();
  //  // resets cursor position 
  //  lcd.setCursor(0, 4); 
  //  lcd.print("    Use right/left buttons to select LED    ");
  //  delay (100);
  //  for (int positionCounter = 0; positionCounter < 27; positionCounter++) {
  //    // scroll one position left:
  //    lcd.scrollDisplayLeft(); 
  //    // wait a bit:
  //    delay(500);
  //  }
  // -----------------------------------  
  lcd.begin(16, 2);
  Serial.begin(57600);
  Wire.begin();
  rtc.begin();  
  //lcd.clear();

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(__DATE__, __TIME__));
  }


}

void loop () {
  akcja.process();
}
// END of loop --------------------------------------------------


Czyli teraz wyświetli ShowClock. Po zamianie miejscami:
akcja.attach(0, 1001,ShowClock); // pokazujemy czas co sekunde
akcja.attach(0, 2001,ShowDS18B20); // pokazujemy temperature co 2 s
... wyświetli ShowDS18B20.
Pozdrawiam serdecznie.
Awatar użytkownika
wojtekizk
Starszy majsterkowicz
Posty: 309
Rejestracja: 19 lis 2013, 10:54
Lokalizacja: Bydgoszcz

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay

Post autor: wojtekizk » 25 mar 2014, 08:16

Witam
Cóż w Twoim kodzie z drugiego postu nie widzę w setupie dołączonych attach... możliwe że jeszcze śpię :-)
A w pierwszym poście masz:

Kod: Zaznacz cały

akcja.attach(0, 2001,ShowDS18B20); // pokazujemy temperature co 2 s
akcja.attach(0, 1001,ShowClock); // pokazujemy czas co sekunde
... czyli wszystko jest poprawne, wyświetla się dokładnie tak jak chce tego kod:-) ...a nie jak twórca programu :-)... ponieważ w attach masz dla obu wątków ten sam numer - 0 !!!, a powinno być 0 dla np. temperatury i 1 dla czasu :-)

Kod: Zaznacz cały

akcja.attach(0, 2001,ShowDS18B20); // pokazujemy temperature co 2 s
akcja.attach(1, 1001,ShowClock); // pokazujemy czas co sekunde
Jest jeszcze jedna sprawa. Otóż jak dobrze pamiętam pojedynczy pomiar temperatury na Dallasach trwa ok 750 ms. (wg. noty katalogowej) i to jest właśnie powód, dla którego staram się nie używać tych w sumie bardzo dobrych elementów. Jesli nie potrzebuję przynajmniej 3 czujników to korzystam z LM35. Łączy się je z Analogiem i po problemie. Również kod jest o niebo prostszy bo czytam sobie stan Analoga i jednym prosciutkim wzorem przerabiam na st. Celsjusa.
W Twoim kodzie widzę, że zaremowałeś owo delay(1000), to bardzo dobrze dla naszej biblioteki Timers ale głowy nie dam czy tak samo dobrze dla pomiarów, bo producent skoro daje to delay, to chyba wie co robi. Z drugiej strony jeśli bez delay działa, to po co to zmieniać :-).
Pozdrawiam
przepro
Młodszy majsterkowicz
Posty: 12
Rejestracja: 24 mar 2014, 23:32

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay

Post autor: przepro » 25 mar 2014, 23:11

:=) Witam ponownie,
ehhhhh, moja wina, faktycznie zawinił nr_watku. Poprawny kod programu ponizej:

Kod: Zaznacz cały

#include <Wire.h>
#include <LiquidCrystal.h>
#include "RTClib.h"
#include <OneWire.h>
#include <Timers.h> 
Timers <2> akcja; // na poczatek 2 niezależne wątki (procesy, zadania, procedury, akcje itp.)
RTC_DS1307 rtc;
OneWire  ds(10);  // on pin 10 (a 4.7K resistor is necessary)
LiquidCrystal lcd(30, 32, 33, 34, 35, 36); // akurat tak podłączyłem

void ShowClock(){
  // ---------- DS1307 -------------  
  DateTime now = rtc.now();
  lcd.setCursor(0, 0);
  if (now.hour() < 10){
    lcd.print("0");
  }
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  if (now.minute() < 10){
    lcd.print("0");
  }  
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  if (now.second() < 10){
    lcd.print("0");
  }
  lcd.print(now.second(), DEC);
  // -----------------------------
}
void ShowDS18B20(){
  // ------- DS18B20 -------------
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius;
  if ( !ds.search(addr)) {
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }
  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end
  //delay(1000);     // maybe 750ms is enough, maybe not
  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);         // Read Scratchpad

  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
  }

  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } 
  else {
    byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
  }
  celsius = (float)raw / 16.0;
  lcd.setCursor(0, 1);
  lcd.print(celsius);
  lcd.setCursor(6, 1);
  lcd.print("C");
}

void setup () {
  lcd.begin(16, 2);
  Serial.begin(57600);
  Wire.begin();
  rtc.begin();  
  
  akcja.attach(0, 1000,ShowDS18B20); // pokazujemy temperature co 2 s
  akcja.attach(1, 1000,ShowClock); // pokazujemy czas co sekunde
}

void loop () {
  akcja.process();
}
Może komuś początkującemu się przyda :=), choć po Twoim wcześniejszym tłumaczeniu to wątpię :=). Wczoraj miliony zmian, wieczór ... soczek :=). Biblioteka faktycznie przydatna.
Apropos DS18B20 to ... chyba ślepy byłem. Faktycznie LM35 w obsłudze prostszy jest. Ehh, cały czas się czegoś uczę.
Pozdrawiam serdecznie i majsterkowo.pl sukcesów życzę :=)
Mariusz
PS. Za chwile zapewne tu wpadnę :=) ...
przepro
Młodszy majsterkowicz
Posty: 12
Rejestracja: 24 mar 2014, 23:32

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay

Post autor: przepro » 25 mar 2014, 23:23

Witam ponownie,
a pozostając przy DS18B20 i czasie ok 750ms pomiędzy rozpoczęciem pomiaru i jego odczytem. Jakby mogła wyglądać jego obsługa? Jedną z procedur musielibyśmy wywołać wcześniej, a drugą ponad 750 ms później. Biblioteka i nr_wątku ustawia w kolejkę, ale nie umożliwia zdefiniowania gwarantowanego odstępu czasowego pomiędzy procedurami. Dobrze myślę?
Pozdrawiam
Mariusz
Awatar użytkownika
wojtekizk
Starszy majsterkowicz
Posty: 309
Rejestracja: 19 lis 2013, 10:54
Lokalizacja: Bydgoszcz

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay

Post autor: wojtekizk » 26 mar 2014, 07:42

Witam
Tak dokładnie jest jak piszesz. Nie jestem twórcą tej biblioteki, cóż jak każda ma swoje ograniczenia. Trzeba tylko uważać jak w przerwaniach, aby to co trzeba zrobić w wątku samo w sobie nie zawierało czasochłonnych operacji. Nawiasem mówiąc warto by przetestować co się stanie jeśli czas wykonywania jakiegoś wątku będzie za długi. Czy procesor wywoła następny wątek? A jeśli tak, to czy po wykonaniu następnego powróci jak z przerwania i dokończy poprzedni? Nie zgłębiałem tego jeszcze. Może ktoś podejmie się tego zadania :-)
Pozdrawiam
ps. Ja bym jednak nie ryzykował u Ciebie z tym samym interfalem (w obu wątkach masz 1000)... dobra praktyka to liczby pierwsze, bo nawet wielokrotność bardzo rzadko się będzie nakładać)
zgred125
Majsterkowicz
Posty: 88
Rejestracja: 23 gru 2013, 22:39

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay

Post autor: zgred125 » 23 wrz 2014, 14:14

Kiedyś czytałem, że jak procesor jest zajęty obsługą przerwania nr 1 a w tym czasie zostanie wykonane przerwanie nr 2 to procek skończy obsługę przerwania nr 1 wróci do pętli loop wykona jedną linię z kodu (!maszynowego) i wyzwoli kod z przerwania nr 2.
brombal
Młodszy majsterkowicz
Posty: 7
Rejestracja: 25 paź 2014, 08:11

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay

Post autor: brombal » 25 paź 2014, 08:25

witam
A po co do pomiaru temperatury delay albo dwa wątki ? Wystarczy jeden wątek flaga i prosty if
Wywołujemy wątek co min 750ms w if-ie sprawdzamy czy ustawiona flaga jesli nie to ją ustawiamy wysyłamy do ds rozkaz pomiaru temp. i wychodzimy jeśli ustawiona to kasujemy flagę odczytujemy temperaturę i finito żadnego delaya i komplikacji wątkowych .(tak robię gdy mam więcej niż jednego ds i co 750ms czytam sobie kolejnego )
Ewentualnie wywołujemy wątek co 750ms najpierw dokonujemy odczytu temp potem dajemy rozkaz pomiaru
i w ten sposób będziesz miał błędne wskazanie temperatury za pierwszym odczytem chyba że gdzieś wcześniej przed pętlą główną dasz rozkaz pomiaru.

wojtekizk nie przyjmij tego co napiszę, że się czepiam bo sam nie jestem orłem ale zmień jak możesz w tym gotowcu "interfał" na interwał . Gratuluję ładnego opisu biblioteki .
gablota
Młodszy majsterkowicz
Posty: 2
Rejestracja: 28 lis 2014, 12:59
Kontakt:

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay

Post autor: gablota » 28 lis 2014, 13:02

przyda mi się na zajęciach :) dzięki :)
Awatar użytkownika
darw
Młodszy majsterkowicz
Posty: 1
Rejestracja: 18 gru 2014, 09:42
Lokalizacja: Łomża
Kontakt:

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay

Post autor: darw » 18 gru 2014, 10:03

Niezły tutorial.
kopara00
Młodszy majsterkowicz
Posty: 10
Rejestracja: 23 sty 2015, 22:50

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay

Post autor: kopara00 » 23 sty 2015, 22:55

dzieki napewno sie przyda
sunortas
Młodszy majsterkowicz
Posty: 11
Rejestracja: 21 sty 2015, 21:27

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay

Post autor: sunortas » 23 mar 2015, 20:45

Witam majsterkowiczów!!

Mam gruby projekt i potrzebuje Waszej pomocy.
Celem mojego projektu jest stworzenie makiety sygnalizacji świetlnej (inteligentnej) która będzie sterowana za pomocą kamery.
Kamera kinekt będzie podłączona do PC i oprogramowana w MVS (Visual Studio) i za pomocą USB ( planuje zrobić to w przyszłości bez przewodowo) będą wysyłane informacje do Arduino o stanie natężenia ruchu na skrzyżowaniu.
Problem mam w tym momencie z kodem pod Arduino. Jeżeli chodzi o kamerkę to jest to inna bajka.
Zaciekawiła mnie biblioteka Timers ponieważ podczas walki z Arduino nie spotkałem się jeszcze z tą biblioteką :). Miałem problem swego czasu z przerwaniami, mimo działającego kodu nie do końca jestem zadowolony z efektu.
Na dziś dzień mam stworzoną makietę skrzyżowania i działający kod, lecz nie do końca.
Problem jest w tym iż: do skrzyżowania podłączone są przyciski łącznie 8 sztuk (mostkowana po 2 na przejście dla pieszych) . 4 pary przycisków są napisane na 4 przerwania w Arduino (Arduino Mega) i nie zawsze te przyciski chcą działać . Już używałem nawet kondensatorów na tych przyciskach , korzystałem z możliwości PULL_UP i tak dalej. Najprawdopodobniej wina leży w kodzie a nie w fizycznym działaniu.
Moja prośba jest taka iż potrzebuje kogoś kto nakieruje mnie jak można wykorzystać tą bibliotekę do mojego skrzyżowania i maksymalne skrócenie kodu. Co prawda kod napisany jest bardzo na piechotę jak na Studenta. (Z programowania jestem cienki ale za to dobrze sobie radze z sieciami i CISCO)
Pozdrawiam,
Majster:)

Kod: Zaznacz cały

volatile int pasy1=0;
volatile int pasy2=0;
volatile int pasy3=0;
volatile int pasy4=0;
void setup ()
{
  Serial.begin(9600);
  while(!Serial);
  pinMode(A0,INPUT);
  pinMode(25,OUTPUT);  // czerwone 1
  pinMode(27,OUTPUT);  // zolte 1
  pinMode(23,OUTPUT);  // zielone 1

  pinMode(51,OUTPUT); //czerwone 2
  pinMode(53,OUTPUT); //zolte 2
  pinMode(49,OUTPUT); // zielone 2

  pinMode(45,OUTPUT); // czerwone 3
  pinMode(47,OUTPUT); //zolte 3
  pinMode(43,OUTPUT); // zielone 3

  pinMode(31,OUTPUT); // czerwone 4
  pinMode(29,OUTPUT); //zolte 4
  pinMode(33,OUTPUT); // zielone 4

  pinMode(13,OUTPUT);  // czerwone pasy 1
  pinMode(12,OUTPUT);  // zielone pasy 1

  pinMode(7,OUTPUT);  // czerwone pasy 2
  pinMode(6,OUTPUT);  // zielone pasy 2

  pinMode(9,OUTPUT);  // zielone pasy 3
  pinMode(8,OUTPUT);  // czerwone pasy 3

  pinMode(11,OUTPUT);  // zielone pasy 4
  pinMode(10,OUTPUT);  // czerwone pasy 4 

  pinMode(4,OUTPUT);  // brzeczek pasów

  attachInterrupt(0, przycisk_pasy_1, RISING);
  attachInterrupt(1, przycisk_pasy_2, RISING);
  attachInterrupt(2, przycisk_pasy_3, RISING);
  attachInterrupt(3, przycisk_pasy_4, RISING);
  
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(21, INPUT_PULLUP);
  pinMode(20, INPUT_PULLUP);
}

void przycisk_pasy_1()
{ 
  pasy1=!pasy1; 
}

void przycisk_pasy_2()
{ 
  pasy2=!pasy2; 
}

void przycisk_pasy_3()
{ 
  pasy3=!pasy3; 
}

void przycisk_pasy_4()
{ 
  pasy4=!pasy4; 
}

void loop ()
{ 
  Serial.println(pasy1);
  Serial.println(pasy2);
  Serial.println(pasy3);
  Serial.println(pasy4);

  int odczyt = analogRead(A0);

  Serial.println(odczyt);
  if (odczyt > 950)
  {
a:
    digitalWrite(51,LOW);
    digitalWrite(45,LOW);
    digitalWrite(25,LOW);
    digitalWrite(12,LOW);
    digitalWrite(7,LOW);
    digitalWrite(8,LOW);
    digitalWrite(31,LOW);
    digitalWrite(10,LOW);

    digitalWrite(27,HIGH);
    digitalWrite(53,HIGH);
    digitalWrite(47,HIGH);
    digitalWrite(29,HIGH);
    delay(2000);
    digitalWrite(27,LOW);
    digitalWrite(53,LOW);
    digitalWrite(47,LOW);
    digitalWrite(29,LOW);
    delay(2000);
  }
  else
  {
    digitalWrite(51,HIGH);
    digitalWrite(43,HIGH);
    digitalWrite(23,HIGH);
    digitalWrite(12,HIGH);
    digitalWrite(7,HIGH);
    digitalWrite(8,HIGH);
    digitalWrite(31,HIGH);
    digitalWrite(10,HIGH);

    if (pasy1 == HIGH)
    { 
      goto pasy1; 
    }

    if (pasy2 == HIGH)
    { 
      goto pasy2; 
    }

    if (pasy3 == HIGH)
    { 
      goto pasy3; 
    }

    if (pasy4 == HIGH)
    { 
      goto pasy4; 
    }

    Serial.println(pasy1);
    Serial.println(pasy2);
    Serial.println(pasy3);
    Serial.println(pasy4);
pasy1:
    pasy1=0;

    delay(3000);
    digitalWrite(12,LOW);
    digitalWrite(13,HIGH);
    digitalWrite(4,HIGH);
    delay(2000);
    digitalWrite(13,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(13,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(13,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(13,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(13,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(13,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(52,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(13,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(13,LOW);
    digitalWrite(4,LOW);
    digitalWrite(12,HIGH);

    delay(3000);
    digitalWrite(27,HIGH);
    delay (3000);
    digitalWrite(23,LOW);
    digitalWrite(27,LOW);
    digitalWrite(25,HIGH);
    delay (5000);
    digitalWrite(25,LOW);
    digitalWrite(27,HIGH);
    delay(5000);
    digitalWrite(27,LOW);
    digitalWrite(23,HIGH);

    if (pasy1 == HIGH)
    { 
      goto pasy1; 
    }

    if (pasy2 == HIGH)
    { 
      goto pasy2; 
    }

    if (pasy3 == HIGH)
    { 
      goto pasy3; 
    }

    if (pasy4 == HIGH)
    { 
      goto pasy4; 
    }

    Serial.println(pasy1);
    Serial.println(pasy2);
    Serial.println(pasy3);
    Serial.println(pasy4);

pasy2:

    pasy2=0;


    odczyt = analogRead(A0);
    Serial.println(odczyt);
    if (odczyt > 950)
      goto a;
    else

        delay(3000);
    digitalWrite(51,HIGH);
    delay(500);
    digitalWrite(7,LOW);
    digitalWrite(6,HIGH);
    digitalWrite(4,HIGH);
    delay(2000);
    digitalWrite(6,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(6,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(6,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(6,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(6,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(6,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(6,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(6,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(6,LOW);
    digitalWrite(4,LOW);
    digitalWrite(7,HIGH);
    delay(3000);

    digitalWrite(53,HIGH);
    delay (3000);
    digitalWrite(51,LOW);
    digitalWrite(53,LOW);
    digitalWrite(49,HIGH);
    delay (5000);
    digitalWrite(49,LOW);
    digitalWrite(53,HIGH);
    delay(5000);
    digitalWrite(53,LOW);
    digitalWrite(51,HIGH);

    if (pasy1 == HIGH)
    { 
      goto pasy1; 
    }

    if (pasy2 == HIGH)
    { 
      goto pasy2; 
    }

    if (pasy3 == HIGH)
    { 
      goto pasy3; 
    }

    if (pasy4 == HIGH)
    { 
      goto pasy4; 
    }

    Serial.println(pasy1);
    Serial.println(pasy2);
    Serial.println(pasy3);
    Serial.println(pasy4);

pasy3:

    pasy3=0;

    odczyt = analogRead(A0);
    Serial.println(odczyt);
    if (odczyt > 950)
      goto a;
    else

        delay(3000);    
    digitalWrite(43,HIGH);
    delay(500);
    digitalWrite(8,LOW);
    digitalWrite(9,HIGH);
    digitalWrite(4,HIGH);
    delay(2000);
    digitalWrite(9,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(9,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(9,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(9,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(9,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(9,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(9,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(9,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(9,LOW);
    digitalWrite(4,LOW);
    digitalWrite(8,HIGH);

    delay(3000);
    digitalWrite(47,HIGH);
    delay (3000);
    digitalWrite(43,LOW);
    digitalWrite(47,LOW);
    digitalWrite(45,HIGH);
    delay (5000);
    digitalWrite(45,LOW);
    digitalWrite(47,HIGH);
    delay(5000);
    digitalWrite(47,LOW);
    digitalWrite(43,HIGH);

    if (pasy1 == HIGH)
    { 
      goto pasy1; 
    }

    if (pasy2 == HIGH)
    { 
      goto pasy2; 
    }

    if (pasy3 == HIGH)
    { 
      goto pasy3; 
    }

    if (pasy4 == HIGH)
    { 
      goto pasy4; 
    }

    Serial.println(pasy1);
    Serial.println(pasy2);
    Serial.println(pasy3);
    Serial.println(pasy4);

pasy4:

    pasy4=0;

    odczyt = analogRead(A0);
    Serial.println(odczyt);
    if (odczyt > 950)
      goto a;
    else

        delay(3000);      
    digitalWrite(31,HIGH);
    delay(500);
    digitalWrite(10,LOW);
    digitalWrite(11,HIGH);
    digitalWrite(4,HIGH);
    delay(2000);
    digitalWrite(11,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(11,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(11,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(11,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(11,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(11,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(11,LOW);
    digitalWrite(4,LOW);
    delay(500);
    digitalWrite(11,HIGH);
    digitalWrite(4,HIGH);
    delay(500);
    digitalWrite(11,LOW);
    digitalWrite(4,LOW);
    digitalWrite(10,HIGH);
    delay(3000);

    digitalWrite(29,HIGH);
    delay (3000);
    digitalWrite(31,LOW);
    digitalWrite(29,LOW);
    digitalWrite(33,HIGH);
    delay (5000);
    digitalWrite(33,LOW);
    digitalWrite(29,HIGH);
    delay(5000);
    digitalWrite(29,LOW);
    digitalWrite(31,HIGH);
  }  
}
P.S. Nie mogę umieścić linków do zdjęć z makietą a chciałbym jakoś pokazać Wam jeżeli treść nie do końca jest jasna.( po umieszczenie linka ze zdjęciem odsyła mnie do działy REKLAMA)
fsq90
Młodszy majsterkowicz
Posty: 1
Rejestracja: 17 gru 2016, 14:42

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay !

Post autor: fsq90 » 29 sty 2017, 13:00

Nie mogę sobie poradzić z prostą rzeczą. Chcę żeby po wciśnięciu przycisku na pilocie dioda mrugnęła 10 razy. Ponadto chciałbym zróżnicować czas świecenia (powiedzmy 1s) i czas gdy dioda nie świeci (powiedzmy 2s). Póki co mam tyle co poniżej, dioda mruga raz po wciśnięciu przycisku. Na delayach mi działa :).

Kod: Zaznacz cały

#include <Timers.h>
#include <IRremote.h>
#include <IRremoteInt.h>

int green = 2;
int yellow = 3;
int red = 4;
int mosfet = 5;
int irPin = 11;
int pwm1 = 9;
int pwm2 = 10;
int pwm3 = 6;
int pwm1a = 135;
int pwm2a = 135;
int pwm3a = 135;

Timers <2> akcja;

IRrecv irrecv(irPin);
decode_results results;

void setup() {

   akcja.attach(0,0,ledOn);      
   
   Serial.begin(9600);
   irrecv.enableIRIn();

   pinMode(irPin, INPUT);
   pinMode(green, OUTPUT);
   pinMode(yellow, OUTPUT);
   pinMode(red, OUTPUT);
   
   pinMode(mosfet, OUTPUT);
   
   pinMode(pwm1, OUTPUT);
   pinMode(pwm2, OUTPUT);
   pinMode(pwm3, OUTPUT);
   
   digitalWrite(green, LOW);
}

void loop() {
akcja.process();
 
if (irrecv.decode(&results)) 
  {   
   switch(results.value)
      {  case 0xFF4AB5: // Button 0
      for (int i=0;i<10;i++){
         akcja.setInterval(0,500);
         digitalWrite(green, HIGH);
         break;
         }
      }     
 irrecv.resume(); }
}

void ledOn(){
  akcja.updateInterval(0,0);
  digitalWrite(green, LOW);
}
porters1
Młodszy majsterkowicz
Posty: 1
Rejestracja: 26 wrz 2017, 18:45

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay !

Post autor: porters1 » 26 wrz 2017, 19:02

Witam, Zainteresował mnie ten tema. Piszę program do wyświetlania czasów na wyświetlaczu ILI9341. Wadą jest powolne wyświetlanie które zajmuje ok 2sek. W między czasie mam komunikacje z portami zewnętrznymi oraz Monitorem portu. Zastosowałem Twój Timers.h jednakże blokuje on całość programu niezależnie od wątku w którym się znajduje. W jaki sposób mogę zastosować Timers.h aby wszystkie wątki działały oddzielnie?
brombal
Młodszy majsterkowicz
Posty: 7
Rejestracja: 25 paź 2014, 08:11

Re: gotowiec 4 - obsługa wątków = koniec z uciążliwym delay !

Post autor: brombal » 7 sty 2018, 21:34

najlepiej nie wysyłaj całego ekranu tylko to co chcesz zmienić i nie będzie to 2 sek .bankowo kasujesz ekran i wysyłasz nową zawartość
ODPOWIEDZ

Strony partnerskie: