Go Down

Topic: PCF8574AN configured as output for relay (Read 2220 times) previous topic - next topic

Grumpy_Mike

Sorry I really do not know what you want.

To keep a relay or LED on you just do not change that bit in the variable you send to the expander.
To change that output you change the bit corresponding to the output you want to change.
You can change bits with the bit set and bit clear instructions or as grown up do use the bit wise logical AND and OR operations.
In the example I was using the bit wise EXCLUSIVE OR operation to toggle the bits. Notice that only one LED flashes at a time and the others not flashing do not change. This surely is what you want isn't it?

Midway

#16
Feb 15, 2013, 10:30 pm Last Edit: Feb 15, 2013, 10:39 pm by Midway Reason: 1
this is a part of the code.

Code: [Select]
 int Stereovalue = analogRead(A2);                 // Read the Stereo input on Analog pin 2:
 float Stereo = Stereovalue * (4.5 / 1023.0);      // Convert the Stereo value to a voltage

 if (Stereo<1)                                     // A Stereo signal wil be present Lower then 1 volts!(0,8v) Mono = 3,6v
{
   Wire.beginTransmission(PCF2_output);            // Begin the transmission to PCF8574AN
   Wire.write(Yellow);                             // (P2) Stereo led (Yellow)
   Wire.endTransmission();                         // End the Transmission

   digitalWrite(Stereoled, HIGH);                  // Turn Stereo LED "ON" when Tuner receive a Stereo signal
   lcd.setCursor(21,0);
   lcd.print("S");                                 // display Stereo signal received
}
 else
{
   Wire.beginTransmission(PCF2_output);            // Begin the transmission to PCF8574AN
   Wire.write(0, Yellow);                             // turn off LED (P2)
   Wire.endTransmission();                         // End the Transmission

   digitalWrite(Stereoled, LOW);                   // Turn Stereo LED "OFF" when there is no Stereo signal
   lcd.setCursor(21,0);
   lcd.print("M");


the Relay PCF2 is compare as the "digitalWrite(Stereoled, HIGH)" or "digitalWrite(Stereoled, LOW)"
This mean that in this code, when i dont have a Stereo signal the relay (LED for now) is switched off and stay off
and if there is a signal, it swiched on and stay on

for testing the code i have put a LED color Yellow in the PCF  

Grumpy_Mike

#17
Feb 15, 2013, 11:32 pm Last Edit: Feb 16, 2013, 06:24 am by Grumpy_Mike Reason: 1
Forget about accessing the pins directly and just go through there two functions:-
Code: [Select]

byte outputData = 0xff;
void setOutptr(byte bitToChange){
   Wire.beginTransmission(PCF2_output);
   outputData |= 1<< bitToChange;
 Wire.write(outputData);                      // set the bit and leave the others alone
 Wire.endTransmission();
}

void clearOutptr(byte bitToChange){
   Wire.beginTransmission(PCF2_output);
   outputData &= ~(1<< bitToChange);
 Wire.write(outputData);                      //  clear the bit and leave the others alone
 Wire.endTransmission();
}


So when you want to turn on say relay 4, that is the relay on bit 4 you just use
Code: [Select]

setOutput(4);


when you want to turn it off then use
Code: [Select]
clearOutput(4);

As long as you use those two calls nothing else will change only the one bit that you specify.

Midway

ok, great.

i will test tomorrow.

let u know!.

thanks for the help so far :)

edwin

Midway

like this ?
Code: [Select]
}
  int Stereovalue = analogRead(A2);                 // Read the Stereo input on Analog pin 2:
  float Stereo = Stereovalue * (4.5 / 1023.0);      // Convert the Stereo value to a voltage

  if (Stereo<1)                                     // A Stereo signal wil be present Lower then 1 volts!(0,8v) Mono = 3,6v
{
void setOutptr(byte bitToChange)
{
    Wire.beginTransmission(PCF2_output);
    outputData |= 1;
    Wire.write(outputData);                         // set the bit and leave the others alone
    Wire.endTransmission();

    digitalWrite(Stereoled, HIGH);                  // Turn Stereo LED "ON" when Tuner receive a Stereo signal
    lcd.setCursor(21,0);
    lcd.print("S");                                 // display Stereo signal received
}
  else
{
void clearOutptr(byte bitToChange)
{
    Wire.beginTransmission(PCF2_output);
    outputData &= ~(1);
    Wire.write(outputData);                         //  clear the bit and leave the others alone
    Wire.endTransmission();

    digitalWrite(Stereoled, LOW);                   // Turn Stereo LED "OFF" when there is no Stereo signal
    lcd.setCursor(21,0);
    lcd.print("M");                                 // display Mono signal received
}

Grumpy_Mike

No,
you haven't got what I put.

Code: [Select]

}
  int Stereovalue = analogRead(A2);                 // Read the Stereo input on Analog pin 2:
  float Stereo = Stereovalue * (4.5 / 1023.0);      // Convert the Stereo value to a voltage

  if (Stereo<1)                                     // A Stereo signal wil be present Lower then 1 volts!(0,8v) Mono = 3,6v
{
void setOutptr(byte bitToChange)
{
    Wire.beginTransmission(PCF2_output);
    outputData |= 1 << bitToChange;
    Wire.write(outputData);                         // set the bit and leave the others alone
    Wire.endTransmission();

    digitalWrite(Stereoled, HIGH);                  // Turn Stereo LED "ON" when Tuner receive a Stereo signal
    lcd.setCursor(21,0);
    lcd.print("S");                                 // display Stereo signal received
}
  else
{
void clearOutptr(byte bitToChange)
{
    Wire.beginTransmission(PCF2_output);
    outputData &= ~(1<<bitToChange);
    Wire.write(outputData);                         //  clear the bit and leave the others alone
    Wire.endTransmission();

    digitalWrite(Stereoled, LOW);                   // Turn Stereo LED "OFF" when there is no Stereo signal
    lcd.setCursor(21,0);
    lcd.print("M");                                 // display Mono signal received
}


The statement should be
Code: [Select]
outputData |= 1 << bitToChange;
This sets the appropriate bit to a 1 without altering any of the other bits. The << is a shift to the left, you shift a one by as many bits to the left as the number of the bit you want to change.
Similarly when you want to clear a bit you create a number with a one in the bit you want to change, then you invert it, that is swap all the zeros and ones. Then you AND it with the number, this clears the bit.
Code: [Select]
outputData &= ~(1<< bitToChange);

Midway

#21
Feb 16, 2013, 08:42 pm Last Edit: Feb 17, 2013, 09:57 pm by Midway Reason: 1
sorry, i dont get it working.

Midway

Quote
when you want to turn it off then use

Code: [Select]
setOutput(4);

Quote
when you want to turn it off then use

Code: [Select]
clearOutput(4);

also where to put those

Grumpy_Mike

What I gave you was two functions to turn on and off individual bits in your interface.

Quote
clearOutput(4);
also where to put those

You put them in your code when ever you want to turn something on or off. Specifically when you want to turn bit 4 off. If you want to turn bit 1 off you would put clearOutput(1) ; if you want to turn bit 6 off you would use clearOutput(6) ; if you want to turn bit 8 off then you understand even less because there is no bit 8 in your interface.

The code you just posted is a nonsense, it contains a function definition in the middle of a function, that does not make sense and the compiler no doubt tells you so. The functions I gave you must be put separately at the end of your code. Then in the code you call the functions when ever you want to turn something on or off. That will be turned on or off without affecting any other things attached to the same expander. Which is what I thought you wanted.

I don't think you know enough about programming to do your project. I would advise you learning some very basic fundamentals of programming. Like what is a function.

Midway

thanks for posting Mike,

just with some help i almost finish the project.

it is only this past part with the PCF what makes it hard to find out.

Grumpy_Mike


it is only this past part with the PCF what makes it hard to find out.

No it is not.
It is exactly the same technique that is used to make individual bits change in shift registers. It is exactly the same technique that is used to make a digitalWrite() function work on individual pins of a port on the arduino.
It is a very simple concept which you seem to be making heavy weather out of.

The concept is you have a variable, you change only one bit in that variable and then you write the whole thing out to your peripheral / port / shift register. The bits you have not changed in the variable do not change in the output. The bits that you have changed in the variable change in the output.

Grumpy_Mike

Just to finish off this thread for anyone following it up later I have written a function that works exactly like the digitalWrite function but for a PCF8574. It is called digitalOutput and it takes the same parameters as digitalWrite.

Code: [Select]
// Output to I2C device as if it were a digitalWrite pin
void digitalOutput(byte pin, boolean level){
  static byte reg = 0xff;
  byte mask;
  mask = 1<< pin;
  if(level){
    reg |= mask;
  }
  else {
    mask = ~mask; // invert mask
    reg &= mask;
  }
  Wire.beginTransmission(PCF_address1);
  Wire.write(reg);                      // change bit
  Wire.endTransmission();
}


This code includes that function and also shows three ways you can use it.

Code: [Select]
/*
Using a PCF8574
and controlling only one bit at a time
the function digitalOutput(pin, LEVEL) works just like the function
digitalWrite does for internal pins but for pins on the PCF8574
To drive an LED connect anode to +5V, cathode to resistor, resistor to
PCF8574 output pin.

By Mike Cook Feb 2013 - creative commons license share and share alike.
*/

#define PCF_address1 0x38 // PCF8574AN, Address 0x38 with A0-A1-A2 pins grounded.
#include <Wire.h>

void setup()
{
  Wire.begin();
  digitalOutput(0, HIGH); // initialise outputs
}

void loop()
{
  static boolean flip = false;
  // examples of using digitalOutput
// pin 0 toggling by direct HIGH and LOW
for(int i=0;i<9;i++){
  digitalOutput(0, HIGH);
  delay(200);
  digitalOutput(0, LOW);
  delay(200); 
}
// pin 1 toggling using the least significant bit of a variable to set HIGH and LOW
for(int i=0;i<8;i++){
  digitalOutput(1, i & 0x1);
  delay(200);
}
// pin 2 toggling once per loop using a boolean variable to define HIGH and LOW
  digitalOutput(2, flip);
  flip = !flip; // invert the variable
  delay(300);

}

// Output to I2C device as if it were a digitalWrite pin
void digitalOutput(byte pin, boolean level){
  static byte reg = 0xff;
  byte mask;
  mask = 1<< pin;
  if(level){
    reg |= mask;
  }
  else {
    mask = ~mask; // invert mask
    reg &= mask;
  }
  Wire.beginTransmission(PCF_address1);
  Wire.write(reg);                      // change bit
  Wire.endTransmission();
}

bperrybap

Grumpy_Mike,
Never underestimate how people can misinterpret things.
I think using the term "pin" may not be clear to some folks
since the parameter is actually a bit number.
It might be a bit clearer for folks to change the names and/or terminology of your parameter
to clearly show that the parameter is bit numbers of the output port.
Or at least include some additional explanation that 0 is for controlling the pin P0,
1 is for the the pin P1, etc...

I've wrestled with a similar issue with an i2c lcd library.
In the case of the i2c to hd44780 adapters, people
would insert pin numbers of the PCF8574 or even the pin numbers of the hd44780 interface
rather than the actual bit numbers of the pcf8574 output register.
Once they finally "get it", it becomes clear, but often there is quite a bit of back and
forth and explanation needed until it finally sinks in.

--- bill

Go Up