PulseIn and Pullup pin

Hallo everyone…!

I’m experimenting a little with function PulseIn and input_pullup pins to see a bit how they work…
So, first I did the very simple example with only a button and the LED in pin 13, as shown here:

That of course works very smooth and the reaction of the led when pushing the button is really quick.
Then, I wanted to implement another LED and using PulseIn to make it HIGH when the button is pushed for ex. more than 5 seconds.

Think is that no matter how many different ways I tried, when I implement PulseIn in the code, then LED on pin 13 reacts very very slow… I can push quick the button and it doesn’t even lights…

Here is one of the codes and a picture of the circuit in the attachments.

unsigned long duration;

void setup() {
  Serial.begin(9600);     //start serial connection  
  pinMode(2, INPUT_PULLUP);   //configure pin2 as an input and enable the internal pull-up resistor
  pinMode(13, OUTPUT);
  pinMode(4, OUTPUT);

}

void loop() {
  int sensorVal = digitalRead(2);     //read the pushbutton value into a variable  
  Serial.println(sensorVal);   //print out the value of the pushbutton

  // Keep in mind the pullup means the pushbutton's
  // logic is inverted. It goes HIGH when it's open,
  // and LOW when it's pressed. Turn on pin 13 when the
  // button's pressed, and off when it's not:

  if (sensorVal == HIGH) {
    digitalWrite(13, LOW);
  } else {
    digitalWrite(13, HIGH);
  }
duration = pulseIn(2,HIGH);

if (duration >= 5000000L) {
digitalWrite(4, HIGH);   //turn the LED on pin 4 on
}
}

Why does that happen? Is there a problem that I use the Input_Pullup pin for PulseIn or have I done something stupid?

Thanks in advance!

111.jpg

The default timeout period of pulseIn() is 1 second.
You can add a new timeout as an argument.

.

Yeap, that of cource worked, thanks very much!

I have one more question…
If I have understood right what the pulseIn function does, then I would expect with my code that I should take as result the duration that I have pressed the button in microseconds…

Why do I take only 0 whether or not I press the button (in the Picture is shown first when putton is unpressed and then pressed)?

I have also checked that it takes also value 1 but nothing else by replacing “Serial.println(duration)” with this:

if (duration == 1) {
   Serial.println(duration);
}

It must be again something simple… :confused:

Printing anonymous data sucks. Stop doing that.

Pictures of code suck. Stop doing that.

Using pulseIn() to determine how long a switch is pressed is wrong.

Look at the state change detection example. Use millis() to record when the switch BECOMES pressed. Use millis() to record when the switch BECOMES released.

Use subtraction to determine how long the switch was pressed.

PaulS: Printing anonymous data sucks. Stop doing that. Pictures of code suck. Stop doing that.

You are right, thank you!

PaulS: Using pulseIn() to determine how long a switch is pressed is wrong.

Could you though explain why is that wrong?

Think is, I want to prepare a programm for later, which will count the time between LOW values (or HIGH values when using pullup) on a digital Signal, but I don't have access to that signal yet. Can someone propose an easy idea as to how to experiment?

I wanted to control whether is a HIGH or LOW input, that's why I used a button.

Think is, I want to prepare a programm for later, which will count the time between LOW values (or HIGH values when using pullup) on a digital Signal, but I don't have access to that signal yet.

What kind of signal? One that changes state quickly? As in very short pulses that pulseIn() can measure?

yeap, with data rate 49kbits/s.

But for now, I just want to check that pulseIn can count the duration between LOW values.

Hey guys, sorry for insisting with this thema, i just still don't get it..

I know that simulations are not your favourite thing, but I tried to experiment a little more with pulseIn and some compoments that I don't have in real life.

So, I power an optocoupler with an external power supply and connect its output to a digital pullup Input in Arduino. I have also connected a LED to light when I give 0V for more than 3 seconds.

When I alternate the voltage from 0-4V I can see in the Serial Monitor that the digital input reads HIGH (due to pullup) and when I alternate higher than 4V then it reads LOW. The duration though is always zero.. why?

I would really appreciate it if someone could take a look and explain..

https://123d.circuits.io/circuits/1229085-the-unnamed-circuit/edit

Have you looked at the pulseIn() code? It waits for the pin to change from the specified state to the other state, and then times how long it takes to get back to the specified state.

It is meant to be used with inputs that change on a regular basis, like data from an RC receiver, PWM output, alternating voltage, etc.

It is NOT meant to time how long a human presses a switch or connects a wire or rotates a knob.

The function returns 0 for more than one reason. You need to understand ALL of them AND the units of time that it measures. Not weeks. Not days. Not hours. Not minutes. Not seconds. Not even milliseconds.

THAT should give you a clue as to what kind of signal it is meant to measure.

Yeap Paul, thanks for your patience!

Hallo again! I used the information from PaulS and tried to finally use pulseIn right.

PaulS: It is meant to be used with inputs that change on a regular basis, like data from an RC receiver, PWM output, alternating voltage, etc.

So, I used an pwm output from arduino (pin11) to import it into another digital input (pin2) and then used pulseIn to measure the duration of zeros (HIGH input to pin2 due to pullup).

Think is that duration is always zero.. The text I have in code in case it is not zero is never shown. Here's the code in case you can help me understand.

unsigned long duration;

void setup()
{
  Serial.begin(9600);
  pinMode(2, INPUT_PULLUP);
  pinMode(7, OUTPUT);
  pinMode(11, OUTPUT);
}

void loop()
{
  analogWrite(11, 127);
  int sensorVal = digitalRead(2);     //read the optocoupler value into a variable  
  Serial.println(sensorVal);  
  duration = pulseIn(2, HIGH, 10);

  
  if (duration != 0) {
    
   Serial.print("Duration:");
    Serial.println(duration);
  }
  
  if (duration >= 3000000L) {
  digitalWrite(7, HIGH);   //turn the LED on pin 7 on
}
}

Am I doing again something wrong? Sorry for insisting and thanks again!

I loaded your code. I put a jumper between pin 11 and pin2, on my Arduino Duemilanove. I get alternating 0 and 1 values.

so duration is 0 or 1? shouldn't be the length in microseconds between the ones?

shouldn't be the length in microseconds between the ones?

It is the duration between the time the call is made and the time the pin goes HIGH. That may happen immediately, or it may happen some amount of time later. How much later depends on the frequency of the signal being measured.

You could read the ATMEL datasheet for the Arduino chip that you have, to see what the frequency of the PWM is on pin 11.

You could try changing the duty cycle, to change the amount of time the pin is HIGH or LOW.

duration = pulseIn(2, HIGH, 10);

You are using PWM on pin 11 which is from Timer 2 at approximately 490Hz for a 2ms period. AnalolgWrite(11,127) will generate a 1 ms = 1000 us pulse.

The third parameter in the pulseIn function is microseconds, so you are itming out before the pulse is measured.

If you change the time out you will see the duration printed.

duration = pulseIn(2, HIGH, 2000);

cattledog: If you change the time out you will see the duration printed.

That worked!! Now I see duration!

PaulS: You could try changing the duty cycle, to change the amount of time the pin is HIGH or LOW.

I also played a little with the duty cycle to vary the duration!

Thank you both very very much, you made my night! :)

Hallo again! I think I have a final question, a bit more general.

What I wanted to achieve with this program was to know when the input in pin 2 is HIGH (zero voltage) for more than 3 seconds and when it is, to light a LED.
So I guess then that pulseIn is not the best way, because it won’t give back a duration till it sees a HIGH again. So if for example the pin2 reads the same value for 2 minutes, the LED will light after two minutes and not in the first 3 seconds that that happens.

So then, why don’t use the “traditional” way, where I have a variable that counts the HIGHs and becomes zero when a LOW is read? What are the pros of pulseIn, the speed, the accuracy?

Also, when I remove the cable from pwm for a while and pin2 reads only HIGHs for some time, shouldn’t then the duration be a much bigger number? I see mostly no change, except sometimes a much smaller one… can it be that pulseIn is not so quick in cooperation with the pwm pin?

I hope you understand my questions.

So then, why don't use the "traditional" way, where I have a variable that counts the HIGHs and becomes zero when a LOW is read? What are the pros of pulseIn, the speed, the accuracy?

That was what I suggested in reply #3. You don't need to count anything. The Arduino already counts clock ticks. You simply record when the switch became pressed, or released, as desired. Periodically, check to see if the switch is in the interesting state, and, if so, has it been in that state for the period of interest. If so, do something.

What are the pros of pulseIn, the speed, the accuracy?

It is useful for reading things like RC transmitters that output a signal over and over, and it is the length of the signal that is interesting.

PaulS: That was what I suggested in reply #3. You don't need to count anything. The Arduino already counts clock ticks.

PaulS you were totally right, sorry for not paying attention the first time and many thanks again.. It seems the idea is exactly what I wanted..

The only question is why the value of my variable "time" is so big (for ex. after 4 seconds with zero voltage, i have a time=8000000 and not 4000).

P.S. I used two variables: time and currentTime, because with only one, I couldn't reset the millis and time would just become bigger and bigger.. If I could make my code a bit smarter or efficient, happy to hear about it :)

I only use a cable from pin 2 to 11..

int sensorVal = 0;  //the value that pin 2 reads
int lastSensorVal = 0;  //the value that pin2 read in the previous loop
unsigned long currentTime;  
unsigned long time; //the duration of successive 1s (or HIGHs) -> zero voltage 


void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT_PULLUP);
  pinMode(11, OUTPUT);
  pinMode(13, OUTPUT);
  
}


void loop() {
  analogWrite(11, 191);
  sensorVal = digitalRead(2); 
  Serial.println(sensorVal);


  if (sensorVal == lastSensorVal && sensorVal == HIGH) {
    currentTime=millis();                
    }
  else {
    time=0; 
  }   
  
  lastSensorVal = sensorVal;
  time = time + currentTime;

  if (time != 0) {
    Serial.print("time is: ");
    Serial.println(time);
  }

  currentTime = 0;

  if (time >= 8000000) {  //by experimenting by taking  the cable out, that's approximately 4-7 seconds..
    digitalWrite(13, HIGH);    
  }
}

If you are trying to measure the time that a PWM-driven pin is HIGH or LOW, you will never get anything useful polling. You MUST use interrupts.