Problema con la transmisión de datos de PIC18F45K20 (C18) a MCP23017

Actualmente estoy probando el expansor de E/S de 16 bits MCP23017 (dispositivo esclavo) usando un PIC18F45K20 con el compilador C18 para transmitir datos al MCP23017. Los pines de dirección (A0, A1 y A2) del MCP23017 están conectados a tierra. El reloj serie (SCL) funciona a 100 kHz.

Revisé el código de mi programa de pies a cabeza y no pude encontrar ningún problema en mi código a pesar de que se compiló sin errores.

Los problemas que enfrenté son:

  • El MCP23017 no emite los datos transmitidos desde el PIC18F45K20 (el código de programa se muestra a continuación).

  • La forma de onda SCL de PIC18F45K20 no es una onda cuadrada. Se midió con un osciloscopio.

    #include <stdio.h>
    #include <stdlib.h>
    #include <delays.h>
    #include <i2c.h>
    #include <p18f45k20.h>
    #include <sw_i2c.h>
    
    #define MCP_IODIR_A 0x00
    #define MCP_IPOL_A 0x02
    #define MCP_OLAT_A 0x14
    #define MCP_GPIO_A 0x12
    #define MCP_IOCON_A 0x0A
    #define MCP_GPINTEN_A 0x04
    
    /*
    * 
    */
    //----------------------------Global variable----------------------------
    
    
    // PIC18F45K20 Configuration Bit Settings
    
    // CONFIG1H
    #pragma config FOSC = INTIO67   // Oscillator Selection bits (Internal oscillator block, port function on RA6 and RA7)
    #pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
    #pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)
    
    // CONFIG2L
    #pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
    #pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
    #pragma config BORV = 30        // Brown Out Reset Voltage bits (VBOR set to 3.0 V nominal)
    
    // CONFIG2H
    #pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
    #pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)
    
    // CONFIG3H
    #pragma config CCP2MX = PORTC   // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
    #pragma config PBADEN = ON      // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
    #pragma config LPT1OSC = OFF    // Low-Power Timer1 Oscillator Enable bit  (Timer1 configured for higher power operation)
    #pragma config HFOFST = ON      // HFINTOSC Fast Start-up (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
    #pragma config MCLRE = OFF      // MCLR Pin Enable bit (RE3 input pin enabled; MCLR disabled)
    
    // CONFIG4L
    #pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
    #pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
    #pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))
    
    // CONFIG5L
    #pragma config CP0 = OFF        // Code Protection Block 0 (Block 0 (000800-001FFFh) not code-protected)
    #pragma config CP1 = OFF        // Code Protection Block 1 (Block 1 (002000-003FFFh) not code-protected)
    #pragma config CP2 = OFF        // Code Protection Block 2 (Block 2 (004000-005FFFh) not code-protected)
    #pragma config CP3 = OFF        // Code Protection Block 3 (Block 3 (006000-007FFFh) not code-protected)
    
    // CONFIG5H
    #pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
    #pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)
    
    // CONFIG6L
    #pragma config WRT0 = OFF       // Write Protection Block 0 (Block 0 (000800-001FFFh) not write-protected)
    #pragma config WRT1 = OFF       // Write Protection Block 1 (Block 1 (002000-003FFFh) not write-protected)
    #pragma config WRT2 = OFF       // Write Protection Block 2 (Block 2 (004000-005FFFh) not write-protected)
    #pragma config WRT3 = OFF       // Write Protection Block 3 (Block 3 (006000-007FFFh) not write-protected)
    
    // CONFIG6H
    #pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
    #pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
    #pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)
    
    // CONFIG7L
    #pragma config EBTR0 = OFF      // Table Read Protection Block 0 (Block 0(000800-001FFFh) not protected from table reads executed in other blocks)
    #pragma config EBTR1 = OFF      // Table Read Protection Block 1 (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
    #pragma config EBTR2 = OFF      // Table Read Protection Block 2 (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
    #pragma config EBTR3 = OFF      // Table Read Protection Block 3 (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)
    
    // CONFIG7H
    #pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)
    
    void init_I2C()
    {
        DDRCbits.RC3 = 1; //Configure SCL as input
        DDRCbits.RC4 = 1; //Configure SDA as input
    
        // SSPSTAT Configuration (0x80)
        SSPSTATbits.SMP = 1;    //Slew rate control disabled
        SSPSTATbits.CKE = 0;    //SMBus disabled
        SSPSTATbits.D_A = 0;    //Reserved in master mode
        SSPSTATbits.P = 0;      //Stop bit was not detected last
        SSPSTATbits.S = 0;      //Start bit was not detected last
        SSPSTATbits.R_W = 0; 
        SSPSTATbits.UA = 0;     //Address doesnot need to be updated
        SSPSTATbits.BF = 0; 
    
        // SSPCON1 Configuration (0x28)
        SSPCON1bits.WCOL = 0;
        SSPCON1bits.SSPOV = 0;
        SSPCON1bits.SSPEN = 1;  //Serial port enabled
        SSPCON1bits.CKP = 0;    //Holds clock low
        SSPCON1bits.SSPM3 = 1;  //1000 = I2C Master mode
        SSPCON1bits.SSPM2 = 0;  //BitRate = FOSC/(4*(SPPADD+1))
        SSPCON1bits.SSPM1 = 0; 
        SSPCON1bits.SSPM0 = 0;                       
    
        // SSPADD Configuration
        SSPADD = 0x27;  //should be 0x27 for 100kHz
                        //SSPADD = [(FOSC/BitRate)/4]-1
    
        // SSPCON2 Configuration (0x00)
        SSPCON2bits.GCEN = 0;       //General call address disabled
        SSPCON2bits.ACKSTAT = 0;    //Acknowledge was received from slave
        SSPCON2bits.ACKDT = 0;      //Acknowledge
        SSPCON2bits.ACKEN = 0;      //Acknowledge sequence idle
        SSPCON2bits.RCEN = 0;       //Receive idle
        SSPCON2bits.PEN = 0;        //Stop condition idle
        SSPCON2bits.RSEN = 0;       //Repeated start condition idle
        SSPCON2bits.SEN = 0;
    }
    
    void MCP_write()
    {
         WriteI2C(0x40);
    }
    
    void MCP_read()
    {
         WriteI2C(0x41);
    }
    
    void MCP_addr()
    {
         StartI2C();
         MCP_write();
    }
    
    void init_MCP()
    {
         //IODIR A configuration
         MCP_addr();
         AckI2C();
         WriteI2C(MCP_IODIR_A);
         AckI2C();
         WriteI2C(0x00);
         StopI2C();
    
         //IPOL A configuration
         MCP_addr();
         AckI2C();
         WriteI2C(MCP_IPOL_A);
         AckI2C();
         WriteI2C(0x00);
         StopI2C();
    
         //OLAT A configuration
         MCP_addr();
         AckI2C();
         WriteI2C(MCP_OLAT_A);
         AckI2C();
         WriteI2C(0xFF);
         StopI2C();
    
         //IOCON A configuration
         MCP_addr();
         AckI2C();
         WriteI2C(MCP_IOCON_A);
         AckI2C();
         WriteI2C(0x00);
         StopI2C();
    
         //GPINTEN A configuration
         MCP_addr();
         AckI2C();
         WriteI2C(MCP_GPINTEN_A);
         AckI2C();
         WriteI2C(0x00);
         StopI2C();
    }
    
    
    //----------------------------Main program----------------------------
    void main(void)
    {
         OSCCON = 0x70;      //Set internal oscillation to 16 MHz
         TRISD=0;
         init_I2C();         //I2C initialization
         init_MCP();         //MCP23017 initialization
    
         while(1)
         {
             MCP_addr();
             AckI2C();
             WriteI2C(MCP_GPIO_A);
             AckI2C();
             WriteI2C(0x11);
             StopI2C();
          }
    }
    
Kelvin-Hertz no es una unidad significativa para describir la línea de reloj del autobús IIC.
Probablemente valga la pena mencionar cómo está midiendo SCL para determinar que no es una onda cuadrada. Eso hace que parezca que posiblemente sea un problema de hardware, por lo que un esquema sería bueno.
No vi que configuraste TRISC en ninguna parte del código. ¿Está seguro de que las líneas de E/S están en el estado correcto?
Tanto RC3 como RC4 se configuraron en la función init_I2C(). Según la hoja de datos, tanto RC3 como RC4 deben configurarse como entrada si SCL y SDA están habilitados.
@RonnÉ ¿Configuró resistencias pull-up/pull-down para los pines SCL y SDA?

Respuestas (2)

Los problemas habían sido resueltos. El origen de este problema es que había bits de reconocimiento en el wcode. No es necesario que el dispositivo maestro envíe un bit de reconocimiento al dispositivo esclavo durante la operación de escritura. De hecho, el dispositivo maestro debe esperar el bit de reconocimiento del dispositivo esclavo.

A continuación se muestra el código para probar el protocolo I2C del PIC18F45K20 con MCP23017.

#include <stdio.h>
#include <stdlib.h>
#include <delays.h>
#include <i2c.h>
#include <p18f45k20.h>
#include <sw_i2c.h>

#define MCP_IODIR_A 0x00
#define MCP_IPOL_A 0x02
#define MCP_OLAT_A 0x14
#define MCP_GPIO_A 0x12
#define MCP_IOCON_A 0x0A
#define MCP_GPINTEN_A 0x04

/*
* 
*/
//----------------------------Global variable----------------------------


// PIC18F45K20 Configuration Bit Settings

// CONFIG1H
#pragma config FOSC = INTIO67   // Oscillator Selection bits (Internal oscillator block, port function on RA6 and RA7)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 30        // Brown Out Reset Voltage bits (VBOR set to 3.0 V nominal)

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config CCP2MX = PORTC   // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = ON      // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer1 Oscillator Enable bit  (Timer1 configured for higher power operation)
#pragma config HFOFST = ON      // HFINTOSC Fast Start-up (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
#pragma config MCLRE = OFF      // MCLR Pin Enable bit (RE3 input pin enabled; MCLR disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection Block 0 (Block 0 (000800-001FFFh) not code-protected)
#pragma config CP1 = OFF        // Code Protection Block 1 (Block 1 (002000-003FFFh) not code-protected)
#pragma config CP2 = OFF        // Code Protection Block 2 (Block 2 (004000-005FFFh) not code-protected)
#pragma config CP3 = OFF        // Code Protection Block 3 (Block 3 (006000-007FFFh) not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection Block 0 (Block 0 (000800-001FFFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection Block 1 (Block 1 (002000-003FFFh) not write-protected)
#pragma config WRT2 = OFF       // Write Protection Block 2 (Block 2 (004000-005FFFh) not write-protected)
#pragma config WRT3 = OFF       // Write Protection Block 3 (Block 3 (006000-007FFFh) not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection Block 0 (Block 0(000800-001FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection Block 1 (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection Block 2 (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection Block 3 (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)

void init_I2C()
{
    DDRCbits.RC3 = 1; //Configure SCL as input
    DDRCbits.RC4 = 1; //Configure SDA as input

    // SSPSTAT Configuration (0x80)
    SSPSTATbits.SMP = 1;    //Slew rate control disabled
    SSPSTATbits.CKE = 0;    //SMBus disabled
    SSPSTATbits.D_A = 0;    //Reserved in master mode
    SSPSTATbits.P = 0;      //Stop bit was not detected last
    SSPSTATbits.S = 0;      //Start bit was not detected last
    SSPSTATbits.R_W = 0; 
    SSPSTATbits.UA = 0;     //Address doesnot need to be updated
    SSPSTATbits.BF = 0; 

    // SSPCON1 Configuration (0x28)
    SSPCON1bits.WCOL = 0;
    SSPCON1bits.SSPOV = 0;
    SSPCON1bits.SSPEN = 1;  //Serial port enabled
    SSPCON1bits.CKP = 0;    //Holds clock low
    SSPCON1bits.SSPM3 = 1;  //1000 = I2C Master mode
    SSPCON1bits.SSPM2 = 0;  //BitRate = FOSC/(4*(SPPADD+1))
    SSPCON1bits.SSPM1 = 0; 
    SSPCON1bits.SSPM0 = 0;                       

    // SSPADD Configuration
    SSPADD = 0x27;  //should be 0x27 for 100kHz
                    //SSPADD = [(FOSC/BitRate)/4]-1

    // SSPCON2 Configuration (0x00)
    SSPCON2bits.GCEN = 0;       //General call address disabled
    SSPCON2bits.ACKSTAT = 0;    //Acknowledge was received from slave
    SSPCON2bits.ACKDT = 0;      //Acknowledge
    SSPCON2bits.ACKEN = 0;      //Acknowledge sequence idle
    SSPCON2bits.RCEN = 0;       //Receive idle
    SSPCON2bits.PEN = 0;        //Stop condition idle
    SSPCON2bits.RSEN = 0;       //Repeated start condition idle
    SSPCON2bits.SEN = 0;
}

void MCP_write()
{
     WriteI2C(0x40);
}

void MCP_read()
{
     WriteI2C(0x41);
}

void MCP_addr()
{
     StartI2C();
     MCP_write();
}

void init_MCP()
{
     //IODIR A configuration
     MCP_addr();
     WriteI2C(MCP_IODIR_A);
     WriteI2C(0x00);
     StopI2C();

     //IPOL A configuration
     MCP_addr();
     WriteI2C(MCP_IPOL_A);
     WriteI2C(0x00);
     StopI2C();

     //OLAT A configuration
     MCP_addr();
     WriteI2C(MCP_OLAT_A);
     WriteI2C(0xFF);
     StopI2C();

     //IOCON A configuration
     MCP_addr();
     WriteI2C(MCP_IOCON_A);
     WriteI2C(0x00);
     StopI2C();

     //GPINTEN A configuration
     MCP_addr();
     WriteI2C(MCP_GPINTEN_A);
     WriteI2C(0x00);
     StopI2C();
} 


//----------------------------Main program----------------------------
void main(void)
{
     OSCCON = 0x70;      //Set internal oscillation to 16 MHz
     TRISD=0;
     init_I2C();         //I2C initialization
     init_MCP();         //MCP23017 initialization

     while(1)
     {
         MCP_addr();
         WriteI2C(MCP_GPIO_A);
         WriteI2C(0x11);
         StopI2C();
     }
}

Estoy de acuerdo en que esta es una publicación anterior, pero solo para la gente que usa las series PIC18f4xk22 y MSSP2, es decir, i2c_2, tenga en cuenta que debe desactivar el soporte de pines analógicos muxed a PIND0 y PIND1. Debe deshabilitar ANALOG usando ANSELD &= 0xFC;