Arduino Polska Forum

Pełna wersja: Lepszy kod do przycisku
Aktualnie przeglądasz uproszczoną wersję forum. Kliknij tutaj, by zobaczyć wersję z pełnym formatowaniem.
Witam,

jestem dosyć świeżo upieczonym użytkownikiem Arduino i mam poniższy problem, a raczej zapytanie.

Poniżej przedstawiam mój kod, służący do obsługi 2 diod, potencjometru i przycisku.
Diody migają za pomocą funkcji millis();, potencjometr zmienia interwał pomiędzy zmianami stanów na diodach, a przycisk ma "włączać i wyłączać" program. 

Kod:
const int greenPin =  8;  // pin 8 to greedPin const
int greenState = LOW;     // green LED LOW (0)
const int redPin =  4;    // pin 4 to redPin const
int redState = LOW;       // red LED LOW (0)

const int btn = 11;     // pin 11 to btn const

int btnCounter = 0;     // counter of button pressed states
int btnState = 0;       // button state
int lastBtnState = 0;   // last button state

unsigned long greenPreviousTime = 0;   // last time for green LED
unsigned long redPreviousTime = 0;     // last time for red LED

void setup() {
 Serial.begin(9600);          //Serial for debug
 pinMode(greenPin, OUTPUT);  
 pinMode(redPin, OUTPUT);
 pinMode(btn, INPUT);
}

void loop() {
 
 int btnState = digitalRead(btn);     // reads current button state 0 or 1 and saves it to variable

 if (btnState != lastBtnState) {
   if(btnCounter==2){              // if counter = 2 reset to 0
       btnCounter=0;
       Serial.println("Program state: RUNNING --> Press button to stop...");
   }
   if (btnState == LOW) {                // if btn pushed down (state is LOW -> 0)
     btnCounter++;                       // add 1 to counter
   }
   if(btnCounter==1 && btnState==HIGH){    // without btnState at HIGH Serial. message was printing 2 times
     greenState = 0;
     redState = 0;                   // turn off LEDs
     digitalWrite(greenPin, greenState);
     digitalWrite(redPin, greenState);
     Serial.println("Program state: STOP --> Press button to start...");
   }                              // delay for avoiding errors ??? how to avoid this ???
 delay(50);
 }
 lastBtnState = btnState;            // changes last btn state variable to current state
 

 if(btnCounter==0){                // if counter 0 main code part runs, if is TRUE
   int timeInterval = analogRead(A5);       // TimeInterval from potentiometer (~ 0 -> 1023)
   /*
   Serial.print("Time interval: ");         // uncomment to see current interval in Serial Monitor
   Serial.println(TimeInterval);
   */
   unsigned long greenCurrentTime = millis();    // add millis(); to RED and GREEN LED time variables
   unsigned long redCurrentTime = millis();
   // GREEN LED CODE START **********************
     
   if (greenCurrentTime - greenPreviousTime >= timeInterval) {   // if passed time is higher that interval
     greenPreviousTime = greenCurrentTime;                       // previous time to current time variable
     if (greenState == LOW) {                                    // simple dioda state change
       greenState = HIGH;
     }else {
       greenState = LOW;
     }  
   digitalWrite(greenPin, greenState);                           // on - off LED
   }

   // RED LED CODE START **********************
 
   if (redCurrentTime - redPreviousTime >= timeInterval) {
     redPreviousTime = redCurrentTime;
     if (redState == LOW) {
       redState = HIGH;
     }else {
       redState = LOW;
     }
   digitalWrite(redPin, redState);
   }
 }
}

Tutaj zdjęcia układu:

[Obrazek: oie_jwld_Aj_GWd_BZF.png]

Chciałbym usłyszeć jakieś uwagi odnośnie samego kodu.

Czy jest jakiś lepszy sposób na kontrolę wciśnięć przycisku?
Czy jest jakiś lepszy sposób na wstrzymywanie i uruchamianie programu (chodzi mi o wstrzymywanie jak i o np: zerowanie wszystkich stanów do początku, czasu, millis(); etc.)?
Jak ogólnie prezentuje się kod, czytelnośc etc. ?


Bedę wdzięczny za wszelkie uwagi, sama obsługa przycisku nadal mnie zastanawia, wyczytałem o czymś takim jak debouncing, może ktoś wyjaśni jakie ma to praktyczne zastosowanie?

EDIT: Aktualnie po wciśnięciu przycisku praca programu wstrzymuje się np: w czasie aktualnym 1500 ms, po ponownym naciśnięciu startuje od 1500 ms i po 500 ms zapala lub gasi diody (zalezne w jakim stanie są). Chodzi mi, aby uniknąć takiej sytuacji, aby po naciśnięciu przycisku diody wchodzi w stan LOW -> 0 i po ponownym naciśnięciu startowały od czasu zerowego (0ms, 1000ms, 2000 ms etc.).
Jeśli chodzi o przejrzystość kodu to zauważyłem że robisz ponowną deklarację zmiennej btnState typu int, jest to Twoja zmienna globalna więc nie wymaga ponownej deklaracji w funkcji loop().
Nie wiem w jakim celu masz btnCounter'a bo on i tak liczy jedynie do 2 i się zeruje, wystarczy zmienna stanu i przy wykryciu stanu nadpisujesz aktualny stan, a ostatni zmieniasz na jego negację
Jeśli chodzi o przyciski to miej na uwadze czas drgania styków, zazwyczaj opóźnienie ok 20ms wystarcza aby stan został ustalony. Jeśli nie wiesz o czym mowa polecam zgłębić się w temacie TactSwitch'y
Do wywoływania takich przerw w różnych odstępach czasu polecam skorzystanie z biblioteki Timers.h. Przeszukaj dobrze forum a znajdziesz jej szczegółowy opis wraz z przykładowymi programami. Sam niedawno poznałem jej zasadę działania i uważam że jest bardzo dobrym rozwiązaniem na Twoje oczekiwania, pozdrawiam
Witam 
Ja tylko chciałbym podpowiedzieć i ułatwić pracę... skorzystaj z biblioteki OneButton.h w przykładach znajdziesz przykłady bardzo stabilne i prostego biblioteki/programu do obsługi jednego przycisku -  kliknięcie, dwa kliknięcia, długie przyciskanie...


Kod:
#include "OneButton.h"

// Setup a new OneButton on pin A1.  
OneButton button(A1, true);


// setup code here, to run once:
void setup() {
 // enable the standard led on pin 13.
 pinMode(13, OUTPUT);      // sets the digital pin as output
 
 // link the doubleclick function to be called on a doubleclick event.  
 button.attachDoubleClick(doubleclick);
} // setup
 

// main code here, to run repeatedly:
void loop() {
 // keep watching the push button:
 button.tick();

 // You can implement other code in here or just wait a while
 delay(10);
} // loop


// this function will be called when the button was pressed 2 times in a short timeframe.
void doubleclick() {
 static int m = LOW;
 // reverse the LED
 m = !m;
 digitalWrite(13, m);
} // doubleclick

// End



Pozd.