Problem beim Übertragen von Daten von PIC18F45K20 (C18) zu MCP23017

Ich teste derzeit den MCP23017 (Slave-Gerät) 16-Bit-E / A-Expander mit einem PIC18F45K20 mit dem C18-Compiler, um Daten an den MCP23017 zu übertragen. Die Adressstifte (A0, A1 und A2) des MCP23017 sind geerdet. Die serielle Uhr (SCL) läuft mit 100kHz.

Ich habe meinen Programmcode von Kopf bis Fuß überprüft und konnte kein Problem in meinem Code finden, obwohl er fehlerfrei kompiliert wurde.

Die Probleme, mit denen ich konfrontiert war, sind:

  • Der MCP23017 gibt die vom PIC18F45K20 gesendeten Daten nicht aus (Programmcode unten gezeigt).

  • Die SCL-Wellenform von PIC18F45K20 ist keine Rechteckwelle. Es wurde mit einem Oszilloskop gemessen

    #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 ist keine sinnvolle Einheit zur Beschreibung der IIC-Bus-Taktleitung.
Es ist wahrscheinlich erwähnenswert, wie Sie SCL messen, um festzustellen, dass es sich nicht um eine Rechteckwelle handelt. Das klingt so, als wäre es möglicherweise ein Hardwareproblem, also wäre ein Schaltplan gut.
Ich habe nicht gesehen, dass Sie TRISC irgendwo im Code gesetzt haben. Sind Sie sicher, dass die E/A-Leitungen im richtigen Zustand sind?
Sowohl RC3 als auch RC4 wurden in der Funktion init_I2C() gesetzt. Basierend auf dem Datenblatt müssen sowohl RC3 als auch RC4 als Eingang konfiguriert werden, wenn SCL und SDA aktiviert sind.
@RonnÉ Haben Sie Pullup-/Pulldown-Widerstände für die SCL- und SDA-Pins eingerichtet?

Antworten (2)

Die Probleme waren gelöst. Die Ursache dieses Problems liegt darin, dass der Wcode Acknowledge-Bits enthält. Es ist nicht erforderlich, dass das Master-Gerät während des Schreibvorgangs ein Bestätigungsbit an das Slave-Gerät sendet. Tatsächlich sollte das Master-Gerät auf das Bestätigungsbit vom Slave-Gerät warten.

Unten ist der Code zum Testen des I2C-Protokolls des PIC18F45K20 mit 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();
     }
}

Ich stimme zu, dass dies ein alter Beitrag ist, aber nur für die Leute da draußen, die PIC18f4xk22-Serien und das MSSP2 verwenden, dh i2c_2, denken Sie bitte daran, die Unterstützung für analoge Pins zu deaktivieren, die auf PIND0 und PIND1 gemuxt werden. Sie müssen ANALOG deaktivieren, indem Sie ANSELD &= 0xFC verwenden;