You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pic18f4550 I2C通信故障:从机无应答问题求助

PIC18F4550 I2C通信故障排查与修复

问题描述

两块PIC18F4550单片机实现I2C通信:主机发送数据,从机接收后将数据输出到PORTD的LED。当前故障:主机地址发送后(LED2点亮),收不到从机应答(LED3不亮);从机地址匹配指示灯(MATCH)点亮,但数据LED无输出。

主机代码

//==================== Master I2C code=========================
bit I2C_Write(unsigned char address, unsigned char *data, unsigned char datasize) {
    SSPCON2bits.SEN = 1; // 启动I2C起始条件,硬件自动清除
    while (!PIR1bits.SSPIF);
    PIR1bits.SSPIF = 0;
    LED1 = 1;
    
    SSPBUF = address;
    while (!PIR1bits.SSPIF);
    PIR1bits.SSPIF = 0;
    LED2 = 1;  // 此LED点亮,说明地址已发送
    if (SSPCON2bits.ACKSTAT) {
        // 未收到应答,发送停止条件
        SSPCON2bits.PEN = 1;
        while (SSPCON2bits.PEN);
        ACK = 1;
        return 0;
    }             
    LED3 = 1; // 此LED不亮,说明未收到从机应答
    int i;
    for (i = 0; i < datasize; i++) {
        SSPBUF = *data;
        while (!PIR1bits.SSPIF);
        PIR1bits.SSPIF = 0;
    
        if (SSPCON2bits.ACKSTAT) {
            SSPCON2bits.PEN = 1;
            while (SSPCON2bits.PEN);
            ERROR = 1;
            return 0;
        }
        LED = *data;
        data++;
    }
    LED4 = 1;
    
    SSPCON2bits.PEN = 1; // 发送I2C停止条件
    while (SSPCON2bits.PEN);
    PIR1bits.SSPIF = 0;
    
    return 1;
}

//-----I2C初始化---------
void I2C_INIT(void) {
    SDA_dir = 1;
    SCL_dir = 1;
    ADCON1bits.PCFG = 0b1111; // 所有引脚设为数字IO

    SSPADD = _XTAL_FREQ / (4 * Baud_Rate) - 1;
    SSPSTATbits.SMP = 0; // 标准速度模式下禁用斜率控制
    SSPCON1bits.SSPEN = 1; // 使能I2C模块
    SSPCON1bits.SSPM = 0b1000; // I2C主机模式,时钟=FOSC/(4*(SSPADD+1))
}

//-------主机调用示例--------
unsigned char data[5] = {0xA1, 0xB1, 0xC1, 0xD1, 0xE1};
I2C_Write(0b00111100, data, 5);

从机代码

//=======================Slave I2c code===========================
unsigned char Read_data;

void __interrupt() ISR(void) {
    if (PIR1bits.SSPIF) {
        if (SSPSTATbits.D_NOT_A) {
            // 收到数据字节
            Read_data = SSPBUF; // 读取数据
            PORTD = Read_data;  // 输出到PORTD的LED
            // 发送应答给主机
            SSPCON2bits.ACKDT = 0; // 应答位设为0(应答)
            SSPCON2bits.ACKEN = 1; // 触发应答发送
            while(SSPCON2bits.ACKEN); // 等待应答完成
        } else {
            // 收到地址字节,匹配成功
            MATCH = 1;
            unsigned char dummy = SSPBUF; // 读取地址清除BF位
            // 发送应答给主机
            SSPCON2bits.ACKDT = 0;
            SSPCON2bits.ACKEN = 1;
            while(SSPCON2bits.ACKEN);
        }
        PIR1bits.SSPIF = 0; // 清除中断标志
    }
}

//--------从机初始化---------------------
void I2C_INIT(void) {
    SDA_dir = 1;
    SCL_dir = 1;
    ADCON1bits.PCFG = 0b1111; // 所有引脚设为数字IO

    SSPADD = 0b0011110; // 7位从机地址(注意:不是带读写位的8位)
    SSPSTATbits.SMP = 0; // 标准速度模式下禁用斜率控制
    
    SSPCON1bits.SSPEN = 1; // 使能I2C模块
    SSPCON1bits.SSPM = 0b1110; // I2C从机模式,7位地址,支持起始/停止中断
    
    // 开启I2C中断
    PIE1bits.SSPIE = 1;
    INTCONbits.PEIE = 1; // 使能外设中断
    INTCONbits.GIE = 1;  // 使能全局中断
}

故障原因与修复要点

  • 从机地址配置错误:从机SSPADD应设为7位地址0b0011110,而非带读写位的8位地址0b00111100,确保与主机发送的地址(7位左移+写位)匹配。
  • 从机未发送应答:无论地址匹配还是数据接收,从机都需主动发送应答——设置ACKDT=0、触发ACKEN=1并等待完成,否则主机收不到应答会终止传输。
  • 从机中断未开启:必须开启SSPIE、PEIE、GIE三个中断控制位,否则I2C中断无法触发,无法处理地址和数据。
  • 从机SMP位设置错误:标准速度(100kHz)模式下,SSPSTATbits.SMP需设为0,符合I2C时序规范。
  • 主机代码语法错误:修复I2C_INIT函数末尾的括号错误,停止条件发送需使用SSPCON2bits.PEN=1。
  • 从机地址匹配时需读取SSPBUF:地址匹配后必须读取SSPBUF清除BF标志,否则后续无法接收数据。

内容的提问来源于stack exchange,提问作者Aizaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 07:07:32