Wiring switches to PCF8575 Inputs

avr_fred:
How am I beating around the bush? I told you how to fix it. Twice. You’ve yet to ask any specifics, rather you tell me I’m wasting my time writing useless posts.

Oh well, I guess it’s true what they say. You can show a programmer their own buggy code but you can’t make them fix it.

You answered your own question, you haven't shown anything. I have a specific problem listed in the the OP but you haven't provided a specific answer. Instead you say to read the datasheet and rewrite the test program from scratch. Since I know of nothing to change, the new program will be the same as the old one.
It is very difficult to ask specific question about general and vague statements.

I know the Pxx pins are "quasi-bidirectional". It listed on the first page of the datasheet.

The reply

avr_fred:
The output ports are "quasi-bidirectional". Read the datasheet again. Your answer is in there.

doesn't show anything because if I had seen the answer I would not have started this thread.

And the other reply

avr_fred:
There’s your answer. Compare what you said with what your “simple” test code does. Start with a blank sketch and simplify your test code. The absolute minimum number of lines using your own understanding stated above.

does nothing for me because the sketch reads inputs and writes outputs. So without a specific change to be made, I don't have or see anything that needs to be changed.

You obviously know or think you know what is wrong, but you haven't been specific about stating it. This conversation is now six posts long without any no new information. I wonder how many more before something useful and enlightening is posted?

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Can you post a picture of your project so we can your component layout?

Thanks.. Tom.. :slight_smile:

Hi,
Can you please run this code and tell us what the serial monitor displays.

 // --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// Version 6, November 27, 2015.
//    Added waiting for the Leonardo serial communication.
// 
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//

#include <Wire.h>


void setup()
{
  Wire.begin();

  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}


void loop()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) 
    {
      Serial.print("Unknown error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}

Thanks.. Tom.. :slight_smile:

Hi,
Can I suggest you look at this link, I know its a Destructible, but the guys explanation and inplementation seems to be valid.

Including sending commands to setup inputs to the IC.

Tom... :slight_smile:

@TomGeorge, I will assume TLDR the whole thread. No problem, I will summarize.

Super short summary:
I can read the inputs and outputs but it requires a direct connection to Vcc to read a 1 input.

Standard length summary:
I can read the inputs and outputs. I am aware of the I2C scanner. It has been a staple in my toolbox since I got my first I2C LCD many years ago. I don't need to rerun the I2C_Scanner. I can read the inputs and outputs. I know the address of the board is 0x23. I can read the inputs and outputs. The test circuit is already described. Barebones. Not worth the time to draw a schematic. I can read the inputs and outputs.

Five wires and one pullup resistor:
A4/A5 to SDA/SCL (pull-up resistors on-board)
5V to Vcc
GND to GND.
The 5th wire the jumper being used to make the connection to toggle the input signal.

Did I mention I can read the inputs and outputs? The problem is that it requires a direct connection to 5V in order to read a 1. It would be preferable to be able to use a pull-up resistor so the current draw from the regulator is current limited in the event of a short circuit. I can see the board. I can read the inputs. I can set the outputs.

I read through the link (again, I have seen it during my own research) and compared that program to mine. All the same commands are used. I can read the inputs and outputs from the board, but cannot use the pullup resistors as described in that link or in the datasheet to provide a 1 as an input. Only a direct connection to Vcc provides a 1 input.

@avr_fred thinks there is something wrong in the code and something in the datasheet but has yet to say what or where and so far the Easter egg hunt has been fruitless.

That instructable does the same thing as the OP’s program and it will behave the same with same erroneous result.

I’ve been trying to get the OP to actually do something different, like starting with a bank sketch and doing the absolute minimum to read a byte from the device. I’ve asked nicely. He simply resists and rants that I’ve said nothing. The routine is getting old. He who refuses to do what is suggested has no business asking for help. It’s rude.

I could also suggest that he place a 10k pot between VCC and and the input pin and measure the current required to detect a high input. Then, compare that with the datasheet for minimum input current required.

The bottom line is that OP has submitted a test program that creates the problem. It obscures what is read and written to the device. The instructable is at least clear. It does exactly the wrong thing, clearly explained in the datasheet, to read an input.

Under the right circumstances, I’ll hand a newbie an answer. But, this is an experienced user that is more than capable of finding the solution. The program fault is a failure to follow the datasheet process to read the device. Nothing more, nothing less.

Correct on almost all points.

avr_fred:
That instructable does the same thing as the OP’s program and it will behave the same with same erroneous result.

Agreed. Since I used the same instructions, I would expect the same results

avr_fred:
I’ve been trying to get the OP to actually do something different, like starting with a bank sketch and doing the absolute minimum to read a byte from the device.

I resist to spin my wheels. Had I produced the sketch as you have suggested, it would have been the same as the instructables sketch, which you admit doesn't work and has the same flaw. So I saved a bunch of time (kuddos to me). But I don't see the flaw. I haven't found in the datasheet whatever it is you are trying to point to.

avr_fred:
I could also suggest that he place a 10k pot between VCC and and the input pin and measure the current required to detect a high input. Then, compare that with the datasheet for minimum input current required.

I would/could do that, but to what end? I don't know what I would do with the result whether it matched or or not.

avr_fred:
The bottom line is that OP has submitted a test program that creates the problem. It obscures what is read and written to the device. The instructable is at least clear. It does exactly the wrong thing, clearly explained in the datasheet, to read an input.

First half, how does it create the problem? (how about more than a generic response beyond than "failure to follow the datasheet").
Second half, same as above. Same instructions = same result. You say it is clear in the datasheet, but apparently I am still missing it.

avr_fred:
Under the right circumstances, I’ll hand a newbie an answer. But, this is an experienced user that is more than capable of finding the solution. The program fault is a failure to follow the datasheet process to read the device. Nothing more, nothing less.

What, where in the datasheet am I missing? Obviously I haven't found it yet. A little help here?

avr_fred:
He simply resists and rants that I've said nothing. The routine is getting old. He who refuses to do what is suggested has no business asking for help. It's rude.

You have said the same two things multiple times.

  1. "It's in the datasheet, read it." I have and obviously haven't found the answer.
  2. "Change your sketch" (which I also read as correct your program). But since I don't know #1 and the sketch does not error, I don't know what to change. If I used the instructable sketch (almost directly) I still don't know what I would change.

@acr_fred: Simplier sketch (removed serial input and write output).

#include <Wire.h>
#define Address 0x23

void setup()
 {
  Serial.begin (115200);
  Wire.begin();
 }

void loop()
 {
  byte read_value;
  if (Wire.requestFrom(Address,2) == 2)
   {
    read_value=(Wire.read());
    Serial.print(" Byte 1:");
    Serial.print(read_value, HEX);    
    read_value=(Wire.read());
    Serial.print(" Byte 2:");
    Serial.print(read_value, HEX);    
   }
  delay(1000);
 }

Same result. No surprise. Since I have no knowledge of what should be changed it is basically the same code.

Happy now? Normally I would ask for a clue on what to change, but you would probably tell me you already gave me two. So I will just ask a specific question: What should I change, please point to the code or the paragraph in the datasheet that tells me what to change.

That program should work. Try with no pull ups. Cycle power, do your get all ones returned for open circuit inputs? You should. Ground an input. Grounded input should read as zero.

Edit: that program is not the same as your test case. There is a huge, significant difference.

Did all that hence

adwsystems:
Same result. No surprise.

Nothing connected = 0

VCC-10k to Pxx = 0

VCC to Pxx =1

From the first program:

if (Wire.requestFrom(Address,2) == 2)
   {
    second_read_value=(Wire.read());// read second byte and discard
    read_value=(Wire.read());// ^ 0xFF;
    Serial.print(" Byte 1:");
    Serial.print(second_read_value, HEX);
    Serial.print(" Byte 2:");
    Serial.print(read_value, HEX);
   }

Just rearranged and removed one variable to make it simpler.

If there is a huge significant difference, I don't see it. Since I started with test sketch 1 to make test sketch 2, I don't see the difference. The proof is in the pudding. There can't be that much difference. Whatever you know is wrong, is not corrected in the new sketch.

From your original code:

uint8_t cmd=0;
void setup()
 {
  Wire.begin();
  Serial.begin(115200);
  pcf8575();
 }

void pcf8575()
 { byte read_value, second_read_value;
  if (Wire.requestFrom(Address,2) == 2)
   {
    second_read_value=(Wire.read());// read second byte and discard
    read_value=(Wire.read());// ^ 0xFF;
    Serial.print(" Byte 1:");
    Serial.print(second_read_value, HEX);
    Serial.print(" Byte 2:");
    Serial.print(read_value, HEX);
   }
    Serial.print(" cmd:");
    Serial.print(cmd, HEX);

  Wire.beginTransmission(Address);
  Wire.write(lowByte(cmd));
  Wire.write(highByte(cmd));
  Wire.endTransmission();
  Serial.println();
 }

You write a zero to each port with Wire.write on every call to the subroutine and then attempt to read from the port. This in direct conflict with the datasheet that says that any bit written to a zero must be followed by a write of one in order to read from the port.

At powerup, all pins are inputs. No writing to the device should occur, just read the port(s). Writing a zero to a pin forces that pin to be an output. The only way to read a one from a pin that has had a zero written to it is to force about 30-40 ma into the pin to overcome the the output current source. This is exactly what you’ve been doing.

To read a pin that has had a zero written to it requires that you first write a one to that pin. It should then read back as a one and then pulling that input low and reading the pin will result in a zero being returned.

If the test sketch in #27 doesn’t return ones with open pins (or possibly 100k pull ups due to device design differences, my part is a Phillips), I’d have to assume the device is damaged from having had the output devices shorted to VCC for extended periods of time.

I’m speculating on the possible damage, I'm not speculating on the code behavior. I tested your original code and saw the saw the same behavior as you documented. When I did a simple wire.read, I oberseved the proper behavior per the datasheet. It’s repeatable with a good device. Write a zero, you read a zero until you overcome the current sink. Write a one, read a one until the pin is grounded.

Ahhhhhh. Finally useful details.

If I modify the sketch in post #27 to

#include <Wire.h>
#define Address 0x23

void setup()
 {
  Serial.begin (115200);
  Wire.begin();
  Wire.beginTransmission(Address);
  Wire.write(0xFF);
  Wire.write(0xFF);
  Wire.endTransmission();
 }

void loop()
 {
  byte read_value;
  if (Wire.requestFrom(Address,2) == 2)
   {
    read_value=(Wire.read());
    Serial.print(" Byte 1:");
    Serial.print(read_value, HEX);    
    read_value=(Wire.read());
    Serial.print(" Byte 2:");
    Serial.print(read_value, HEX);    
   }
  delay(1000);
 }

then all works fine.

It would have been faster for you to have stated

avr_fred:
To read a pin that has had a zero written to it requires that you first write a one to that pin. It should then read back as a one and then pulling that input low and reading the pin will result in a zero being returned.

back around post #14-16 and referred to datasheet Section 9.1 paragraph 7. One sentence would have saved 14 posts. And no I did not know the solution at the time nor found the information in the datasheet. I figured it out based on an example sketch found online around soon after post 18 without using anything you wrote or didn't write. At that point my effort was not on finding the solution but finding why the solution (sketch) worked. It wasn't until someone else pointed out Section 9.1 paragraph 7 earlier today I understood the why the double 0xF write works.

What I would wonder is if the pin will read 1 with only a 2.2k pullup (and Pxx not connected to ground).

I would almost bet my life that it would read "1" if not grounded.
Almost anything less than 1 Mohm would pull up the input.

raschemmel:
I would almost bet my life that it would read "1" if not grounded.
Almost anything less than 1 Mohm would pull up the input.

Only if you write a 1 to the pin per the datasheet. That was the missing piece that @avr_fred was hinting at.

This directly from the datasheet:

The I/Os should be high before being used as inputs. After power on, as all the I/Os are set high,
all of them can be used as inputs. Any change in setting of the I/Os as either input or outputs can be done with
the write mode. If a high is applied externally to an I/O that has been written earlier to low, a large current (IOL)
will flow to GND

So, let's be clear here. You're saying your test sketch in #27 does not work with your PCF8575? Conditions being just reading open inputs. Both ports should return 0xFF's. If not, your device does not match the expected behavior in the datasheet. The three devices I tested, all Phillips & NXP, do work as expected. I would ask anyone else reading this thread to test any PCF8575's they might have on hand with this code (identical to #27 with a corrected println so you can actually see the results) and post the results. PCF8574's will work as well, they return the same value for both ports.

#include <Wire.h>
#define Address 0x23

void setup()
 {
  Serial.begin (9600);
  Wire.begin();
 }

void loop()
 {
  byte read_value;
  if (Wire.requestFrom(Address,2) == 2)
   {
    read_value=(Wire.read());
    Serial.print(" Byte 1:");
    Serial.print(read_value, HEX);    
    read_value=(Wire.read());
    Serial.print(" Byte 2:");
    Serial.println(read_value, HEX);    
   }
  delay(1000);
 }

Also, for the benefit of anyone reading this thread in the future, your initialization routine in #31 is creating four inputs and four outputs for each eight bit port since your are using Wire.write(0xF) rather than Wire.write(0xFF).

Since you never posted a schematic, I have to assume thats the I/O configuration you're using in spite of the fact you said your intention was "to read a series of switches, pushbuttons, and limit (lever) switches", never mentioning any pins being used as outputs.

It's really ironic that you admonish me that I could have saved fourteen posts by posting one sentence. A sentence in which you struck out the key words that were the source of the problem that you created for yourself. No, in my opinion, the sentence you should focus on and learn from is your opening post where you said in one concise error filled statement:

The program is not the problem. I am able to read the inputs.

avr_fred:
Also, for the benefit of anyone reading this thread in the future, your initialization routine in #31 is creating four inputs and four outputs for each eight bit port since your are using Wire.write(0xF) rather than Wire.write(0xFF).

My bad. Generational error as it is now three sketches away from the primary program. Copy paste error. Program posted updated.

avr_fred:
Since you never posted a schematic, I have to assume thats the I/O configuration you're using in spite of the fact you said your intention was "to read a series of switches, pushbuttons, and limit (lever) switches", never mentioning any pins being used as outputs.

Nothing to assume, see schematic of the port in post #3. Since I could communicate with the board the I2C wiring did not require inspection.

avr_fred:
It's really ironic that you admonish me that I could have saved fourteen posts by posting one sentence. A sentence in which you struck out the key words that were the source of the problem that you created for yourself.

I struck out the words that were not part of the datasheet. You said read the datasheet and the data says:
"Before reading from the PCF8575, all ports desired as input should be set to logic 1".

Hindsight is 20/20. Posts 14 and 16 formed two equations with two unknowns. Something not noticed in the datasheet (post 14) and something wrong in the program (post 16). But in neither case stating the fact. Stating either would have pointed out the other (granted stating the sentence in the datasheet work better than the error in the program. Teach man to fish...).

avr_fred:
No, in my opinion, the sentence you should focus on and learn from is your opening post where you said in one concise error filled statement:

Almost agree. I was trying to avoid replies straying into irrelevant territory (as is a high tendency on this forum), such do you know the address, can you see the board, can you read the inputs and/or write outputs. But some tried to anyway. If you noticed the statement was wrong, you could have simply stated that when you joined the conversation. So two sentences in post 14 and this conversation would have likely ended there.

I was trying to avoid replies straying into irrelevant territory

Reading this thread is so painful.

The 'How to use this forum, please read' thread applies to everyone.

If you only want to answer certain questions you should lay down 'your rules' in your opening post.

After reading your rules, we can decide whether we should respond.

larryd:
Reading this thread is so painful.

As painful as it was to work through.

larryd:
If you only want to answer certain questions you should lay down 'your rules' in your opening post.

After reading your rules, we can decide whether we should respond.

huh?

Every thread I start I hope stays on topic. Here people wander off topic and away from the focus fast and easy. Much more so (IMHO) than at any of the other half-dozens forums I frequent. I'm not sure what the value of this forum would be without the experts that frequent it daily.

I'm not talking about correcting someone that is barking up the wrong tree (like I was). If the OP is at the wrong tree, they need to be corrected. I'm talking of looking at things that are proven to not be the issue. If the inputs and outputs are proved to be working, then communication and board address is not the issue.