Hi there,
I have an UNO with a 4 relay shield. I am building and automatic teatsprayer for our cowshed. For stage 1 of this project I have 1 photoelectric sensor and 1 solenoid valve switched through the relay. I have all of the hardware operating but I need some help with delays using millis.
- I need to ignore pin HIGH to LOW from sensor1 under 2 second.
- I need to switch the relay when sensor1 goes HIGH and then LOW (The sensor is a photoelectric retro-reflective sensor. The cow will break the light beam, but I don't want the relay to switch until the beam is reconnected).
I had that basic function working with the following code
int sensor1 = 6;
int relay1 = 4;
void setup() {
pinMode(sensor1,INPUT_PULLUP);
pinMode(relay1,OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
while(digitalRead(sensor1) == HIGH){
//wait forever unless button pin is low
}
digitalWrite(relay1,HIGH); // energize your relay
delay(1000); // this is the delay you requested it should act an excellent debounce delay also
digitalWrite(relay1,LOW); // release your relay
while(digitalRead(sensor1) == LOW){
//wait forever unless button pin is high
// we need to wait tile your button is released before starting over
}
// Start the loop over
}
This uses a delay which I don't this is suitable as for stage 2 of my project I will be adding and another sensor and solenoid valve that will detect cows who are moving faster and spray and larger amount of teatspray.
Below is the code I have tried with millis. It is ignoring sensor1 HIGH under 2 seconds but it is switching relay1 on sensor1 HIGH after the interval. I'm struggling to work out how to have it switch relay1 on sensor1 LOW.
Any help would be much appreciated
const int sensor1 = 6;
const int relay1 = 4;
int Reading;
boolean relayOn = false;
unsigned long startTime;
unsigned long interval = 2000;
void setup() {
pinMode(sensor1, INPUT_PULLUP);
pinMode(relay1, OUTPUT);
Serial.begin(9600);
}
void loop() {
Reading = digitalRead(sensor1); // Reading status of Arduino digital Pin
if(Reading == HIGH)
{
Serial.println("HIGH");
}
if(Reading == LOW)
{
Serial.println("LOW");
}
if (digitalRead(sensor1) == LOW) {
startTime = millis();
digitalWrite(relay1, LOW);
relayOn = true;
}
if (millis() - startTime >= interval && relayOn == true) {
digitalWrite(relay1, HIGH);
relayOn = false;
}
}
Have a look at an example sketch called Blink without delay. It uses a different approach to give a delay without using the arduino delay function and is "non-blocking", which means other code can continue to run while the delay is being counted. the delay function is blocking - that is, code stops running until the delay is completed. It does still use the millis function, but I don't think that is cause for concern.
That approach may suit your requirement better.
Thanks for your reply @steve_macdonald
I have had a play around with millis and it is nearly working as I would like. Its change the intervals seems to be conflicting with each other.
It is ignoring the sensor state change for 2 seconds but now there is now a delay before the relay is switched and the relay is staying on too long.
Can anyone help with where my code is conflicting?
const int sensor1 = 6;
const int relay1 = 4;
int sensorState;
boolean relayOn = true;
unsigned long previousMillis = 0; // will store last time LED was updated
// constants won't change:
const long interval = 2000; // interval at which to blink (milliseconds)
unsigned long startTime;
unsigned long sprayinterval = 1000;
boolean sensorWasLow = false;
void setup() {
pinMode(sensor1, INPUT_PULLUP);
pinMode(relay1, OUTPUT);
Serial.begin(9600);
}
void loop() {
sensorState = digitalRead(sensor1); // Reading status of Arduino digital Pin
if(sensorState == HIGH)
{
Serial.println("HIGH");
}
if(sensorState == LOW)
{
Serial.println("LOW");
}
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
if (digitalRead(sensor1) == HIGH) {
sensorWasLow = true;
}
// This if statement will only fire on the rising edge of the sensor input
if (digitalRead(sensor1) == LOW && sensorWasLow) {
// reset the button low flag
sensorWasLow = false;
// Sensor event here
startTime = millis();
digitalWrite(relay1, HIGH);
relayOn = false;
}
if (millis() - startTime >= sprayinterval && relayOn == false) {
digitalWrite(relay1, LOW);
relayOn = false;
}
}
}
Hello sanch012,
I am interested in helping with this code, but not quite sure exactly how you want this version to work. I would write out the operation in sequence, identifying the state of the system at each change point. this is sometimes referred to as making a state machine definition or a state chart. I find it very useful to do that before writing code, so I am certain what the machine is going to do every time in response to each input state.
COuld you write out what the initial state of the sensor and relay should be then what sensor state change should cause what relay change, and the timing that drives state changes?
Concur with Steve, but getting out of the habit of using delay() unless for very short periods or you actually want to stop the loop operating is a good thing, similarly storyboarding your need on paper aids coding no end!
Hi Steve,
Thanks for your reply.
I have changed my hardware setup and have it working now.
Thanks for your time.
Charles