#define PCF8574_SDA PIN_B0 #define PCF8574_SCL PIN_B1 //#define max7328_29_ADDRESS long int #use i2c(master, sda=PCF8574_SDA, scl=PCF8574_SCL, SLOW=50000) // ---------------------------------------------------------------------------- // routines for the philips PCF8574/(A) i2c based 8 I/O chip // i2c_pcf8574_get_io(); reads state from 1 or all 8 inputs // i2c_pcf8574_set_io(); set the state all 8 outputs // i2c_device_exists(); test for presence of device #define I2CWRITE 0b00000000 #define I2CREAD 0b00000001 // this is a handy function for taking the i2c physical address // and shifting the bits left so that the address can simply be // OR'd with an i2c write command... int i2c_addr_mask(int device_addr) { /* xxxxxIJK --> 00000IJK, then 00000IJK --> 0000IJK0 */ return((device_addr & 0x07)<<1); } #define PCF8574_ID 0b01000000 #define PCF8574A_ID 0b01110000 int i2c_pcf8574_get_io(int device_type, int device_addr,int port_id) { /* 0 <= port_id <= 8, or 8 for all */ int io_field; int addr_mask; addr_mask=i2c_addr_mask(device_addr); i2c_start(); i2c_write(device_type | addr_mask | I2CREAD); io_field=i2c_read(); /* this byte contains the prior conversion result. */ io_field=i2c_read(0); /* returned data is big-endian (msbit first) */ i2c_stop(); if (port_id >= 8) return(io_field); if (BIT_TEST(io_field,port_id)) return(1); else return(0); } // note: in order to implement "per bit" port control, it will be necessary // to first read all bits, and then OR that value with the bit you are // trying to toggle. otherwise, you'll just end up overwriting adjacent // io bits and thus inadvertently changing other io lines. int i2c_pcf8574_set_io(int device_type, int device_addr, int io_field) { int addr_mask; addr_mask=i2c_addr_mask(device_addr); i2c_start(); i2c_write(device_type | addr_mask | I2CWRITE); i2c_write(io_field); //i2c_write(io_field); i2c_stop(); return(io_field); } // note: due to a production screw-up, some PCB assy's were delivered with // the "A" version of the pcf8574 device; while the responsible parties // were in fact tortured by being forced to consume large quantites // of a popular laxative, it was nevertheless necessary to implement // a scheme by which the FW could detect which flavor pcf8574 was on // the board. hence the following function... call it using either // PCF8574_ID or PCF8574A_ID and test the return value. this function // is actually not pcf8574-specific; you can use it to test for the // presence of any type of i2c device at any i2c physical address. short int i2c_device_exists(int device_type, int device_addr) { short int result=FALSE; int addr_mask; int testbyte; addr_mask=i2c_addr_mask(device_addr); testbyte=(device_type | addr_mask | I2CWRITE); // mode is write i2c_start(); if (i2c_write(testbyte)) // if the ACK error bit is set, target is absent result=FALSE; else result=TRUE; i2c_stop(); return(result); }