• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Sterowanie Światłem
#1
Cześć.
Właśnie pracuję nad sterownikiem do domu. Ogólnie sterownik będzie opierał się na RPI z Domoticzem + Arduino ale mój problem dotyczy właśnie Arduino. Nie mogę sobie proadzić z zaprogramowaniem sterowania oświetleniem. Chodzi o to, że światło ma być załączane sygnałem z czujki PIR i dodatkowo włącznikiem dzwonkowym w takim układzie, że jeśli włączymy włącznikiem to czujka nam tego nie wyłączy a jeśli wyłączymy włącznikiem to czujka będzie załączała oświetlenie. To wszystko działa jak trzeba tylko chciałbym dodać opóźnienie wyłączenia z czujki PIR. Próbowałem opóźnień millis na wszystkie sposoby, próbowałem z biblioteką Timers ale nic mi nie działa.
Będę wdzięczny za pomoc.
Pozdrawiam.
Kod:
// Enable debug prints to serial monitor
#define MY_DEBUG


// Enable and select radio type attached
//#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69

// Set LOW transmit power level as default, if you have an amplified NRF-module and
// power your radio separately with a good regulator you can turn up PA level.
//#define MY_RF24_PA_LEVEL RF24_PA_LOW

// Enable serial gateway
#define MY_GATEWAY_SERIAL

// Define a lower baud rate for Arduino's running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender)
#if F_CPU == 8000000L
#define MY_BAUD_RATE 38400
#endif

// Flash leds on rx/tx/err
// #define MY_LEDS_BLINKING_FEATURE
// Set blinking period
// #define MY_DEFAULT_LED_BLINK_PERIOD 300

// Inverses the behavior of leds
// #define MY_WITH_LEDS_BLINKING_INVERSE

// Enable inclusion mode
#define MY_INCLUSION_MODE_FEATURE
// Enable Inclusion mode button on gateway
#define MY_INCLUSION_BUTTON_FEATURE

// Inverses behavior of inclusion button (if using external pullup)
//#define MY_INCLUSION_BUTTON_EXTERNAL_PULLUP

// Set inclusion mode duration (in seconds)
#define MY_INCLUSION_MODE_DURATION 60
// Digital pin used for inclusion mode button
#define MY_INCLUSION_MODE_BUTTON_PIN  3

// Uncomment to override default HW configurations
//#define MY_DEFAULT_ERR_LED_PIN 4  // Error led pin
//#define MY_DEFAULT_RX_LED_PIN  6  // Receive led pin
//#define MY_DEFAULT_TX_LED_PIN  5  // the PCB, on board LED

#include <SPI.h>
#include <MySensors.h>  
#include <Bounce2.h>

// Enable repeater functionality for this node
#define MY_REPEATER_FEATURE


#define RELAY_1  5  // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
#define NUMBER_OF_RELAYS 5 // Total number of attached relays
#define RELAY_ON 0  // GPIO value to write to turn on attached relay
#define RELAY_OFF 1 // GPIO value to write to turn off attached relay

#define BUTTON_PIN A1
#define BUTTON_PIN2 A2
#define LIGHT_PIN 8
#define PIR_PIN 9

void before() {
 for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS;sensor++, pin++) {
   // Then set relay pins in output mode
   pinMode(pin, OUTPUT);  
   // Set relay to last known state (using eeprom storage)
   digitalWrite(pin, loadState(sensor)?RELAY_ON:RELAY_OFF);
 }
}
Bounce debouncer = Bounce();

void setup() {
 // Setup locally attached sensors
 delay(10000);
  // Setup the button.
 pinMode(BUTTON_PIN, INPUT_PULLUP);
 pinMode(BUTTON_PIN2, INPUT_PULLUP);
 // After setting up the button, setup debouncer.
 debouncer.attach(BUTTON_PIN);
 debouncer.interval(25);
 //presentation();
}
void presentation()  
{  
 // Send the sketch version information to the gateway and Controller
 sendSketchInfo("Relay", "1.0");

 for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS;sensor++, pin++) {
   // Register all sensors to gw (they will be created as child devices)
   present(sensor, S_LIGHT);
 }
}

MyMessage msg(4, V_LIGHT);
MyMessage msg2(5, V_LIGHT);


void loop() {
 // Send locally attached sensor data here
 int pinState = digitalRead(BUTTON_PIN2);
 if (debouncer.update()) {
   // Get the update value.
   int value = debouncer.read();
   // Send in the new value.
   if(value == LOW){
        saveState(4, !loadState(4));
        digitalWrite(PIR_PIN, HIGH);
        digitalWrite(LIGHT_PIN, loadState(4)?RELAY_ON:RELAY_OFF);
        send(msg.set(loadState(4)));
   }
 }
 if(loadState(4) == LOW){
   if(pinState == LOW) {
     digitalWrite(PIR_PIN, !pinState);  
  }
  else if(pinState == HIGH){
   digitalWrite(PIR_PIN, !pinState);
  }
  saveState(5, pinState);
  send(msg2.set(pinState));
 }  
}


void receive(const MyMessage &message) {
 // We only expect one type of message from controller. But we better check anyway.
 if (message.type==V_LIGHT) {
    // Change relay state
    digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF);
    // Store state in eeprom
    saveState(message.sensor, message.getBool());
    // Write some debug info
    Serial.print("Incoming change for sensor:");
    Serial.print(message.sensor);
    Serial.print(", New status: ");
    Serial.println(message.getBool());
  }
}
 
Odpowiedź
#2
(24-05-2019, 11:28)AdamJab napisał(a): Nie mogę sobie proadzić z zaprogramowaniem sterowania oświetleniem. Chodzi o to, że światło ma być załączane sygnałem z czujki PIR i dodatkowo włącznikiem dzwonkowym w takim układzie, że jeśli włączymy włącznikiem to czujka nam tego nie wyłączy a jeśli wyłączymy włącznikiem to czujka będzie załączała oświetlenie.
Musisz reagować na zbocze sygnału a nie jego poziom.
 
Odpowiedź
#3
(25-05-2019, 13:08)AdamJab napisał(a): ile bym nie zmieniał to nadal nie działa opóźnienie wyłączenia po załączeniu czujką PIR.
Coś tu robię źle ale nie mam pojęcia co.
Wysyłaj na serial monitor stan kluczowych zmiennych. Najlepszy do tego jest debuger, ale cóż, wybrałeś IDE bez tego pożytecznego narzędzia a praktycznie wszystkie współczesne uC maja możliwość debugowania, chyba, ze ktoś wybiera np Mega8, który jest droższy od Mega88, ma gorsze peryferia i brak możliwości debugowania.
 
Odpowiedź
#4
(24-05-2019, 13:21)es2 napisał(a):
(24-05-2019, 11:28)AdamJab napisał(a): Nie mogę sobie proadzić z zaprogramowaniem sterowania oświetleniem. Chodzi o to, że światło ma być załączane sygnałem z czujki PIR i dodatkowo włącznikiem dzwonkowym w takim układzie, że jeśli włączymy włącznikiem to czujka nam tego nie wyłączy a jeśli wyłączymy włącznikiem to czujka będzie załączała oświetlenie.
Musisz reagować na zbocze sygnału a nie jego poziom.

Ok. Trochę pozmieniałem i teraz prekaźnik Relay_4 jest załączany i wyłączany odpowiednim zboczem sygnału ale pomimo tego nie działa mi opóźnienie wyłączenia po załączeniu czujką PIR.
Co ciekawe doskonale działa opóźnienie załączenia czzujką PIR ale nie o to mi chodzi. 


Kod:
// Enable debug prints to serial monitor
#define MY_DEBUG


// Enable and select radio type attached
//#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69

// Set LOW transmit power level as default, if you have an amplified NRF-module and
// power your radio separately with a good regulator you can turn up PA level.
//#define MY_RF24_PA_LEVEL RF24_PA_LOW

// Enable serial gateway
#define MY_GATEWAY_SERIAL

// Define a lower baud rate for Arduino's running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender)
#if F_CPU == 8000000L
#define MY_BAUD_RATE 38400
#endif

// Flash leds on rx/tx/err
// #define MY_LEDS_BLINKING_FEATURE
// Set blinking period
// #define MY_DEFAULT_LED_BLINK_PERIOD 300

// Inverses the behavior of leds
// #define MY_WITH_LEDS_BLINKING_INVERSE

// Enable inclusion mode
#define MY_INCLUSION_MODE_FEATURE
// Enable Inclusion mode button on gateway
#define MY_INCLUSION_BUTTON_FEATURE

// Inverses behavior of inclusion button (if using external pullup)
//#define MY_INCLUSION_BUTTON_EXTERNAL_PULLUP

// Set inclusion mode duration (in seconds)
#define MY_INCLUSION_MODE_DURATION 60
// Digital pin used for inclusion mode button
#define MY_INCLUSION_MODE_BUTTON_PIN  3

// Uncomment to override default HW configurations
//#define MY_DEFAULT_ERR_LED_PIN 4  // Error led pin
//#define MY_DEFAULT_RX_LED_PIN  6  // Receive led pin
//#define MY_DEFAULT_TX_LED_PIN  5  // the PCB, on board LED

#include <SPI.h>
#include <MySensors.h>  
#include <Bounce2.h>

// Enable repeater functionality for this node
#define MY_REPEATER_FEATURE


#define RELAY_1  5  // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
#define RELAY_2  6
#define RELAY_3  7
#define RELAY_4  8

#define NUMBER_OF_RELAYS 4 // Total number of attached relays
#define RELAY_ON 0  // GPIO value to write to turn on attached relay
#define RELAY_OFF 1 // GPIO value to write to turn off attached relay

#define BUTTON_PIN A1
#define PIR_PIN A2

boolean buttonFlag;
unsigned long pirTime = 0;
unsigned long pirTime2 = 0;

void before() {
 for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS;sensor++, pin++) {
   // Then set relay pins in output mode
   pinMode(pin, OUTPUT);  
   // Set relay to last known state (using eeprom storage)
   digitalWrite(pin, loadState(sensor)?RELAY_ON:RELAY_OFF);
 }
}
Bounce debouncer = Bounce();
Bounce debouncer2 = Bounce();

void setup() {
 // Setup locally attached sensors
 delay(10000);
  // Setup the button.
 pinMode(BUTTON_PIN, INPUT_PULLUP);
 pinMode(PIR_PIN, INPUT_PULLUP);
 // After setting up the button, setup debouncer.
 debouncer.attach(BUTTON_PIN);
 debouncer.interval(25);
 debouncer2.attach(PIR_PIN);
 debouncer2.interval(25);
 //presentation();
}
void presentation()  
{  
 // Send the sketch version information to the gateway and Controller
 sendSketchInfo("Relay", "1.0");

 for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS;sensor++, pin++) {
   // Register all sensors to gw (they will be created as child devices)
   present(sensor, S_LIGHT);
 }
}

MyMessage msg(4, V_LIGHT);

void loop() {
 // Send locally attached sensor data here
 
 debouncer.update();
 debouncer2.update();
 
   if ( debouncer.fell()&& loadState(4) == HIGH ) {  // Call code if button transitions from HIGH to LOW
        saveState(4, !loadState(4));
        digitalWrite(RELAY_4, RELAY_ON);
        send(msg.set(loadState(4)));
        buttonFlag = true;
  }
  else if( debouncer.fell()&& loadState(4) == LOW ){
        saveState(4, !loadState(4)); //Store new state in eeprom
        digitalWrite(RELAY_4, RELAY_OFF);
        send(msg.set(loadState(4))); // Send new state
        buttonFlag = false;
  }
   
 if(buttonFlag == false){
   if(debouncer2.rose()) {  // Call code if button transitions from LOW to HIGH
       digitalWrite(RELAY_4, RELAY_ON);
       saveState(4, !RELAY_ON);  
       send(msg.set(loadState(4)));
     }
   
   else if(debouncer2.fell()) {  // Call code if button transitions from HIGH to LOW
     
      if(millis() - pirTime >= 4000UL) {
       digitalWrite(RELAY_4, RELAY_OFF);
       saveState(4, !RELAY_OFF);  
       send(msg.set(loadState(4)));
       pirTime = millis();
    }          
   }
 }  
}

void receive(const MyMessage &message) {
 // We only expect one type of message from controller. But we better check anyway.
 if (message.type==V_LIGHT) {
    // Change relay state
    digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF);
    // Store state in eeprom
    saveState(message.sensor, message.getBool());
    // Write some debug info
    Serial.print("Incoming change for sensor:");
    Serial.print(message.sensor);
    Serial.print(", New status: ");
    Serial.println(message.getBool());
  }
}
Powyżej wkleiłem pełny kod ale błąd jest gdzieś tu:
Kod:
void loop() {
 // Send locally attached sensor data here
 
 debouncer.update();
 debouncer2.update();
 
   if ( debouncer.fell()&& loadState(4) == HIGH ) {  // Call code if button transitions from HIGH to LOW
        saveState(4, !loadState(4));
        digitalWrite(RELAY_4, RELAY_ON);
        send(msg.set(loadState(4)));
        buttonFlag = true;
  }
  else if( debouncer.fell()&& loadState(4) == LOW ){
        saveState(4, !loadState(4)); //Store new state in eeprom
        digitalWrite(RELAY_4, RELAY_OFF);
        send(msg.set(loadState(4))); // Send new state
        buttonFlag = false;
  }
   
 if(buttonFlag == false){
   if(debouncer2.rose()) {  // Call code if button transitions from LOW to HIGH
       digitalWrite(RELAY_4, RELAY_ON);
       saveState(4, !RELAY_ON);  
       send(msg.set(loadState(4)));
     }
   
   else if(debouncer2.fell()) {  // Call code if button transitions from HIGH to LOW
     
      if(millis() - pirTime >= 4000UL) {
       digitalWrite(RELAY_4, RELAY_OFF);
       saveState(4, !RELAY_OFF);  
       send(msg.set(loadState(4)));
       pirTime = millis();
    }          
   }
 }  
}
 
Odpowiedź
#5
Im więcej informacji wyślesz na monitor tym szybciej znajdziesz błąd.
Niestety, Arduino nie daje możliwości zakładania pułapek, zatrzymania programu i podglądu zmiennych.
 
Odpowiedź
#6
Załóżmy, że ma coś świecić 100s, czyli w momencie gdy uruchamiasz program deklarujesz zmienną dlugSwiecenia, po starcie ma wartość 0.
Wprowadzasz warunek, gdy dlugSwiecenia>0 to załączasz świecenie.
Co sekundę w trakcie działania programu zmniejszasz zmienną if(dlugSwiecenia>0) dlugSwiecenia--.
Gdy pir wykryje ruch ustawiasz zmienną dlugSwiecenia=100.
Jeśli ma działać niezależnie od przycisku to w warunku załączenia świecenia ma być warunek LUB od tej drugiej opcji. Stan przycisku zapisujesz do drugiej zmiennej, np. "przycisk", gdy włączony to przycisk=1, gdy wyłączony to 0.
if(dlugSwiecenia OR przycisk) zaświeć; - to zadziała gdy zmienna dlugSwiecenia LUB przycisk jest różne od 0.
Jak chcesz odwrócić wartości zmiennej przycisk to potem wstawiasz jej odwrotność do warunku:
if(dlugSwiecenia OR !przycisk) zaświeć - gdy ma świecić gdy przycisk ==0;
Jak zmierzyć upływ 1s masz podane w przykładzie blinkWithoutDelay, zamiast zmieniać stan led po prostu robisz to co ma się wydarzyć gdy minie sekunda.
 
Odpowiedź
#7
(25-05-2019, 22:06)kaczakat napisał(a): Załóżmy, że ma coś świecić 100s, czyli w momencie gdy uruchamiasz program deklarujesz zmienną dlugSwiecenia, po starcie ma wartość 0.
Wprowadzasz warunek, gdy dlugSwiecenia>0 to załączasz świecenie.
Co sekundę w trakcie działania programu zmniejszasz zmienną if(dlugSwiecenia>0) dlugSwiecenia--.
Gdy pir wykryje ruch ustawiasz  zmienną dlugSwiecenia=100.
Jeśli ma działać niezależnie od przycisku to w warunku załączenia świecenia ma być warunek LUB od tej drugiej opcji. Stan przycisku zapisujesz do drugiej zmiennej, np. "przycisk", gdy włączony to przycisk=1, gdy wyłączony to 0.
if(dlugSwiecenia OR przycisk) zaświeć; - to zadziała gdy zmienna dlugSwiecenia LUB przycisk jest różne od 0.
Jak chcesz odwrócić wartości zmiennej przycisk to potem wstawiasz jej odwrotność do warunku:
if(dlugSwiecenia OR !przycisk) zaświeć - gdy ma świecić gdy przycisk ==0;
Jak zmierzyć upływ 1s masz podane w przykładzie blinkWithoutDelay, zamiast zmieniać stan led po prostu robisz to co ma się wydarzyć gdy minie sekunda.

Dziękuję za odpowiedź. Bardzo ciekawe podejście ale mam jedno pytanie: czy zapisanie w ten sposób nie spowoduje, że światło przestanie świecić po określonym czasie od załączenia czujki? Bo chodzi o to, żeby światło przestało świecić po określonym czasie od wyłączenia czujki.
 
Odpowiedź
#8
Tutaj jest problem. Nie mogę dołączyć odliczania millis do debounce. Skróciłem kod do niezbędnego minimum. 
Może ktoś spojrzeć i podpowiedzieć co jest nie tak?

Kod:
#include <Bounce2.h>
#define RELAY_4  8
#define RELAY_ON 0  // GPIO value to write to turn on attached relay
#define RELAY_OFF 1 // GPIO value to write to turn off attached relay
#define BUTTON_PIN A1
#define PIR_PIN A2

unsigned long pirTime = 0;
unsigned long pirTime2 = 0;
unsigned long dlugoscSwiecenia = 0;

Bounce debouncer2 = Bounce();

void setup() {
 // put your setup code here, to run once:
 pinMode(RELAY_4, OUTPUT);
 pinMode(PIR_PIN, INPUT_PULLUP);
 digitalWrite(RELAY_4, RELAY_OFF);
 debouncer2.attach(PIR_PIN);
 debouncer2.interval(25);
}

void loop() {
 debouncer2.update();
   if(debouncer2.rose()) {  // Call code if button transitions from LOW to HIGH
       digitalWrite(RELAY_4, RELAY_ON);
     }
   
   if(debouncer2.fell()) {  // Call code if button transitions from HIGH to LOW
        pirTime = millis();
        if(pirTime - pirTime2 >= 5000UL) {
        pirTime2 = pirTime;    
        digitalWrite(RELAY_4, RELAY_OFF) ;        
    }          
   }
}  
 
Odpowiedź
#9
Nie wiem po co sprawdzasz stan przejścia z góry na dół i potem z dołu do góry. Jak pir jest aktywny to resetuj zmienną, czyli wg mnie własnie nie zbocze, a stan niski. Przy PIR w ogóle debounce można wg mnie wywalić, po prostu dopóki wykrywa ruch, jest stan niski to resetujesz timer.
Kod:
#include <Bounce2.h>
#define RELAY_4  0
#define RELAY_ON 0  // GPIO value to write to turn on attached relay
#define RELAY_OFF 1 // GPIO value to write to turn off attached relay
#define BUTTON_PIN 16
#define PIR_PIN 17

#define czasSwiecenia 60 //s

unsigned long pirTime = 0;
unsigned long pirTime2 = 0;
uint8_t dlugoscSwiecenia = 0; //trzeba wiecej niz 255s?
bool stanPrzycisku, fsekundy;
Bounce debouncer2 = Bounce();

void setup() {
Serial.begin(115200);
 
// put your setup code here, to run once:
pinMode(RELAY_4, OUTPUT);
pinMode(PIR_PIN, INPUT_PULLUP);
pinMode(BUTTON_PIN, INPUT_PULLUP);

digitalWrite(RELAY_4, RELAY_OFF);
debouncer2.attach(BUTTON_PIN);
debouncer2.interval(100); //dla sciennych przyciskow czas moze byc wiekszy

}

void loop() {
debouncer2.update();
fsekundy=0;
 
// obsluga czasu
pirTime=millis();
if( (uint32_t) (pirTime-pirTime2)>=1000UL) //co 1s
{
 
 if (dlugoscSwiecenia>0) dlugoscSwiecenia--; // to ja zmniejszaj
  pirTime2=pirTime; //reset licznika millis
 fsekundy=1; // to mozna gdzies wykorzystac w kodzie, "gdy wybije nowa sekunda", trzeba zerowac w kazdej petli na poczatku loop
}


//obsluga zmiennych PIR
if ( ! digitalRead(PIR_PIN)) dlugoscSwiecenia=czasSwiecenia; //gdy pir wykryje ruch resetuj czas swiecenia


//obsluga przycisku
if( ! debouncer2.read())  stanPrzycisku = ! stanPrzycisku; //dla dzwonkowego gdy wcisniety zmien stan na przeciwny
//ewentualnie mozna tu wyzeroac zmienna z PIR, gdby ktos chcial wylaczyc swiatlo natychmiast przyciskiem, a przycisk jest daleko od PIR


//obsluga przekaznika
if( dlugoscSwiecenia or stanPrzycisku) digitalWrite(RELAY_4, RELAY_ON );
else digitalWrite(RELAY_4, RELAY_OFF);

//Arduinowy debug
if(fsekundy)
{
 Serial.print("Stan przycisku  " );
 Serial.print(stanPrzycisku);
 Serial.print(", Timer PIR:  " );
 Serial.println( dlugoscSwiecenia);
 Serial.println();
 
}

 
}
 
Odpowiedź
#10
Proponuję zacząć od tego od czego powinno się zacząć czyli od algorytmu a później pisania softu a nie od du... strony. Początkujący, niczym profesjonaliści zaczynają od pisania softu ale u profesjonalisty, proste algorytmy powstają w głowie (najczęściej w kiblu, w kolejce w sklepie czy u lekarza, w czasie jazdy pociągiem a nawet w czasie seksu) po czy zapamiętany w szarych komórkach algorytm (mimo to zawsze mam ze sobą notatnik) jest przenoszony na program.

Początkujący powinien najpierw narysować sobie graf przejść programu a dopiero potem pisać soft!
AdamJab pokaż algorytm programu, bo z pewnością zrobiłeś go zanim zacząłeś pisać soft, jest nie masz algorytmu to program możesz pisać bardzo długo.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości