[SOLVED !!!] Car windows opening by remote control

Dear all,

that's my first post on the forum ^_^. I'm based in France. I'm new in the community, new with Arduino, and... new with C...

Sorry for my message, it will be a little bit long... (well, it is long as I'm lost)

I have at home a 10$ arduino nano v3 from China, seems to be good quality (from powermcu.com)

I would like to use my Arduino for a basic function... but I'm a little bit lost.

My car is equiped with central locking and electric windows. I would like to open a window from my remote control which has only one button. The only way to do that is by something like "if I click 3 times on the button into 3 seconds the window will open".

So it means if I open-close-open within 3 seconds the window will open. I can detect opening by connecting on the positive terminal of the lock-motor. The lock motor has two terminals let say A and B. A is + and B is - when opening and A is - and B is + at closing.

So it means that if two positive pulse are detected within 3 seconds on an Arduino input I send a pulse to an output (this pulse will be connected on the window-command).

Ok so I belive the code is very simple and I thought the way to do that was to use attachInterrupt(), as I'm really newbe with this I tried to understand this command by using a very simple example I found on the web about attachInterrupt(), but... my Arduino freeze with this code (I mean after few contact on +Vcc and the input: data are not sent anymore to the COM port):

:drooling_face:

volatile int countPulse=0; 

void setup()   { 

Serial.begin(9600); 

attachInterrupt(0, toDo, RISING); 

void loop(){
  
void toDo() {

countPulse=countPulse+1;

Serial.print("TOTAL COUNT = ");
Serial.println(countPulse);

}
}

So what goes wrong, is attachInterrupt() a bad way to do what I want ?

I don't ask you for the complete code (even if for me it will only take few lines !!!), it's not a good way to begin but is there anyone of you who can give me the right direction to begin ?

Thank you very much, merci beaucoup :P

First problem is that you have your interrupt routine within loop(){}. They should be separate so you have

void loop() {
  // loop stuff
}

void todo() {
  // interrupt stuff
}

If that doesn't work (and I haven't used attachInterrupt() myself) I think you will need to consider whether the Arduino is getting a suitable signal on the pin. As far as I can see interrupt 0 uses pin 2. If you are connecting to a car it will presumably be 12v (and probably with much higher voltage spikes - a car is a very demanding environment) and the Arduino can't accept more than 5v. You will also need to ensure that the low voltage is low enough, but not negative. You will probably need to isolate the Arduino pins from the car voltages altogether.

...R

When you untangle the two routines, make sure the serial.print stuff is in loop, not the interrupt servicing routine. Interrupts are best handled quickly. Serial port is slow.

Thank you Robin and wildbill for your answer.

OK so the fisrt example was bad, I do not need the serial.print so I removed it of my project :wink:

So I found (by trying and reading the web) how to stick a relay(1s.) after 2 rising on an input :slight_smile: and then put the counter to 0.
Yes I know it’s really basic but I learn slowly… :blush:

int output = 13;

volatile int countPulse=0;

void setup()   {

attachInterrupt(0, interrupt, RISING);
pinMode(output, OUTPUT);

}

void loop(){

if (countPulse == 2) {
digitalWrite(output, HIGH);
delay(1000);
digitalWrite(output, LOW);
countPulse = 0;
}

}

void interrupt() {

countPulse=countPulse+1;

}

The problem is now to stick the relay ONLY IF the time between the 2 rises is not more than X seconds (3 or 4s). If the time is more we put the rise counter to 0 (like a timeout or operation canceled). :slight_smile:

I believe the only way is to use milis() but I miss the logical sens to do it…
I know how to explain it but I don’t know how to write it in Arduino langage…

At fisrt Interrupt: catch time and store it !
At second Interrup: catch time again, compare it to the first recorded. If the difference is < 3s. stick the relais 1s, and then put the CountPulse to zero to be able to do it again later. If difference is > 3s. Put CountPulse at zero…

Another question, is using “Interrupt” a must ? Because sometime my Arduino freeze during tests… is there another way to proceed compatible with what I need ?

Did any one of you has already made something similar ?

Thank you for your help. In any case I continue to try to write it from my side… ]:slight_smile: Antoine.

Last thing about Robin’s remark about voltage level: no problem the input will be managed with an optocoupler: http://electronics.stackexchange.com/questions/43498/how-can-i-use-a-12-v-input-on-a-digital-arduino-pin

Yeah, there's no need to use an interrupt here, and may be confusing if you are just learning. Your loop function will be running very quickly (if you take out the delay :) ) and you can keep a variable that records the last state of the line, if the last state was low and the new state is high, then that must be a rising edge (depending upon the noise etc. on the line, you may want to de-bounce it a bit with a short delay). In order to reset your counter after 3s, you can keep a record of the time when you get the first rising edge, then compare that with the "current" time, and when 3s has passed, reset the counter.

Thank you Toby, you're right, I just found many projects with time usage without Interrupt, just a loop as you just said.

I continue to read other projects to have the good direction. But I'm far from the result :D

Thank you for your answer... ;) I will now try to write without Interrupt with a fresh new project...

OK so I wrote something… but it doesn’t work… for sure, because I’m a beginner :drooling_face:

My code contains certainly many errors however what I want to do is very simple…

To remember you the goal of the project is:

if the Arduino counts 2 rise on the input within 3s. the output is HIGH during 4,5s. If the time between 2 rise is over 3s. do nothing but get ready to do what I said previously (in the future…)

My code is a mix of Debounce example and things I wrote myself… :slight_smile:

Thank you all ]:slight_smile:

const int InputPin = 2;     // input pin
const int OutputPin = 13;   // output pin

int OutputState = LOW;      // current state of the output pin
int InputState;             // current reading from the input pin
int lastInputState = LOW;   // previous reading from the input pin
int PositiveINCount = 0;    // total positive pulse counter

long lastDebounceTime = 0;  // last time the output pin was toggled
long debounceDelay = 50;    // debounce time
long totalTime = 0;         // total time since the first pulse

void setup() {
  pinMode(InputPin, INPUT);
  pinMode(OutputPin, OUTPUT);

  // set initial output state
  digitalWrite(OutputPin, OutputState);
}

void loop() {
  // read the state of the input into a local variable:
  int reading = digitalRead(InputPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise:  

  // If the input changed, due to noise or input rising:
  if (reading = HIGH) {
    // reset the debouncing timer
    lastDebounceTime = millis();
    // store the time in the totalTime
    totalTime = millis();
    
  }
 
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != InputState) {
      InputState = reading;

      // only ++ counter if Input is HIGH
      if (InputState == HIGH && PositiveINCount < 2 && totalTime < 3000) {
        PositiveINCount++;
      }
      
      else if (InputState == HIGH && PositiveINCount == 2 && totalTime < 3000) {
        digitalWrite(OutputPin, HIGH);
        // 4,5s. to close the Window 
        delay(4500);
        digitalWrite(OutputPin, LOW);
        PositiveINCount = 0;
      }
      
      else (InputState == HIGH && totalTime > 3000); {
        PositiveINCount = 0; 
      }
    }
  }
}

Ok, It's a valiant effort ;) but I think you could do with a bit of help structuring the code. You created some good sounding variables at the top, but then never used them :) Here's some pseudocode that should help you get it working:

int InputState;                   // current reading from the input pin
int lastInputState = LOW;   // previous reading from the input pin
int pulseCount=0;
unsigned long firstPulse=0;

void loop(){
    get current state of input pin -> InputState
    If (InputState HIGH and lastInputState LOW){
        wait 10ms for debounce (tweak this value as appropriate, about 1/4 of pulse length should be good)
        if current state of input pin is still HIGH, then not noise{
            Increment Pulse Counter
            If Pulse Counter is 1: Set firstPulse to current time
            If Pulse Counter is 3: Set Ouput HIGH, Wait 4.5s, Set Output LOW, Reset Pulse Counter
        }
        else Set InputState to LOW
    }
    
    lastInputState=InputState;

    if currentTime>firstPulse+3s -> Reset Pulse Counter
}

Hello Tobby, thanks to you I believe I'm not far from the end :open_mouth:

I've translated what you sent, but still not working, I don't worry because this langage is new for me, and I need to learn... unfortunately the code does not support error unlike a foreign language where you can make some mistakes remaining understandable XD

I believe something goes wrong with IF imbrications but logic sens is still missing, I will work on this with other projects and a lot of time (I hope !)

Any idea with this new code ? Thank you, regards !!!

const int InputPin = 2;     // input pin
const int OutputPin = 13;   // output pin

int InputState;             // current reading from the input pin
int lastInputState = LOW;   // previous reading from the input pin
int pulseCount = 0;
unsigned long firstPulse = 0;
unsigned long MaxTime = 3000; 

void setup() {
  pinMode(InputPin, INPUT);
  pinMode(OutputPin, OUTPUT);
}

void loop() {
  
  int IntputState = digitalRead(InputPin); //get current state of input pin -> InputState
    
    if (InputState == HIGH && lastInputState == LOW){
      delay(50); //wait 50ms for debounce
    }
        if (InputState == HIGH){ //current state of input pin is still HIGH, then not noise
            pulseCount++;
        }
            if (pulseCount == 1){
              firstPulse = millis(); //Set firstPulse to current time
            }
              if (pulseCount == 3){
                digitalWrite(OutputPin, HIGH);
                delay(4500);
                digitalWrite(OutputPin, LOW);
                pulseCount = 0; //Set Ouput HIGH, Wait 4.5s, Set Output LOW, Reset Pulse Counter
              }
      else {
          InputState = LOW;
          }
    
    lastInputState = InputState;

    if (millis() > firstPulse + MaxTime){
      pulseCount = 0;
    }
      
}

Why does your code say "inputstate = LOW"?

Inputstate is what you have obtained with a digitalRead. Setting it to LOW seems illogical.

Can you describe the result you are getting and the result you would like to get?

...R

I've just changed around some of the braces in the if loops, look at them carefully and let me know if it makes sense.

const int InputPin = 2;     // input pin
const int OutputPin = 13;   // output pin

int InputState;             // current reading from the input pin
int lastInputState = LOW;   // previous reading from the input pin
int pulseCount = 0;
unsigned long firstPulse = 0;
unsigned long MaxTime = 3000; 

void setup() {
  pinMode(InputPin, INPUT);
  pinMode(OutputPin, OUTPUT);
}

void loop() {

  int IntputState = digitalRead(InputPin); //get current state of input pin -> InputState

  if (InputState == HIGH && lastInputState == LOW){
    delay(50); //wait 50ms for debounce
    if (digitalRead(InputPin) == HIGH){ //current state of input pin is still HIGH, then not noise
      pulseCount++;
      if (pulseCount == 1){
        firstPulse = millis(); //Set firstPulse to current time
      }
      else if (pulseCount == 3){
        digitalWrite(OutputPin, HIGH);
        delay(4500);
        digitalWrite(OutputPin, LOW);
        pulseCount = 0; //Set Ouput HIGH, Wait 4.5s, Set Output LOW, Reset Pulse Counter
      }
    }
    else {
      InputState = LOW;
    }
  }

  lastInputState = InputState;

  if (millis() > firstPulse + MaxTime){
    pulseCount = 0;
  }
}

@Robin2: The reason for adding the InputState=LOW is for when it detects that the pulse was just noise so it sets it to LOW so that lastInputState is LOW in the next iteration. I suppose it's not really necessary in this case, but it would be needed for detecting the falling edge.

:) huuummm not better...

Nothing hapens when I push my test buton on D2 input...

There was a simple typo (first line of loop): int In[u]t[/u]putState = digitalRead(InputPin); It didn't cause a compiler error because you had declared InputState (spelled correctly) globally at the top. Take out the declaration in loop, so that line should just be:

InputState=digitalRead(InputPin);

I've tested this now and it works perfectly (if you want it to do what I think you want it to)

If I was trying to use the Arduino to detect edges (or highs or lows) caused by external devices the last thing I would do is try to tamper with that data from within my program. If you are getting noisy readings deal with it by averaging or ignoring readings, not by generating artificial data.

...R

tobyb121: @Robin2: The reason for adding the InputState=LOW is for when it detects that the pulse was just noise so it sets it to LOW so that lastInputState is LOW in the next iteration. I suppose it's not really necessary in this case, but it would be needed for detecting the falling edge.

It's not generating artificial data, in fact it's the opposite, the only way to get to that bit of code is to read a rising edge, wait 50ms and then read a low pulse, so the input state is LOW. If that line wasn't there InputState would be left HIGH, so lastInputState would be HIGH, and the next time it entered the loop InputState would be LOW, lastInputState would be HIGH, and so that would be recognised as a falling edge, which is incorrect. I admit this is a very crude noise rejection algorithm but it works. If you want to detect falling edges that line, or code to that effect, is needed.

Toby XD XD XD !!!!!!!!! You've made my day !!!!! It works really fine :stuck_out_tongue_closed_eyes: (I just replace 3 by 2 because I need 2 rise to activate the output).

Now in the future and with new project (if I find new ideas to use an Arduino) I will reread myself several times. My error was too stupid !!!

I really thank you for your help and without you I believe I would have need several hours to get a good result (but it's a good way to learn I agree).

I hope to come again soon, with more knowledges :cold_sweat: Thank you again !

So the code used is finally:

const int InputPin = 2;     // input pin
const int OutputPin = 13;   // output pin

int InputState;             // current reading from the input pin
int lastInputState = LOW;   // previous reading from the input pin
int pulseCount = 0;
unsigned long firstPulse = 0;
unsigned long MaxTime = 3000; 

void setup() {
  pinMode(InputPin, INPUT);
  pinMode(OutputPin, OUTPUT);
}

void loop() {

  int InputState = digitalRead(InputPin); //get current state of input pin -> InputState

  if (InputState == HIGH && lastInputState == LOW){
    delay(50); //wait 50ms for debounce
    if (digitalRead(InputPin) == HIGH){ //current state of input pin is still HIGH, then not noise
      pulseCount++;
      if (pulseCount == 1){
        firstPulse = millis(); //Set firstPulse to current time
      }
      else if (pulseCount == 2){
        digitalWrite(OutputPin, HIGH);
        delay(4500);
        digitalWrite(OutputPin, LOW);
        pulseCount = 0; //Set Ouput HIGH, Wait 4.5s, Set Output LOW, Reset Pulse Counter
      }
    }
    else {
      InputState = LOW;
    }
  }

  lastInputState = InputState;

  if (millis() > firstPulse + MaxTime){
    pulseCount = 0;
  }
}

]:D

hi there,

Can you share the electronic circuit for me?