Shop OBEX P1 Docs P2 Docs Learn Events
Using buttons in an automotive environment. — Parallax Forums

Using buttons in an automotive environment.

eagletalontimeagletalontim Posts: 1,399
edited 2014-04-22 22:02 in Propeller 1
I have a project that requires the use of several buttons in a vehicle. Since switching from the SX28, I have had strange issues with buttons on the Prop. Using the SX, I would have 1 5v power output wire that would connect to all buttons, then one wire from each button feeding back to the circuit. To make things easier and use less wire, I have decided to go with a 10K pull up resistor attached to the "button pin" on the prop. Each "button pin" has it's own 10K resistor. All the resistors are connected to the 3.3V rail. This would enable the ability for the buttons to be wired to my circuit with 1 wire, then the other pin of the button tied to the vehicle chassis.

What I am having an issue with is occasionally, a random button circuit is triggered without a button being pressed. Would adding a small cap to the prop pin to ground help prevent this from happening? How could I determine the capacitor value? Would a non polarized ceramic cap work, or would I need to use a polarized cap?

Comments

  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-04-13 22:15
    You should do software debouncing of the buttons; cleans up contact bounce and can eliminate false positives if done well. Remember that the automotive environment is electrically noisy, and long wires are acting like antennae.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2014-04-14 00:32
    If software debouncing is not what you want to do, you can add a one-shot for push buttons via a chip such as a CD4047.

    Or if you have an actual switch that needs debouncing, there are ways using simple logic chips.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2014-04-14 04:22
    I have the debounce working properly I believe. My issue is, the buttons may not be touched for 20 or 30 minutes, but a button press may still be triggered automatically.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2014-04-14 04:36
    Long wires act as antenna, shield them and ground at only one end
  • eagletalontimeagletalontim Posts: 1,399
    edited 2014-04-14 05:38
    Is there any other way besides a shielded wire? The stock ecu and wiring did not have a shielded wire and it the button contacts went to ground.
  • BeanBean Posts: 8,129
    edited 2014-04-14 05:53
    You could try a stronger pull-up resistor. Maybe a 2.7K instead of a 10K.

    Bean
  • CRST1CRST1 Posts: 103
    edited 2014-04-14 06:01
    Agree, 10K resistor is only 330micro amps. 1K would be 3.3mamp. Noise in automotive circuits can be bad. The only time current would be flowing is during a button press. Could even go a low as 500 ohm which would be 6.6 mA
  • max72max72 Posts: 1,155
    edited 2014-04-14 06:13
    Besides the pullups you can try to increase noise immunity.
    If you can use two wires twist them and ground one besides the board while the other goes to the input pin.
    There is some very nice stuff about that in the low level measurement handbook from keithley. The PDF is downloadable for free.
    Massimo
  • CogSaverCogSaver Posts: 17
    edited 2014-04-14 06:30
    Have you measured the duration of the false "button presses" ? If it's high frequent (e.g. low duration) your software should only look for pulses longer than this.

    I have seen debounce logic that only filters out repeated pulses from "ringing" but not the initial short duration pulse that is in fact noise.

    A human pressing a button is typically of much longer duration anyways and we are still talking fractions of seconds so resonse is normally not an issue.


    CogSaver
  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-04-14 08:07
    Stronger pullup and better debouncing.

    Here's an example of a routine (it blocks, so be aware of that) to debounce multiple inputs.
    pub debounce(ms) | btns, t
    
      btns := %1111                                         ' "arm" inputs
    
      t := cnt
      repeat ms
        waitcnt(t += clkfreq/1000)                          ' wait 1ms
        btns &= !ina[BTN4..BTN1]                            ' invert for active-low          
    
      return btns
    
  • BigFootBigFoot Posts: 259
    edited 2014-04-14 09:46
    You could try running the ground from the buttons back to the cpu board. The chassis ground is good for higher current loads, but it can be noisy for low current signals.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2014-04-14 17:30
    I did think about that, but some users like to use the stock buttons on the steering wheel that are already tied to ground. I will try the stronger resistor and maybe even make a function that counts the time passed that a button is pressed. If the button is not pressed long enough, it fails the button press. Too much of a delay would cause it to not detect quick button presses as well. Guess I have some testing to do.
  • T ChapT Chap Posts: 4,223
    edited 2014-04-14 17:37
    Can you put an opto fet, so that the button only turns on power to the LED. The opto is placed very close to the processor. For a simple debounce, I like to just read the pin twice in a row with small delay between:
    If ina[but] == 1
      waitcnt(100_000 + cnt)
         If ina[but] == 1
           do stuff
    

    Another option could be to check for 0 in between the 1's:
    If ina[but] == 1
      waitcnt(50_000 + cnt)
         If ina[but] == 0 
           return 0
         If ina[but] == 1
             waitcnt(50_000 + cnt)
             If ina[but] == 0 
                return 0
             If ina[but] == 1
                return 1
    
  • eagletalontimeagletalontim Posts: 1,399
    edited 2014-04-14 19:21
    T Chap wrote: »
    Can you put an opto fet, so that the button only turns on power to the LED. The opto is placed very close to the processor. For a simple debounce, I like to just read the pin twice in a row with small delay between:
    If ina[but] == 1
      waitcnt(100_000 + cnt)
         If ina[but] == 1
           do stuff
    

    Another option could be to check for 0 in between the 1's:
    If ina[but] == 1
      waitcnt(50_000 + cnt)
         If ina[but] == 0 
           return 0
         If ina[but] == 1
             waitcnt(50_000 + cnt)
             If ina[but] == 0 
                return 0
             If ina[but] == 1
                return 1
    

    That is a good idea. I did not think about checking twice for a button press. Thanks for that tip!
  • T ChapT Chap Posts: 4,223
    edited 2014-04-14 19:26
    If the button is providing ground for an opto or transistor near the processor, you will eliminate a lot of antenna. In the case of testing for a button, I always assume that any given 1 can be noise, but noise will not maintain a constant 1 (or > 3.3V / 2) level. So if you test for a several successive 1's, then it greatly reduces false triggers.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-04-14 20:15
    Another option could be to check for 0 in between the 1's:

    That's what my debounce routine does; if there's a drop-out during the scan window the button is not counted as pressed/closed. This process seems to eliminate high-speed transients.
  • edited 2014-04-14 22:34
    I use a long for each button being monitored and I always use active low button circuits. Each monitor long is initialized to $FFFFFFFF. Each button is polled and its state is rotated into the long on each pass through a 1 ms duration loop. When / if the monitor long value equals $00000000 I know that that button has been pressed and debounced. After the action is completed I just have to wait for the first button up state and reinitialize the monitor long to $FFFFFFFF. The advantage to this approach is that buttons that settle quickly will automatically have a shorter response time.

    I don't think I've done a very good job of describing it but it works for me.

    Sandy
  • eagletalontimeagletalontim Posts: 1,399
    edited 2014-04-20 18:52
    Ok, I have the debounce code in place, but I still can't get it working right. Now, button presses are accepted randomly no matter what I do. Please remember this is in a dirty environment so buttons may not always have a perfect connection. I do NOT want to add anything to my circuit if possible to fix this issue. I would prefer it be software change rather than hardware change. I have changed the resistor values to 2.2K which was the closest I had to 2.7K that is recommended above.

    Is there a recommended debounce time?

    Here is the debounce code :
    User_Setting3 := 100    ' I have tried everything between 10 and 100.  Still not stable...
    
        if ina[upbutton] == 0
          btndown := debounce(User_Setting3, upbutton)
          if btndown == 1
            ' Do stuff here
          
        if ina[downbutton] == 0
          btndown := debounce(User_Setting3, downbutton)
          if btndown == 1
            ' Do stuff here
    
    PUB debounce(ms, button) | downcount
      downcount := 0
      repeat ms
        pause(1)
        if ina[button] == 0
          downcount++
    
      if ms - downcount =< ms / 2     ' if button down count is at least 1/2 the debounce delay, return as good
        return 1
      else
        return 0
    
  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-04-20 19:05
    Your check logic may be in the wrong place. Here's my version of your debounce routine; it will early escape if the threshold (ms/2) is met.
    pub debounce(pin, ms) | dbtimer, t
    
      dbtimer := 0
    
      t := cnt
      repeat ms
        waitcnt(t += clkfreq/1000)
        ifnot (ina[pin])
          if (++dbtimer => ms/2)
            return 1
        else
          dbtimer := 0
    


    Remember -- as I was recently reminded -- if you don't specify a return value a method will return 0, hence we don't have to spell this out.

    My code looks for ms/2 consecutive button presses; your version does not hence may be allowing noise to pass.
  • photomankcphotomankc Posts: 943
    edited 2014-04-21 13:44
    I use a long for each button being monitored and I always use active low button circuits. Each monitor long is initialized to $FFFFFFFF. Each button is polled and its state is rotated into the long on each pass through a 1 ms duration loop. When / if the monitor long value equals $00000000 I know that that button has been pressed and debounced. After the action is completed I just have to wait for the first button up state and reinitialize the monitor long to $FFFFFFFF. The advantage to this approach is that buttons that settle quickly will automatically have a shorter response time.

    I don't think I've done a very good job of describing it but it works for me.

    Sandy


    This is the approach I use as well. It's easy to implement without blocking too.
  • BigFootBigFoot Posts: 259
    edited 2014-04-22 10:32
    Back in the 80's I was designing automatic welding systems. Welding is a very noisy enviroment and and we used a hex de-bouncer chip
    (MC14490) that used counters for de-bouncing the buttons. Just as you guys are describing with software, it was very effective. It is a cool
    chip with an internal clock that could be used for clocking other logic.
  • infoinfo Posts: 31
    edited 2014-04-22 22:02
    Most unexplainable problems are caused by power supply. Small electronics should be powered through diode or bridge rectifier with good size capacitor. The diode prevents voltage drop due to A/C or motors turning on and off, and the big capacitor provides the extra power at the moment of voltage drop in the vehicle electrical system.

    Power supply failure (cracked pcb traces, etc) can make your computer crash (blue screen of death) showing memory or parity error and it is not the memory. It is power supply.
Sign In or Register to comment.