View previous topic :: View next topic |
Author |
Message |
FFT
Joined: 07 Jul 2010 Posts: 92
|
Floating input pin issue [solved] |
Posted: Sat Jan 08, 2022 7:10 am |
|
|
Hello,
I just realized that I made a mistake to leave 3 button input pins floating.
PIC's Inputs are connected to buttons which are tied to 3.3V over resistors, the other pins of the buttons are tied to PIC's input pins.
So when the buttons is not pushed, input pin stays floating and I get wrong parasitic button push signals..
Connection:
PIC input -----o‾o----/\/\/\/----- 3.3V
Resistor is 680 R
I use 18LF14K50
The input pins are;
- RC1/AN5/C12IN1-/INT1/VREF-
- RB5/AN11/IOCB5/RX/DT
- RB7/IOCB7/TX/CK
I can add resistors externally but I already have many PCBs assembled and I look for a software based solution.
Question;
Is it possible to solve the issue using other functionality of those pins?
Any idea would help.
Thanks!
Last edited by FFT on Mon Jan 10, 2022 6:59 am; edited 2 times in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Sat Jan 08, 2022 7:43 am |
|
|
Pins B5, and B7 both have software programmable internal pull ups. So on
these pins just enable them. port_b_pullups(0b10100000);
However the problem here is these are pull ups, so you can't tell this from
the button pushed state.
Port C does not offer these, so really does need an external resistor.
There have been historic 'cheat' ways of testing a pin by pulsing it high, and
then releasing and testing immediately, but all have issues like producing
massive spike current on the supply (if the button is made when it is pulsed),
and are very unreliable.
If the pins are wired as you show (very strange layout), then simply pulse
the pins low before testing.
Code: |
output_low(PIN_B5);
delay_us(10);
output_float(PIN_B5);
delay_us(1);
if (input_state(PIN_B5)==1)
//Here button is pushed
|
Personally, leave the pins all driven high when you are not testing. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9241 Location: Greensville,Ontario
|
|
Posted: Sat Jan 08, 2022 7:52 am |
|
|
Unless I'm seeing it wrong, from your diagram, you actually need pull down resistors not pullups, so Mr. T.'s suggestion won't work.
As shown, you expected the PIC pin normally to be low, then when the button is pressed, the pin sees the +3 volts, through the 680r resistor.
If the connections to the 3 pushbuttons are close to a ground , adding 'pulldown' resistors should be easy. |
|
|
FFT
Joined: 07 Jul 2010 Posts: 92
|
|
Posted: Sat Jan 08, 2022 9:27 am |
|
|
Yeah, I need pull-down resistors.
I just tried to have very long debounce time and seems it worked!
I incremented a variable when pin is high and zeroed it when pin is low,
after a threshold I accept that the button is pressed.
That was my actual code but the debouce was 30 ms. So I made it 1 second and it works properly. It didn't get false push within 2 hours time.
Actually my idea was to select the pin as ADC, so maybe I didn't need pull-down resistor for an ADC pin.. But long debounce seems resolved the issue. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9241 Location: Greensville,Ontario
|
|
Posted: Sat Jan 08, 2022 10:04 am |
|
|
Works now.'in the lab'..... but change in temperature and humidity will make it fail again. Also any EMI can look like a '1'.
You really should use a proper,reliable pulldown circuit. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Sun Jan 09, 2022 6:17 am |
|
|
Yes, as I said:
Quote: |
However the problem here is these are pull ups, so you can't tell this from
the button pushed state.
|
Thew wiring really is completely stupid. You must have had the brain switched
off when this was done.
Do what I suggested, and drive the pins low all the time. Then release this,
wait a tiny moment, and test the pin. Then switch it back to driving low.
This means that what you have is a pin capacitance (with it's tracks), being
driven 'high' by the resistor if the button is made. Assume the input has
something like 15pF capacitance, so the time constant to drive up to Vih
will then be perhaps 0.5uSec. Unless you have very massive EMI, this is
not going to charge the pin to this level in this sort of time.
It's a poor solution, but should work reliably. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9241 Location: Greensville,Ontario
|
|
Posted: Sun Jan 09, 2022 7:56 am |
|
|
Yes, Mr. T's software solution will work but adding code to compensate for very poor hardware design, is bad. To have a very reliable product, you need very good hardware.
Adding just 3 resistors shouldn't be a huge problem. |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Sun Jan 09, 2022 10:31 am |
|
|
temtronic wrote: | Adding just 3 resistors shouldn't be a huge problem. |
It is if there are 15,000 assemblies with this shortcoming piled up in the back of the shop. |
|
|
FFT
Joined: 07 Jul 2010 Posts: 92
|
|
Posted: Sun Jan 09, 2022 11:02 am |
|
|
ARM have internal pull-downs, PIC have not. The confusion comes from there.
I have many assemblies and I don't want to solder that much resistors as @newguy mentioned.
I will add the resistors on the next production.
Very big debounce time really works for now, tested for 30+ hours with EMI existing env.
I will add the output_low suggestion of @Ttelmah just before reading the inputs.
I think this will be enough for now.
Thank you so much. |
|
|
FFT
Joined: 07 Jul 2010 Posts: 92
|
|
Posted: Sun Jan 09, 2022 4:35 pm |
|
|
Ttelmah wrote: | Do what I suggested, and drive the pins low all the time. Then release this,
wait a tiny moment, and test the pin. Then switch it back to driving low.
This means that what you have is a pin capacitance (with it's tracks), being
driven 'high' by the resistor if the button is made. Assume the input has
something like 15pF capacitance, so the time constant to drive up to Vih
will then be perhaps 0.5uSec. |
Hi again, can you describe the idea by code please?
I mixed it up a bit since I'm using fast IO, set_tris_a and output_low concept.
Do you mean setting the pin as input using set_tris_a by releasing it?
This is what I got;
Code: |
#use fast_io(A)
// # initial state
set_tris_b(0b11111110); // Button pin is output
output_low(ButtonPIN);
......
// # in the loop
//output_float(ButtonPIN); // releasing it?
set_tris_b(0b11111111); // Button pin is input
delay_us(5);
int state = input(ButtonPIN);
set_tris_b(0b11111110); // Button pin is output
output_low(ButtonPIN); |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jan 09, 2022 5:35 pm |
|
|
Here is how I did it once. I'm reading several bits on Ports B and D.
This was done with a 16F877 type PIC.
Code: |
// The opto-sensors are active high, with 1k pullups providing the high level.
// The normal, non-activated state for the sensors is a logic low level.
// If a sensor cable falls off, the lines on the PIC processor will float.
// We are seeing false sensor "hits" when this happens. The following
// code tries to protect against that happening. (You can force some
// false hits by pulling the cable on the main board, and then touch the
// connector pins with your finger. If you're displaying the last known
// sensor on your PC, then you'll see false hits).
// Set latches on ports B and D = 0, ahead of time.
port_b = 0;
port_d = 0;
// Then configure ports B and D as all outputs. This will drive the
// pins low in 30 ns.
set_tris_b(0);
set_tris_d(0);
// Give the low level outputs some time to discharge whatever capacitive
// charge may exist on the pins. Testing shows that this takes 30 ns.
delay_us(10); // A larger delay doesn't hurt.
// Configure ports B and D as all inputs. They will "float" low initially,
// because we just pre-charged the pins to a low level.
// The effects of this may vary, depending on whether the cable fell off
// an opto-sensor board or the main board.
set_tris_b(0xff);
set_tris_d(0xff);
// Do a short delay, which allows the pullup resistor on the opto-board
// (one which is still connected) to raise the level up to +5v.
// Testing shows that this takes 500 ns max.
delay_us(1);
// Now read the ports.
low_bits = port_b;
mid_bits = port_d;
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9241 Location: Greensville,Ontario
|
|
Posted: Sun Jan 09, 2022 7:05 pm |
|
|
If you can get a copy of Microchip's 'Tips and Tricks' or whatever the book was called, (probably online at their website ??) they show, in assembler' how to do it. It'd be simple to re-code into 'C'.
The original books are now 20 ? years old but have a wealth of info on how to efficiently program PICs. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Mon Jan 10, 2022 1:10 am |
|
|
Just use output_float, and drive:
So for B5:
Code: |
//Set the pins low and drive them at boot:
output_drive(PIN_B5); //This sets TRIS to 0 on the pin
output_low(PIN_B5); //pin is now driven low
//then when you want to test the pin:
output_float(PIN_B5); //pin is now set as an input
delay_us(1); //wait 1uSec
state=input_state(PIN_B5); //read the pin level
output_drive(PIN_B5); //set the pin back to being driven low
|
|
|
|
FFT
Joined: 07 Jul 2010 Posts: 92
|
|
Posted: Mon Jan 10, 2022 2:26 am |
|
|
Ttelmah wrote: | Just use output_float, and drive:
So for B5:
Code: |
//Set the pins low and drive them at boot:
output_drive(PIN_B5); //This sets TRIS to 0 on the pin
output_low(PIN_B5); //pin is now driven low
//then when you want to test the pin:
output_float(PIN_B5); //pin is now set as an input
delay_us(1); //wait 1uSec
state=input_state(PIN_B5); //read the pin level
output_drive(PIN_B5); //set the pin back to being driven low
|
|
Is this code working on FAST_IO mode?
Quote: | The tristate register is updated unless the FAST_IO mode is set on port A |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Mon Jan 10, 2022 3:16 am |
|
|
Yes.
The way it works:
input/output set TRIS for standard_io, but not for fast_io.
drive/float work whatever the I/O mode.
So you see, for the output_low, I have to have both the output_low, and the
drive command to set the tris.
The manual looks as if it is wrong for the output_drive command.
If you look at the generated assembler (with fast_io selected), you get:
Code: |
.................... output_drive(PIN_B5); //set TRIS to drive the pin
005C: BCF TRISB.RB5
.................... output_low(PIN_B5); //pin is now driven low
005E: BCF LATB.LATB5
....................
.................... //then when you want to test the pin:
.................... output_float(PIN_B5); //pin is now set as an input
0060: BSF TRISB.RB5
.................... delay_us(1); //wait 1uSec
0062: BRA 0064
0064: BRA 0066
0066: NOP
....................
.................... state=input_state(PIN_B5); //read the pin
0068: CLRF state
006A: BTFSC PORTB.RB5
006C: INCF state,F
.................... output_drive(PIN_B5); //set the pin back to being driven low2
006E: BCF TRISB.RB5
|
|
|
|
|