Second half:
/*
* Returns address of first i2c device found, negative value if none found
*/
int locatedevice(void)
{
uint8_t error, address;
int rval = -1;
int devcount = 0;
Serial.println("Scanning i2c bus for devices..");
/*
* Note:
* Addresses below 8 are reserved for special use
* Addresses above 0x77 are reserved for special use
*/
for(address = 8; address <= 0x77; address++ )
{
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
devcount++;
Serial.print("i2c device found at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
rval = address;
}
else if (error==4)
{
Serial.print("Unknown error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (rval < 0)
Serial.println("No I2C device found");
if (devcount > 1)
{
Serial.println("Warning: More than 1 device found");
rval = -1; // for now we don't allow multiple devices on the bus
}
return(rval);
}
/*
* Identify I2C device type.
* Currently PCF8574 or MCP23008
*/
int IdentifyIOexp(uint8_t address)
{
uint8_t data;
int chiptype;
/*
* Identify PCF8574 vs MCP23008
* It appears that on a PCF8574 that 1 bits turn on pullups and make the pin an input.
* and 0 bits set the output pin to 0.
* And a read always reads the port pins.
*
* Strategy:
* - Try to Write 0xff to MCP23008 IODIR register (location 0)
* - Point MCP23008 to IODIR register (location 0)
* - Read 1 byte
*
* On a MCP23008 the read will return 0xff because it will read the IODIR we just wrote
* On a PCF8574 we should read a 0 since we last wrote zeros to all the PORT bits
*/
/*
* First try to write 0xff to MCP23008 IODIR
* On a PCF8574 this will end up writing 0 and then ff to output port
*/
Wire.beginTransmission(address);
Wire.write((uint8_t) 0); // try to point to MCP23008 IODR
Wire.write((uint8_t) 0xff); // try to write to MCP23008 IODR
Wire.endTransmission();
/*
* Now try to point MCP23008 to IODIR for read
* On a PCF8574 this will end up writing a 0 to the output port
*/
Wire.beginTransmission(address);
Wire.write((uint8_t) 0); // try to point to MCP23008 IODR
Wire.endTransmission();
/*
* Now read a byte
* On a MCP23008 we should read the 0xff we wrote to IODIR
* On a PCF8574 we should read 0 since the output port was set to 0
*/
Wire.requestFrom((int)address, 1);
data = Wire.read();
if(data == 0xff)
{
chiptype = IICchip_MCP23008;
}
else if (data == 0x00)
{
chiptype = IICchip_PCF8574;
}
else
{
chiptype = IICchip_UNKNOWN;
}
return(chiptype);
}
const char *iicType2Name(int type)
{
const char *name;
switch(type)
{
case IICchip_PCF8574:
name = "PCF8574";
break;
case IICchip_MCP23008:
name = "MCP23008";
break;
default:
name = "UNKNOWN";
break;
}
return(name);
}
/*
* Bit positions on i2c expander output port for LCD pins
*/
typedef struct
{
uint8_t en;
uint8_t rw;
uint8_t rs;
uint8_t d4;
uint8_t d5;
uint8_t d6;
uint8_t d7;
uint8_t bl;
__typeof__(POSITIVE) pol; // use typeof() for backward compability since polarity type name changed
} IICexpdata;
IICexpdata i2cparam[] = {
// EN, RW, RS, D4, D5, D6, D7, BL, POL
{ 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE }, // YwRobot/DFRobot/SainSmart
{ 2, 1, 0, 4, 5, 6, 7, 3, NEGATIVE }, // Robot Arduino LCM1602/2004
{ 4, 5, 6, 0, 1, 2, 3, 7, NEGATIVE }, // MJKDZ board
{ 6, 5, 4, 0, 1, 2, 3, 7, NEGATIVE }, // I2CIO board modded for backlight (pnp transistor)
{ 6, 5, 4, 0, 1, 2, 3, 7, POSITIVE }, // I2CIO board modded for backlight (npn transistor)
{ 4, 5, 6, 0, 1, 2, 3, 7, POSITIVE }, // (extra combination of MJKDZ just in case...)
{0xff} // end of guess table
};
int guessconfig(uint8_t address)
{
uint8_t guess = 0;
char buf[64];
while(i2cparam[guess].en != 0xff)
{
Serial.print("Trying: ");
sprintf(buf, "lcd(0x%02x, %d, %d, %d, %d, %d, %d, %d, %d, %s)",
address,
i2cparam[guess].en,
i2cparam[guess].rw,
i2cparam[guess].rs,
i2cparam[guess].d4,
i2cparam[guess].d5,
i2cparam[guess].d6,
i2cparam[guess].d7,
i2cparam[guess].bl, i2cparam[guess].pol == POSITIVE ? "POSITIVE" : "NEGATIVE");
Serial.println(buf);
/*
* initialize constructor with guess
*/
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(
address,
i2cparam[guess].en,
i2cparam[guess].rw,
i2cparam[guess].rs,
i2cparam[guess].d4,
i2cparam[guess].d5,
i2cparam[guess].d6,
i2cparam[guess].d7,
i2cparam[guess].bl,
i2cparam[guess].pol);
lcd.begin(LCD_ROWS, LCD_COLS);
/*
* Quick 3 blinks of backlight
*/
for(int i = 0; i< 3; i++)
{
lcd.backlight();
delay(250);
lcd.noBacklight();
delay(250);
}
lcd.backlight();
lcd.clear();
sprintf(buf, "0x%02x,%d,%d,%d,%d,",
address,
i2cparam[guess].en,
i2cparam[guess].rw,
i2cparam[guess].rs,
i2cparam[guess].d4);
lcd.print(buf);
sprintf(buf, "%d,%d,%d,%d,%s",
i2cparam[guess].d5,
i2cparam[guess].d6,
i2cparam[guess].d7,
i2cparam[guess].bl, i2cparam[guess].pol == POSITIVE ? "POSITIVE" : "NEGATIVE");
lcd.setCursor(0, 1);
lcd.print(buf);
waitinput(DEFPROMPT);
lcd.clear();
guess++;
}
return(0);
}
#undef read // ugly but removes Wire libary function mapping done above
void waitinput(const char *prompt)
{
if(prompt)
Serial.print(prompt);
else
Serial.print("<Press <ENTER> or click [Send] to Continue>");
while(Serial.available())
Serial.read(); // swallow all input
while(!Serial.available()){} // wait on serial input
Serial.println();
}
This will give you the configuration to insert in this line:
LiquidCrystal_I2C lcd(0x3F,2,1,0,4,5,6,7,3,POSITIVE);
However a better approach is to install from the IDE Library Manager, Bill Perry’s “HD44780” library and use the test program and examples from that instead of the older LiquidCrystal_I2C.