Making car window roll automatically using an ATtiny85

Hey all! I have a project I would like to do for a car I’m restoring. I want to use an ATtiny85 (if it’s powerful enough) to make the dome and courtesy lights (converted to LEDs) fade on and off when the door opens and closes. I also want to add a pushbutton somewhere on the drivers side that, after it’s pressed, will roll the window down when the door opens, and back up when it closes.

If I wire it up the way I have it in the schematic, then when the regular window switch (not shown in the schematic, but it just reverses polarity to the motor) is pressed, it’ll create a direct short. That’s obviously not good. My best idea so far is to make the regular window switch an input for the microcontroller, then just control the windows directly from the microcontroller. Other than that, I can’t think of any way to isolate my circuit from the factory circuit. That’s why I’ve come here. Here is a link to a schematic of the factory wiring, the window circuit is in the middle of the picture.

Here is my sketch (I received help from some great people on the Programing Questions sub-forum). The pushbutton inputs are coded for pulldown resistors, but the build will use the internal pull-up resistors.

/* This sketch has two purposes and is designed for use in a car.  The first 
 purpose of this sketch is to fade a set of LEDs on when the car door is opened,
 then fade them back off when the car door is closed.  The second purpose of
 this sketch is to make a push button that when pressed, the door window will
 roll down when the door is opened, then roll back up when the door is clossed.*/

// Define the pins the pushbutton and door switches are on
const int buttonPin[] = {
  2, 4, 6};
// Define the pins that will ultimately control the window rolling up or down
const int windowPin[] = {
  7, 8};
// Define the pin the LEDs to fade are on
const int ledPin = 3;
// Define the amount of time the fade delay will be
const int fadeDelay = 15;
// Define the brightness increase interval
const int fadeAmount = 3; 
// Define the delay for button debounce
const int debounceDelay = 15;
// Define the amount of time the windows will spend rolling up and down.
//rollUpDelay will be longer to ensure window rolls all the way up.
const int rollUpDelay = 3000; 
const int rollDownDelay = 2000; 

//Variables that will change

// Variable to track the current state of the push button, in an array the size
//of buttonPin.
boolean currentButtonVal[sizeof(buttonPin)/sizeof(buttonPin[0])];
// Initialize variables to define and store the debounced switch values. doorSwitch
//is in an array the size of buttonPin
byte doorSwitch[2];
byte windowButton;
// Define the inital brightness of the LED. Starts off, or 0
int brightness = 0;
// Define the inital "previous time" variable for comparison with millis().
//Will start at 0 and be redifned every time fadeDelay has passed. 
unsigned long previousTime = 0;
// Define the inital comparison time for the debounce function.  Has the same
//purpose as in "previousTime."
unsigned long lastDebounceTime = 0;
// Initialize a variable that is set to millis() every time a button state is 
//toggled. In an array the size of buttonPin[], and is unique to each button.
unsigned long toggleTime[sizeof(buttonPin)/sizeof(buttonPin[0])];
// Define the inital state for a button toggle. This value will be reversed
//when a button is pressed. In an array the size of buttonPin[], and is unique
//to each button.
boolean buttonToggle[sizeof(buttonPin)/sizeof(buttonPin[0])] = {};
// Initialize a variable to track if the rollWindow function should be active
boolean rollWindowToggle;
// Initialize a variable to detect if the rollWindow button should finish
boolean continueFunction; 

void setup () {
  for (int i = 0; i < sizeof(buttonPin)/sizeof(buttonPin[0]); i++) {
    pinMode (buttonPin[i], INPUT);
  }
  for (int i = 0; i < sizeof(windowPin)/sizeof(windowPin[0]); i++) {
  pinMode (windowPin[i], OUTPUT);
  }
  pinMode (ledPin, OUTPUT);
}


void loop () {
  // Create a variable to store the millis() value this time through the loop
  unsigned long currentTime = millis();

  // Define variables to debounce and keep track of the different switches
  doorSwitch[0] = debounce(0); 
  doorSwitch[1] = debounce(1);
  windowButton = debounce(2);

  // If either car door is open, then fade the LEDs.  If both car doors are
  //closed, then fade the LEDs off.
  if (doorSwitch[0] == HIGH || doorSwitch[1] == HIGH) {
    if (currentTime - previousTime > fadeDelay) {
      previousTime = currentTime;
      brightness = brightness + fadeAmount;
      // Limit the fade amount from going above 255
      brightness = min(brightness, 255);
      analogWrite (ledPin, brightness);
    }
  }
  else {
    if (currentTime - previousTime > fadeDelay) {
      previousTime = currentTime;
      brightness = brightness - fadeAmount;
      // Limit the fade amount from going bellow 0
      brightness = max(brightness, 0);
      analogWrite (ledPin, brightness);
    }
  }

  // If windowButton has been toggled to true (on) and the door switch is HIGH,
  //then make rollWindowToggle true. This allows the rollWindow function to 
  //begin. If buttonToggle is not true (on), then make rollWindowToggle false.
  if (buttonToggle[2]) { //Start function when buttonToggle is true
    if (doorSwitch[0] == HIGH) { //If the door is open
      rollWindowToggle = true; //Let the rollWindow function execute
    }
  }
  else rollWindowToggle = false;

  // Test to see if rollWindowToggle was toggled on while the door was open,
  //if it was, then reset toggleTime so the window will still roll the correct
  //amount of time. continueFunction must not equal true so toggleTime does not
  //continuously reset if rollWindowToggle gets toggled while the function is
  //in progress.
  if (!rollWindowToggle && doorSwitch[0] == HIGH && !continueFunction) {
    toggleTime[0] = millis();
  }

  // Iniate rollWindow function if either requirment is meant. continueFunction
  //tracks if the function should continue, even if rollWindowToggle is 
  //toggled to false.
  if (rollWindowToggle || continueFunction) {
    // Iniate rollWindow function, doorSwitch and toggleTime indicate which
    //switch will activate the function. currentTime passes the variable assigned
    //to millis().
    rollWindow(0, currentTime);
  }
}


void rollWindow (int thisSwitch, unsigned long currentTime) {
  // If statements checks if door is open or closed and performs apropriate function
  // If the door is open
  if (doorSwitch[thisSwitch] == HIGH) {

    // Define the state of continueFunction to indicate that the function is
    //in progress and should continue until it is complete
    continueFunction = true;

    // If the rollDownDelay time has passed, stop rolling the window. If not,
    //roll the window down. Make windowPin[1] LOW to ensure the window will
    //not try to roll down and up at the same time.
    if (currentTime - toggleTime[thisSwitch] > rollDownDelay) { //If roll up time has passed:
      digitalWrite (windowPin[0], LOW); //Stop rolling the window down
    }
    else {
      digitalWrite (windowPin[1], LOW); //Make sure the window is not rolling up
      digitalWrite (windowPin[0], HIGH); //Make the window roll down
    }
  }
  // If the door is closed:
  else {
    // If the rollUpDelay time has passed, stop rolling the window, reset
    //buttonToggle[2] to false, and make continueFunction false to indicate
    //the function is complete. If rollUpDelay time has not passed, then
    //roll the window up and make windowPin[0] LOW to ensure the window will
    //not try to roll up and down at the same time.
    if (currentTime - toggleTime[thisSwitch] > rollUpDelay) { 
      digitalWrite (windowPin[1], LOW); 
      buttonToggle[2] = false; 
      continueFunction = false;
    }
    else {
      digitalWrite (windowPin[0], LOW); 
      digitalWrite (windowPin[1], HIGH);
    }
  }
}

// Create a debounce function to debounce the switches, start the toggleTime
//timer, and toggle the buttonToggle variable. Return the value current.
byte debounce(int thisButton) {
  // Take a reading of the switch pin and store it in a local variable.
  byte current = digitalRead(buttonPin[thisButton]);
  // If the reading does not equal the current recorded state of the button,
  //wait the debounceDelay, then take another reading of the currenet value and
  //begin the toggle timer.  If the state of the switch is high, then toggle
  //buttonToggle.
  if (currentButtonVal[thisButton] != current) {
    if (millis() - lastDebounceTime > debounceDelay) {
      current = digitalRead(buttonPin[thisButton]); 
      toggleTime[thisButton] = millis(); 
      if (current == HIGH) {
        buttonToggle[thisButton] = !buttonToggle[thisButton];
      }
    }
  }
  // Record the curent button value and return current
  currentButtonVal[thisButton] = current;
  return current;
}

Here is the schematic. This is my first real schematic, so I’m open to suggestions on how I can improve it.

You may note that the "Auto" function on car window controls only applies to the driver's door. Do you know why that is?

As to the relay wiring, that is dead simple. You must intercept the wires (Lt Blu & Tan) from the control switch to the motor and put one relay in series with each wire so that it switches that motor wire from the control switch instead to the 12V supply (pink). We had a fellow here a little while back who absolutely could not get the idea of relays in series into his head. :smiley:

And yes, the fact that you have a circuit diagram, indicates it is a very old car indeed.

Hi, can I make a suggestion, for safety reasons you DO NOT make the window wind up function automatic.
They are very strong motors and if anything gets jammed in the window it could be possibly fatal if not debilitating.

You will find that car manufacturers do not provide this facility in their cars for this reason.

The delayed/fading interior lights though is a very good idea, even a dash mounted button to trigger a delayed/fade would be good.

Tom..... :slight_smile:

TomGeorge:
Hi, can I make a suggestion, for safety reasons you DO NOT make the window wind up function automatic.

I was trying to be a little more subtle than that! :smiley:

Q2 and Q3 are back-to-front...usually comes from drawing the circuit(or part of) upside down.
Best to stick to conventional methods, much easier to read.

Not sure what you mean about "dead short" but mostly, dc motors used in a reversing arrangement are fed from 2 relays or microswitches when in the parked position, the motor terminals are connected together and to ground. Usual to also draw the relays (or microswitches) in the "parked" or "no-voltage" position for the same reason as circuit drawing above.

for a car I'm restoring customising.

The set up for the relay is a little off. The coil of the relays should not be connected to 12vdc, you will want to use a 5volt relay that can handle the load of your window motors. The linked diagram shows the WDO circuit is 30amps, key on power. You will want to use at least 12 gauge wire, but 10 gauge would be better between new relays and existing wires. You could also use automotive DIN relays that handle larger current, you would just need to control the auto relay coil through a 5v relay on the arduino.

I am assuming you want this to work with the key off so you will need a 30 amp fused constant power from somewhere. You could try the Pwr/Acc circuit, BUT it also powers your locks, so you could potentially blow the fuse with the windows halfway up. You may need to add a new 30 amp fused circuit from the battery or a main fuse.

Back to using just the 5v relays:

Since you want both windows to go up and down together, consider using two DPDT relays, each side of a relay controls both up or both down controls.

The coils with the flyback diodes just need to be connected to the arduino.

Next to get the desired switching on the 12 volt load side of the relay you will want to wire it like this:

Up relay - cut Lt.Blu
Common - Lt.Blue to motor
Normally Closed - Lt.Blue from door switch
Normally Open - 12volt constant power

Down relay - cut Tan
Common - Tan to motor
Normally Closed - Tan from door switch
Normally Open - 12volt constant power

That does one window. Just do the same with two more relays for the other side or use DPDT relays.

The only problem is that if the door is opened while the key is still on and the window goes up; if someone unwittingly pushes the door switch you might melt those wires. But it will work if the button doesn't get pressed while the arduino is pulling in those relays.

I hope this helps, the relay set up above can also be used to power linear actuators like power door lock actuators.

Good Luck, Arduino in the car is great fun. I am working on integrating an Arduino into my car to control a remote starter module.

You haven't quite thought this through. :smiley:

FutureScience:
The set up for the relay is a little off. The coil of the relays should not be connected to 12vdc, you will want to use a 5volt relay that can handle the load of your window motors.

No, pretty much dead right actually. You do want to use 12V relays, switched by the transistors (wired correctly as per that previous correction). Regulating the power to the relays is a very bad idea as not only is it inefficient (by 60%) but it would put the relays on the supply line for the MCU which is just asking for trouble! {So often seen here if you read back a ways.}

FutureScience:
you would just need to control the auto relay coil through a 5v relay on the arduino.

Again, very bad idea. In fact, you could control an "Auto" relay with a suitable Logic level FET.

FutureScience:
I am assuming you want this to work with the key off so you will need a 30 amp fused constant power from somewhere.

Good point.

FutureScience:
Back to using just the 5v relays:

Or not. :astonished:

FutureScience:
Since you want both windows to go up and down together, consider using two DPST relays, each side of a relay controls both up or both down controls.

I think you actually meant DPDT relays for this suggestion.

FutureScience:
The coils with the flyback diodes just need to be connected to the arduino.

No.

FutureScience:
Up relay - cut Lt.Blu
Common - Lt.Blue to motor
Normally Closed - Lt.Blue from door switch
Normally Open - 12volt constant power

Down relay - cut Tan
Common - Tan to motor
Normally Closed - Tan from door switch
Normally Open - 12volt constant power

Correct. Probably doesn't matter that the relay contacts and the switches are powered from different circuits.

FutureScience:
The only problem is that if the door is opened while the key is still on and the window goes up; if someone unwittingly pushes the door switch you might melt those wires. But it will work if the button doesn't get pressed while the arduino is pulling in those relays.

Not if you wire it correctly - as you actually described.

FutureScience:
Good Luck, Arduino in the car is great fun. I am working on integrating an Arduino into my car to control a remote starter module.

Hope you understand my advice about the relays.

Paul__B:
You haven't quite thought this through. :smiley:

Hope you understand my advice about the relays.

I agree...main problem as I said before Q2 and Q3 are back-to-front and the righthand relay is shown in the energised position
(this would make motor run continuously without any external control)
Other than that, relay arrangement in the drawing is fine.

Thanks for all the replies!

Paul__B:
You may note that the “Auto” function on car window controls only applies to the driver’s door. Do you know why that is?

As to the relay wiring, that is dead simple. You must intercept the wires (Lt Blu & Tan) from the control switch to the motor and put one relay in series with each wire so that it switches that motor wire from the control switch instead to the 12V supply (pink). We had a fellow here a little while back who absolutely could not get the idea of relays in series into his head. :smiley:

And yes, the fact that you have a circuit diagram, indicates it is a very old car indeed.

I’ll admit I don’t know why it’s only on the driver side, though I would assume it’s for safety reasons, as indicated by you and TomGeorge. Presumably, the driver is (theoretically) always in his seat and could interrupt the window if needed?

At any rate, there may be a slight misunderstanding of what I’m attempting to achieve. I’m not trying to make the window roll all the way down or up automatically (like newer cars do when you hold the switch for a couple seconds), but rather roll slightly down when the door is opened and roll back up when the door is closed. This is to make the door close easier, because it has pillarless doors (the window seals directly to the weatherstripping on the car body) which on an 80’s car with top notch American build quality, can be somewhat difficult to shut. Some newer cars also have this feature, though there may be some sort of safety switch that stops the window if it detects it’s pushing too hard. Regardless, the window will only crack a few inches, and only when the door is opened, so it should be fairly safe. I’m also only doing this to the drivers side, at least for now.

I’ll also admit that it took me a little while to understand what you were trying to describe with putting the relay in series, but now that I see it, it makes perfect sense! I believe this is what you were trying to describe? Also note that I fixed the relay so it displays the NC contacts correctly.

bluejets:
Q2 and Q3 are back-to-front…usually comes from drawing the circuit(or part of) upside down.
Best to stick to conventional methods, much easier to read.

Not sure what you mean about “dead short” but mostly, dc motors used in a reversing arrangement are fed from 2 relays or microswitches when in the parked position, the motor terminals are connected together and to ground. Usual to also draw the relays (or microswitches) in the “parked” or “no-voltage” position for the same reason as circuit drawing above.

In my original schematic, If I had pressed the factory window switch, it would create a direct short to ground through my relay. This new schematic should fix that issue. This car doesn’t use relays to control the window motors, it uses beefy switches instead. The principle is the still the same though, the switch reverses polarity to the motor.

Thanks to everyone! Especially Paul__B for your thorough reply.
FutureScience, thanks a bunch for your post too, you really helped me understand the relay wiring. I agree that Arduino in the car can be quite fun!

If using 12v relays, would you ground the arduino to the vehicle chassis? Or isolate the Arduino completely from the vehicle system since they are different voltages?

I do not totally understand what can be done with FETs, I have only used transistors so far.

So from the above schematic; envisioning the correct orientation of Q2 & Q3, the transistors base is energized at 5v from arduino? The collector is seeing 12v? And the emitter is then goes to the relay coil then should be grounded to chassis ground and arduino ground? Please check the updated diagram, I think the relay coils shouldn't go to the load contacts, but to ground.

I was mistaken, I did mean to use DPDT relays.

FutureScience:
If using 12v relays, would you ground the arduino to the vehicle chassis? Or isolate the Arduino completely from the vehicle system since they are different voltages?

I do not totally understand what can be done with FETs, I have only used transistors so far.

So from the above schematic; envisioning the correct orientation of Q2 & Q3, the transistors base is energized at 5v from arduino? The collector is seeing 12v? And the emitter is then goes to the relay coil then should be grounded to chassis ground and arduino ground? Please check the updated diagram, I think the relay coils shouldn't go to the load contacts, but to ground.

I was mistaken, I did mean to use DPDT relays.

You are correct, my bad! The transistors are suppose to be connected to ground, then the 5v signal from the Arduino (or ATtiny) will "turn on" the transistor, completing the relay coil circuit. The collector will "see" the load from the relay, and the emitter will be attached to ground. The 12v supply here supplies power for the motor load, and the 12v required to turn on the relay.

From everything I've seen with transistors, you connect the grounds of your different voltages together. In this case, that would mean the car ground gets connected to the Arduino ground. I don't know if you need some sort of protection, like a diode, in between the Arduino ground pin and the body ground. The voltage regulator I'm using (LM2940CT) is designed for in car use, and has reverse batter protection, but I'm still unsure if I need protection on the ground side.

Here is the updated schematic. The only thing different is the transistors are connected properly to ground, as you pointed out, and I moved the transistors down to better illustrate current flow.

Awesome schematic.

I am not sure either about exact grounding, if it is no problem I will have to adjust one of my designs to use transistors and 12 volt relays like you did.

Good Luck with the installation.