Conexión del PCF8574 a un MSP430G2553

El PCF8574 es un expansor  de entrada/salida que se conecta al bus I2C. Los pines pueden funcionar indistintamente como entrada o salida sin ningún tipo de configuración. Un pin de interrupción permite conocer cuando hay cambios en las entradas (o salidas).

PCF8574 Conectado a un MSP430G2553

PCF8574 Conectado a un MSP430G2553

 

El ejemplo

La idea es conectar dos PCF8574 a un MSP430G2553. El primero lo usaré como salida, mientras que el segundo lo utilizaré de entrada. De esta manera voy a obtener 8 entradas y 8 salidas con sólo 3 pines del microcontrolador.

Al primer expansión le asigno la dirección 0b0100 000 (32 en decimal) poniendo A0, A1 y A2 a LOW. El segundo tiene la dirección 0b100001 (33 en decimal) conectando A0 a VCC a través de una resistencia de 10K. El pin de interrupción está conectado al MSP para avisar cuando hay cambios en las entradas. Para funcionar necesita una resistencia pull-up.

 

Configurando el USCI

  1. Poner los pines 1.6 y 1.7 como SDA y SCL
  2. Parar el USCI
  3. Poner USCI en modo Master, I2C y sincrono
  4. Utilizar SMCLK como fuente del reloj. De aquí depende la velocidad del bus.
  5. Asignar la velocidad del bus. En este caso, SMCLK funciona a 16 Mhz. Para obtener 400 kHz en el bus I2C hay que dividr por 40.
  6. Activar USCI.
void initI2c(){
    // Configurar los pins en modo i2c
    P1SEL |= BIT6 + BIT7;
    P1SEL2 |= BIT6 + BIT7;

    /* Disable USCI */
    UCB0CTL1 |= UCSWRST;

    // UCMST -- Master mode
    // UCMODE_3 -- I2C Mode
    // UCSYNC -- Synchronous Mode
    UCB0CTL0 = UCMST | UCMODE_3 | UCSYNC;

    //UCSSEL_2 -- SMCLK
    //UCSWRST -- Enabled. USCI logic held in reset state
    UCB0CTL1 = UCSSEL_2 | UCSWRST;

    /* Bit Rate Control Register 0 */
    // La velocidad del bus es 16000 kHz (16Mhz) del MCLK / 40 = 400 kHz

    UCB0BR0 = 40;

    /* Enable USCI */
    UCB0CTL1 &= ~UCSWRST;
}

 

Enviar y recibir datos

// Lee un byte
unsigned char pcf8574_readByte(unsigned char addr){
	volatile unsigned char data;

	UCB0I2CSA = addr; //Address de destino

	while ((UCB0STAT & UCBBUSY) != 0);

	UCB0CTL1 &= ~UCTR;	// modo read
	UCB0CTL1 |= UCTXSTT;	// enviar start
	while ((UCB0CTL1 & UCTXSTT) != 0);

	// Sólo quiero recibir un byte. Envio stop
	while ((UCB0STAT & BUSY) != 0);
	UCB0CTL1 |= UCTXSTP;	//enviar stop

	while ((UCB0STAT & UCBBUSY) != 0);
	while ((IFG2 & UCB0RXIFG) == 0);
	data = UCB0RXBUF;

	return data;
}


// Envia un byte a la addr apuntada
void pcf8574_sendByte(unsigned char addr, unsigned char data){
	while ((UCB0STAT & UCBBUSY) != 0);

	UCB0I2CSA = addr; //Address de destino
	UCB0CTL1 |= UCTR; 	// modo transmitir
	UCB0CTL1 |= UCTXSTT;	//enviar start
	UCB0TXBUF = data;
	while ((IFG2 & UCB0TXIFG) == 0);	//Espera a que este enviado

	///////////// Enviar stop
	UCB0CTL1 |= UCTXSTP;	//enviar stop
}

 

Configurar el pin que recibe la interrupción

#define PCF_INT_PIN BIT2

void initIO() {
	P1DIR &= ~PCF_INT_PIN;	// entrada
	P1REN &= ~PCF_INT_PIN;	//Sin pull-up
	P1IES |= PCF_INT_PIN;	//HIGH TO LOW interruption
	P1IFG &= ~PCF_INT_PIN;	// clear interrupt flag
	P1IE |= PCF_INT_PIN;	// enable interrupcion
}


#pragma vector = PORT1_VECTOR
__interrupt void port1_ISR(void){

    if ((P1IFG & PCF_INT_PIN) == PCF_INT_PIN) {
		// Lee las entradas del segundo integrado (addr=33)
		readed = pcf8574_readByte(33);

		// Envia el resultado al primer integrado (addr=32);
		pcf8574_sendByte(32,readed);
		P1IFG &= ~PCF_INT_PIN;
    }

}

 

Datasheet

PCF8574

MSP430G2553