Triggering relays with a voltage sensor

Forgive the n00by-ness of this, but I'm brand new to Arduino and coding. My thought process tells me what I want to do is possible, but wanted to ask before I bought any hardware.

I'd like to use a nano, 2 voltage sensors, and an 8-channel relay board to activate certain relays based on what the voltage sensor is reading. I'd like the relays to stay active until the voltage changes to another value or is removed.

I'll be using (2) 0-10v analog signals. All relays should be off if the voltage is 0
Relay 1 active if the voltage1 is between 0.5-2v
Relay 2 active if the voltage1 is between 3-5v
Relay 3 active if the voltage1 is between 6-8v
Relay 4 active if the voltage1 is above 9v

Relay 5 active if the voltage2 is between 0.5-2v
Relay 6 active if the voltage2 is between 3-5v
Relay 7 active if the voltage2 is between 6-8v
Relay 8 active if the voltage2 is above 9v

Is this possible?

Hello dpitalo

Yes.

Post your sketch, well formated, with well-tempered comments and in so called code tags "</>" and schematic to see how we can help.
Have a nice day and enjoy coding in C++.

Start project small.
Focus on getting a basic input working such as a button. Then try getting a basic output working such as a led. Then you can start with the knowledge you have gained to work on the voltage sensor. Work with one component at a time. Plan on paper and use data sheets.

When coding only work on the most simple step you can conceive. Save often and use the save as option to give new iterations a reasonable name.

Assuming you will be using a 5v Arduino, then you will need to first lower the voltage from your input source. You can do this with a simple voltage divider circuit.

image

If you make the 2 resistors 10k, then Vout will be 50% of Vin.

Then in your code...

float voltage1 = analogRead(sensorPin1) * (5.0 * 2) / 1023;

Then you can use an if-else statement to do what you want...

if (voltage1 > 9.0)
  digitalwrite(relay4Pin, HIGH);
else if (voltage1 >= 6.0)
  digitalwrite(relay3Pin, HIGH);
etc.

Did you really mean for all relays to be off if the voltage is above 2.0V and below 3.0V? Like 2.7V?

I did, yes.

I'll be using it with an aquarium controller's 0-10v output. I can define what voltage is output, but I don't know how steady it is yet, so I just gave it a range that I'm guessing will be wide enough to account for any variance and to make sure that if it does drift high or low, there's no chance of it triggering another relay. Further testing will tell me if I can narrow that range.

Thanks!

I'm not great at soldering, so I opted for premade devices.

As I mentioned before, I'm not much of a coder, so I found code for each module and got them to work together. Everything appears to be working as intended, but now I want to know if there's anything I can do to the code that would be better? Best practices, etc.

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
 
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C 
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
 
// Define analog input
#define ANALOG_IN_PIN01 A0
#define ANALOG_IN_PIN02 A3

// Define output pins
#define Relay01 5
#define Relay02 6
#define Relay03 7
#define Relay04 8
#define Relay05 9
#define Relay06 10
#define Relay07 11
#define Relay08 12
 
// Floats for ADC voltage & Input voltage
float adc_voltage01 = 0.0;
float adc_voltage02 = 0.0;
float in_voltage01 = 0.0;
float in_voltage02 = 0.0;
 
// Floats for resistor values in divider (in ohms)
float R1 = 30000.0;
float R2 = 7500.0;
 
// Float for Reference Voltage
float ref_voltage = 5.0;
 
// Integer for ADC value
int adc_value01 = 0;
int adc_value02 = 0;

void setup()
{
  // Setup Serial Monitor
  Serial.begin(9600);
  Serial.println("DC Voltage Test");
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
  {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;); // Don't proceed, loop forever
  }
  display.clearDisplay();
 
  // Define digital pins as OUTPUT
  pinMode(Relay01, OUTPUT);
  pinMode(Relay02, OUTPUT);
  pinMode(Relay03, OUTPUT);
  pinMode(Relay04, OUTPUT);
  pinMode(Relay05, OUTPUT);
  pinMode(Relay06, OUTPUT);
  pinMode(Relay07, OUTPUT);
  pinMode(Relay08, OUTPUT);
 
}
 
void loop() {
  // Read the Analog Input
  adc_value01 = analogRead(ANALOG_IN_PIN01);
  adc_value02 = analogRead(ANALOG_IN_PIN02);
  
  // Determine voltage at ADC input
  adc_voltage01 = (adc_value01 * ref_voltage) / 1024.0;
  adc_voltage02 = (adc_value02 * ref_voltage) / 1024.0;
 
  // Calculate voltage at divider input
  in_voltage01 = adc_voltage01 / (R2 / (R1 + R2)) ;
  in_voltage02 = adc_voltage02 / (R2 / (R1 + R2)) ;

  //Activate Relays based on input voltage
  if (in_voltage01 > 0.5 && in_voltage01 < 2){
    digitalWrite(Relay01, LOW);
  }    
  else{    
    digitalWrite(Relay01, HIGH);
  } 
  if (in_voltage01 > 3 && in_voltage01 < 4.5){
    digitalWrite(Relay02, LOW);
  }
  else{
    digitalWrite(Relay02, HIGH);  
  }
  if (in_voltage01 > 5.5 && in_voltage01 < 8){
    digitalWrite(Relay03, LOW);
  }          
  else{
    digitalWrite(Relay03, HIGH);
  }
  if (in_voltage01 > 9){     
    digitalWrite(Relay04, LOW);
  }
  else{
    digitalWrite(Relay04, HIGH);
  }
     if (in_voltage02 > 0.5 && in_voltage02 < 2){
    digitalWrite(Relay05, LOW);
  }    
  else{    
    digitalWrite(Relay05, HIGH);
  } 
  if (in_voltage02 > 3 && in_voltage02 < 4.5){
    digitalWrite(Relay06, LOW);
  }
  else{
    digitalWrite(Relay06, HIGH);  
  }
  if (in_voltage02 > 5.5 && in_voltage02 < 8){
    digitalWrite(Relay07, LOW);
  }          
  else{
    digitalWrite(Relay07, HIGH);
  }
  if (in_voltage02 > 9){     
    digitalWrite(Relay08, LOW);
  }
  else{
    digitalWrite(Relay08, HIGH);
  }  
               
   // Print results to Serial Monitor to 1 decimal place
  Serial.print("Input Voltage = ");
  Serial.println(in_voltage01, 1);
  
  //Display static text on OLED display
  display.setCursor(2, 2);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.println("Input Voltage 1");

  display.setCursor(2, 33);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.println("Input Voltage 2");

  //Display voltage readings on OLED display
  display.setCursor(50, 13);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print(in_voltage01, 1);
  display.println(" V");
  
  display.setCursor(50, 44); 
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print(in_voltage02, 1);
  display.println(" V");  
  
  display.display();
  delay(500);
  display.clearDisplay();
 
}
  

Your code looks ok.

Maybe one thing I'd change is that you have a lot of repeated logic for each of the 8 relays. You could shorten the code quite a bit if you created a structure that represents a relay... something like...

struct relay
{
  uint8_t pin;
  uint8_t voltage;
  float   minimum;
  float   maximum;
};

You can then create an array of these like this...

relay relays [] = 
{
    5, 1, 0.5, 2.0,
    6, 1, 3.0, 4.5,
    7, 1, 5.5, 8.0,
    8, 1, 9.0, 999.9,
    9, 2, 0.5, 2.0,
   10, 2, 3.0, 4.5,
   11, 2, 5.5, 8.0,
   12, 2, 9.0, 999.9
};

You can then loop through the array instead of coding separately for each relay. Like this...

  for (uint8_t x = 0; x < 8; x++)
    pinMode(relays[x].pin, OUTPUT);

and...


  for (uint8_t x = 0; x < 8; x++)
  {
    if (relays[x].voltage == 1)
    {
      if (in_voltage01 > relays[x].minimum && in_voltage01 < relays[x].maximum)
        digitalWrite(relays[x].pin, LOW);
      else
        digitalWrite(relays[x].pin, HIGH);
    }
    else
    {
      if (in_voltage02 > relays[x].minimum && in_voltage02 < relays[x].maximum)
        digitalWrite(relays[x].pin, LOW);
      else
        digitalWrite(relays[x].pin, HIGH);
    }
  }

Functionally the code is the same as yours... just a lot more concise.

2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.