Digital Input Problem

Status
Not open for further replies.

Manu

Well-known member
Hello,

I currently test an hardware that use Digital Input (3 inputs). I try to use an photocoupler : Renesas PS2801-4

I think I have make mistake with the way I use it because if I set : pinmode (input, INPUT_PULLUP), at startup the input is high.

buton.png

In this schematic, the B pad is put to GROUND with a button, which *should* trigger the LED and put the Teensy input to ground too.

My code use "bounce2" library and have events to identify short press and long press.

Without the photocoupler, if I put the input to ground it behave normal.

But with the photocoupler the behaviour seem inverted.

Can someone point me to my error ?

Thank you,
Manu
 
Look like a code problem too.

If I try to inverse the way I trigger the photocoupler (button before the led, and resistor after the LED), it's behave the same.
 
This is the code :

Code:
#include "Bounce2.h"

#define PIN_BOUTON1 2
#define PIN_BOUTON2 3
#define PIN_BOUTON3 4
#define DEBOUNCE_TIME 5
#define SHORT_PRESS 500
#define LONG_PRESS 1500

#define noEvent    0
#define shortPress 1
#define longPress  2

Bounce debouncer1 = Bounce();
Bounce debouncer2 = Bounce();
Bounce debouncer3 = Bounce();

unsigned long buttonPressStartTimeStamp;
unsigned long buttonPressDuration;
boolean startTimeout = false;
boolean endTimeout = false;
byte event = noEvent;

byte checkButton1()
{
  byte event = noEvent;
  debouncer1.update();
  // Button press transition from HIGH to LOW)
  if (debouncer1.fell())
  {
    buttonPressStartTimeStamp = millis();
    startTimeout = true;
  }
  //if (debouncer1.rose())
  if (debouncer1.rose())
  {
    buttonPressDuration = (millis() - buttonPressStartTimeStamp);
  }
  if (buttonPressDuration > 0 && buttonPressDuration <= SHORT_PRESS)
  {
    event = shortPress;
    startTimeout = false;
    buttonPressDuration = 0;
  }
  if (buttonPressDuration > 0 && buttonPressDuration > LONG_PRESS)
  {
    event = longPress;
    startTimeout = false;
    buttonPressDuration = 0;
  }
  return event;
}

void setup()
{
  Serial.begin(115200);
  while ((!Serial) && (millis() < 500))
  debouncer1.attach(PIN_BOUTON1, INPUT_PULLUP);
  debouncer1.interval(DEBOUNCE_TIME);
  debouncer2.attach(PIN_BOUTON2, INPUT_PULLUP);
  debouncer2.interval(DEBOUNCE_TIME);
  debouncer3.attach(PIN_BOUTON3, INPUT_PULLUP);
  debouncer3.interval(DEBOUNCE_TIME);
}

void loop()
{
  event = checkButton1();
  switch (event)
  {
  case shortPress:
    doShortPressButton1();
    break;
  case longPress:
    doLongPressButton1();
    break;
  }

  event = checkButton2();
  switch (event)
  {
  case shortPress:
    doShortPressButton2();
    break;
  case longPress:
    doLongPressButton2();
    break;
  }

  event = checkButton3();
  switch (event)
  {
  case shortPress:
    doShortPressButton3();
    break;
  case longPress:
    doLongPressButton3();
    break;
  }
}

At the first startup, "doLongPressButton1()" is executed, while neither button is pressed.
If I unplug and replug power quickly, the module *sometime* start as expected.

Apart this, the button operate as it should.

Weird...
 
Last edited:
Here are scope trace of what I think do this :

Startup.png

Yellow : the main power (+12,5V)
Magenta : the voltage at button (0V when not pressed)
Blue : the voltage at digital pin at teensy side (pullup activated)
Green : the voltage at the output of DC/DC converter that feed the Teensy 3.2 (switcher)
Timebase : 100ms.

At startup the digital pin take more 700ms to initialise, witch I think is the problem


PressButton.png

In this screenshot I play with the button, all operate as expected.
 
The last one for today :

power_up.png

Yellow : the main power (+12,5V)
Magenta : Teensy 3v3 Regulator
Blue : the voltage at digital pin at teensy side (pullup activated)
Green : the voltage at the output of DC/DC converter that feed the Teensy 3.2 (switcher)
Timebase : 100ms.

At startup the digital pin still take more 700ms to initialise, while one can notice that the teensy 3.2 get power since the early beginning.

Do you think that this is a code problem ?
 
Last test I've done is to place button init at the very beginning of the setup().

Doing this highly reduce the pin pullup thing to 350ms. but the result is still the same
 
You don't include all of your code but it looks like a start up issue. The input to the teensy pin should be high when the button is not pressed. I don't setting of pinMode() in your setup code. Do that before you initialize the debounce code or have your code take into account that you may see an unpress (rising) event first.
 
Hi,

I have found the problem, but have hard time to figure how to solve it.
In my setup function, I have this :

Code:
  for (int i = 0; i < 5; i++)
  {
    analogWrite(PIN_LED, LED_BRIGHTNESS);
    delay(100);
    analogWrite(PIN_LED, 0);
    delay(100);
  }

This make a LED to flash 5 time. Removing this code from setup and the module power-up as expected, each time.

I can move this in the loop, but it's useless to have it there since it will add a condition each loop that will be true only one time over all the time the module is powered.

Is there a way to drive LED asynchronously so the code won't stop on it ?

thank you,
Manu
 
This led blinking is probably pretty, but it is not easy to help when the code you run when testing is not the code you share in the forum :(

Also if you want to be 100% sure of having the pullup on the optocoupler active at startup you can simply add an external pullup resistor.
 
Is there a way to drive LED asynchronously so the code won't stop on it ?

Sure, here a solution using the TeensyTimerTool. BlinkAsync takes the number of blinks and the blink period. It then starts the blinking in the background. You can see that the sketch already prints while it still blinks.

Code:
#include "TeensyTimerTool.h"
using namespace TeensyTimerTool;

// -------------------------------------------------------------------
//Best to copy the class definition into LED.h

class LED
{
 public:
    LED(unsigned _pin)
        : pin(_pin), t1(TCK)  // use a cheap software (TCK) timer for this task
    {}

    void blinkAsync(unsigned cnt, milliseconds delay)
    {
        pinMode(pin, OUTPUT);

        total = 2 * cnt;
        current =0;
        t1.begin([this] { doBlink(); }, delay);
    }

 protected:
    void doBlink()  // timer callback function
    {
        digitalToggle(pin);
        if (++current >= total) t1.stop();
    }

    unsigned pin, current, total;
    PeriodicTimer t1;
};

// --------------------------------------------------------------------

LED led(13);


void setup()
{
    while (!Serial && millis() < 1000);  // wait for the PC to connect 

    led.blinkAsync(5, 100ms);            // Start blinking 5 times with 100ms delay in between
}

void loop()
{
    Serial.println(millis());            // do something to demonstrate that the blinking is asynchronous
    delay(50);
}
 
Thank you Luni, this do exactly what I want. I had 2 simple functions to LED.h :

Code:
#ifndef LED_h
#define LED_h

class LED
{
public:
    LED(unsigned _pin)
        : pin(_pin), t1(TCK)
    {
    }

    void blinkAsync(unsigned cnt, milliseconds delay)
    {
        pinMode(pin, OUTPUT);

        total = 2 * cnt;
        current = 0;
        t1.begin([this] { doBlink(); }, delay);
    }

    void activate()
    {
        pinMode(pin, OUTPUT);
        if (digitalRead(pin) == LOW)
            digitalToggle(pin);
    }

    void desactivate()
    {
        pinMode(pin, OUTPUT);
        if (digitalRead(pin) == HIGH)
            digitalToggle(pin);
    }

protected:
    void doBlink()
    {
        digitalToggle(pin);
        if (++current >= total)
            t1.stop();
    }

    unsigned pin, current, total;
    PeriodicTimer t1;
};

#endif
 
Glad it works. In case you are interested, here some remarks:

Code:
  void activate()
    {
        pinMode(pin, OUTPUT);
        if (digitalRead(pin) == LOW)
            digitalToggle(pin);
    }

I don't quite understand this logic. activate will always end up with pin HIGH.
So, why not simply do a
Code:
  void activate()
  {
        pinMode(pin, OUTPUT);
        digitalWriteFast(pin,HIGH);
  }

Same for deactivate.

You can also place the pinMode into the constructor. Then you don't have to call it each and every time and it would make your LED class even smaller. (I know that people say that one shouldn't access hardware in the constructor but I never ran into problems with pinMode in a constructor).

Last but not least, you can also replace your include guards

Code:
#ifndef LED_h
#define LED_h
...
#endif

by a simple
Code:
#pragma once

on top of the file (but that's a matter of taste...)

EDIT: ---------------------------------
I'd also add a
Code:
void operator=(uint8_t state) const
{
   digitalWriteFast(pin, state);
}

Then you can simply say
Code:
led = HIGH; 
led = LOW;
 
I do a test because I was thinking that it's useless to activate a pin if it's already done. But maybe I'm wrong ? I don't know...
Anyway, thank you
 
Status
Not open for further replies.
Back
Top