Controlling a DC Motor by Light Sensor for Specific Time

The idea was to automate my window blinds so that they open during the day and close at night however the rod of my mini blinds rotate multiple times when opening or closing so a servo motor won’t work as rotation is limited to 180 degrees. A stepper motor is ideal but I couldn’t find one in time and I simply wanted to play.

Searching the web for a sketch that would make a DC motor stop/start was hard so I decided to post this code is case someone else has the same idea. Disclaimer: This is my very first sketch so it’s not perfect hopefully this will be helpful to other newbies if you want to stop start a DC motor for a specified time based on a light sensor. There might be a better way to do this but this is the best I could come up with.

Reference:

See new code on post below.

I don’t think that this does quite what you expect:-

const byte speed = 255;   // Change this (0-255) to control the speed of the motors 
...
...
...
digitalWrite(AIB, speed);

Or this:-

// Set status based brightness.
   if (photocellReading < 350) {  // Night
     state = false;       
    }
    else if (photocellReading < 900) {  // Day
     state = true; 
    }

I didn’t look any further, except for one thing. It’s never a good idea to power a motor directly from the Arduino’s 5V rail.

Thanks OldSteve. It was probably not a good idea to post my very first sketch online. I’ve had some time to fine tune the code. There was a few critical errors with the first version as OldSteve pointed out especially with status (day/night). I’ve included EEPROM updates this will save the day/night status in case of power failure.

The main purpose of this code is to control a DC motor without encoder, run it for a specified time and stop, if light conditions change turn on the motor again. As a noob I couldn’t find code on these forums that allowed me to do this. Before yesterday I had zero experience with C/C++, YouTube is an amazing learning platform.

// Description:
// ----------------------------------
// Run a DC Motor for a specified time once a light sensor triggers a day/night event. 
// Possible applications includes automatically opening & closing blinds.
//
// Components Used:
// ----------------------------------
// Arduino UNO
// DC Motor H-Bridge L9110 Controller 
// Light Sensor
// 10K Pulldown Resistor
// DC Motor
// ----------------------------------
#include <EEPROM.h>

int photocellPin = A0;     // The cell and 10K pulldown are connected to a0
int photocellReading;      // The analog reading from the sensor divider
int addr = 0;              // EEPROM Address

// Swap these to change direction on DC motor
int AIA = 9;        // (PWM) pin 9 connected to pin motor controller (left) 
int AIB = 10;       // (PWM) pin 5 connected to pin motor controller (right)

int light = 0;                          // Day (1) & Night (2) Status
int prestate = (EEPROM.read(addr));     // Status saved in EEPROM in case of power failure 

// SETUP
void setup() {
  Serial.begin(9600);     // Debug
  pinMode(AIA, OUTPUT);   // Set pins to output
  pinMode(AIB, OUTPUT);
  lightsensor();          // Get a light reading and set status
}

// Set Day (1) & Night (2) Status
void lightsensor() {       
  
  photocellReading = analogRead(photocellPin);      // Light sensor reading 
  
// Set status based brightness.
   if (photocellReading > 300) {        // Day
    light = 1;                          
    Serial.println("Status: Day");      // Debug
    } 
    else if (photocellReading < 200) {  // Night
    light = 2;
    Serial.println("Status: Night");    // Debug 
    }
delay(300000);                          // Delay 5 minutes between readings change to 1000 (1 sec) for testing     
}

// Open Blinds, 
void openblinds()                      
{
  digitalWrite(AIA, HIGH);                      // Trigger motor controller
  digitalWrite(AIB, LOW);
  delay(2500);                                  // Time motor spins (eg. 2500 = 2.5 seconds)
  EEPROM.update(addr, 1);                       // Update EEPROM to remember status incase of power failure
  light = 1;                                    // Set status to Day (1)
  Serial.println("Blinds: Open, EEPROM: 1");    // Debug
// Stop Motor Loop
  while (light == 1) {
  digitalWrite(AIA, LOW); 
  digitalWrite(AIB, LOW);
  Serial.println("Motor Stopped: DAY");    // Debug
  lightsensor();                           // Run light test again if light changes the motor will activate 
  }
}
// Close Blinds
void closeblinds()                     // Close blinds, swap polarity on your DC motor to set correct direction
{
  digitalWrite(AIA, LOW);              // Trigger motor controller
  digitalWrite(AIB, HIGH);
  delay(2500);                         // Time motor spins (eg. 2500 = 2.5 seconds)
  EEPROM.update(addr,2);               // Update EEPROM to remember status incase of power failure
  light = 2;                           // Set status to Night (2)
  Serial.println("Blinds: Closed, EEPROM: 2");  
// Stop Motor Loop
  while (light == 2) {
  digitalWrite(AIA, 0);                    // Trigger motor controller
  digitalWrite(AIB, 0);
  Serial.println("Motor Stopped: DAY");    // Debug
  lightsensor();                           // Run light test again if light changes the motor will activate 
  
  }
}
// LOOP
void loop() {

  while (light == prestate) {          // On boot check EEPROM if status is the same don't engage motor
  digitalWrite(AIA, LOW); 
  digitalWrite(AIB, LOW);
  lightsensor();                       // Run light test
  } 
    if (light == 1){                   // If the light status changes execute these
      openblinds();                    // Open
    }
    else (light == 2);{
      closeblinds();                   // Close
    }
  delay(5000);
}

Your code here...

    if (light == 1){                   // If the light status changes execute these
      openblinds();                    // Open
    }
    else (light == 2);{
      closeblinds();                   // Close
    }

the use of if-else statement is not correct. You should use "else if" instead of "else". And no semicolon right after the test bracket, i.e. (light == 2)

You may want to read this... https://www.arduino.cc/en/Reference/Else

:)

Alex, there are some pretty serious shortcomings in your code and method of implementing your blinds controller. I can only assume that you haven't actually built it and tested it over a period to see if it works as you expected.

Using a DC motor for this purpose will only work effectively if you have limit switches at each end of the motor's travel, to let you know when the blinds are fully open or fully closed. You'll have nothing but trouble doing it by timing alone.

The next point that comes to mind - you save the "light/dark" state in EEPROM just in case of a blackout when it only takes 100uS to read the state with your light sensor anyway, yet you overlook the possibility of the power interruption happening in the midst of either opening or closing the blinds. That's another reason why you need limit switches, and then you won't need to save anything to EEPROM. Also, what if you've decided to manually half-open the blinds? Then the timing goes right out the window.

Another thing I noticed is that you use three states for your light/dark state flag, 0, 1 and 2, when in your context a boolean and two states would be far more appropriate. I'd personally declare a 'boolean' variable and call it something like "isDark", then make it either 'true' or 'false' after reading the light sensor. (Much easier to keep track of than 0, 1, 2 when reading your code, too.)

Then your 'if...else' statement mentioned by ckho would look more like this:-

if(isDark)
    closeBlinds();          // Close the blinds.
else
    openBlinds();           // Open the blinds.

Note the use of "camelCase" to make the code more readable, too. ie The "B" in "closeBlinds" and "openBlinds" is upper-case.

Another lesser point - it's a good idea to declare all values that will not change during execution as constants, to save RAM space. When declared as variables, they chew up precious RAM. This applies to pin numbers too, so your pin declarations would look more like this:-

// Constants:-
const byte photocellPin = A0;       // The cell and 10K pulldown are connected to A0.

// Swap these to change direction on DC motor:-
const byte AIA = 9;                 // (PWM) pin 9 connected to pin motor controller (left).
const byte AIB = 10;                // (PWM) pin 5 connected to pin motor controller (right).

Except... it's better to use names that clearly describe the function of the pins, so instead I'd do this:-

// Swap these to change direction on DC motor:-
const byte leftMotorPin = 9;      // (PWM) pin 9 connected to pin motor controller (left).
const byte rightMotorPin = 10;    // (PWM) pin 5 connected to pin motor controller (right).

And although you call them "PWM" pins, you never actually use 'analogWrite()' with them, only 'digitalWrite()' with 'LOW' or 'HIGH'.

I haven't gone over your code any further, because this is already enough to keep you busy re-designing/rewriting, but I'll keep an eye open for updates in this thread. I'll be interested to see how you progress. ;)

alexharper: It was probably not a good idea to post my very first sketch online.

No, it's a good idea. People have been able to point out issues in your code and you can / did learn from it.