Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 14 of 14

Thread: Digital Input Problem

  1. #1
    Senior Member
    Join Date
    Jan 2015
    Location
    France
    Posts
    135

    Digital Input Problem

    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.

    Click image for larger version. 

Name:	buton.png 
Views:	33 
Size:	1.8 KB 
ID:	22317

    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

  2. #2
    Senior Member
    Join Date
    Jan 2015
    Location
    France
    Posts
    135
    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.

  3. #3
    Senior Member
    Join Date
    Jan 2015
    Location
    France
    Posts
    135
    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 by Manu; 11-05-2020 at 06:27 PM.

  4. #4
    Senior Member
    Join Date
    Jan 2015
    Location
    France
    Posts
    135
    Here are scope trace of what I think do this :

    Click image for larger version. 

Name:	Startup.png 
Views:	7 
Size:	18.3 KB 
ID:	22319

    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


    Click image for larger version. 

Name:	PressButton.png 
Views:	7 
Size:	16.7 KB 
ID:	22320

    In this screenshot I play with the button, all operate as expected.

  5. #5
    Senior Member
    Join Date
    Jan 2015
    Location
    France
    Posts
    135
    The last one for today :

    Click image for larger version. 

Name:	power_up.png 
Views:	6 
Size:	17.4 KB 
ID:	22325

    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 ?

  6. #6
    Senior Member
    Join Date
    Jan 2015
    Location
    France
    Posts
    135
    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

  7. #7
    Senior Member
    Join Date
    Mar 2016
    Posts
    261
    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.

  8. #8
    Senior Member
    Join Date
    Jan 2015
    Location
    France
    Posts
    135
    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

  9. #9
    Senior Member
    Join Date
    Aug 2013
    Location
    Gothenburg, Sweden
    Posts
    344
    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.

  10. #10
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,319
    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);
    }

  11. #11
    Senior Member
    Join Date
    Jan 2015
    Location
    France
    Posts
    135
    Thank you Luni,
    I'll try this ASAP

  12. #12
    Senior Member
    Join Date
    Jan 2015
    Location
    France
    Posts
    135
    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

  13. #13
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,319
    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;

  14. #14
    Senior Member
    Join Date
    Jan 2015
    Location
    France
    Posts
    135
    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

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •