MSP430F249T I2C起始条件后传输失败问题求助
MSP430F249T I2C写操作失败:UCTXSTT始终置位、SDA卡低电平问题排查与修复
核心问题分析
- 总线空闲检查缺失:发送起始条件前未等待总线空闲,导致起始条件无法正常触发
- NACK处理逻辑错误:从机NACK后未发送停止条件就直接重试起始,导致总线状态混乱
- 初始化顺序与总线复位不规范:重新初始化时未正确处理总线忙状态,导致SDA引脚被锁定在低电平
具体修复方案
1. 修正I2C初始化函数
调整引脚复用配置顺序,确保USCI模块配置前引脚已正确复用,同时确认分频参数匹配SMCLK频率:
#pragma location = "APP_INTERNAL_SEG" void i2c_msp_init(unsigned char DevAddr, USHORT ClkIdDivisor) { P5SEL |= 0x06; // 先配置I2C引脚复用:SDA(P5.1)、SCL(P5.2) UCB1CTL1 = UCSWRST; // 进入软件复位模式 UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // 配置为主机、I2C模式、同步通信 UCB1CTL1 |= UCSSEL_2; // 选择SMCLK作为时钟源(保持软件复位状态) UCB1BR0 = LOBYTE(ClkIdDivisor); // 设置分频低字节 UCB1BR1 = HIBYTE(ClkIdDivisor); // 设置分频高字节 // 注意:确保SMCLK频率 / (BR1<<8 + BR0) = 目标I2C频率(如100kHz) UCB1I2CSA = DevAddr; // 设置从机地址 UCB1CTL1 &= ~UCSWRST; // 退出软件复位,启用USCI模块 }
2. 修正发送起始函数的逻辑
恢复总线空闲检查,正确处理NACK情况,添加标志位清除:
#pragma location = "APP_INTERNAL_SEG" BOOL i2c_msp_start_tx(void) { int count01; int count02; // 等待总线空闲,避免干扰正在进行的传输 count01 = 0; while(UCB1STAT & UCBBUSY) { count01++; if(count01 > COUNT_MAX) return FALSE; } UCB1STAT &= ~UCNACKIFG; // 提前清除NACK标志 UCB1CTL1 |= (UCTR | UCTXSTT); // 发送起始条件+从机地址(写模式) count01 = 0; while(UCB1CTL1 & UCTXSTT) // 等待起始+地址传输完成 { count01++; if(count01 > COUNT_MAX) { // 超时:发送停止条件释放总线 UCB1CTL1 |= UCTXSTP; while(UCB1CTL1 & UCTXSTP); return FALSE; } } // 处理从机NACK情况 count01 = 0; while(UCB1STAT & UCNACKIFG) { count01++; if(count01 > COUNT_MAX) { UCB1CTL1 |= UCTXSTP; while(UCB1CTL1 & UCTXSTP); return FALSE; } UCB1STAT &= ~UCNACKIFG; // 清除NACK标志 UCB1CTL1 |= UCTXSTP; // 先发送停止条件释放总线 while(UCB1CTL1 & UCTXSTP); // 等待停止条件完成 // 重新发送起始+地址 UCB1CTL1 |= (UCTR | UCTXSTT); count02 = 0; while(UCB1CTL1 & UCTXSTT) { count02++; if(count02 > COUNT_MAX) { UCB1CTL1 |= UCTXSTP; while(UCB1CTL1 & UCTXSTP); return FALSE; } } } return TRUE; }
3. 优化重新初始化的逻辑
避免每次传输都重新初始化I2C模块,若必须重启,需先释放总线:
// 如需重新初始化I2C,先执行以下操作释放总线 void i2c_msp_reset(void) { int count = 0; // 尝试发送停止条件释放总线 UCB1CTL1 |= UCTXSTP; while(UCB1CTL1 & UCTXSTP) { count++; if(count > COUNT_MAX) break; } // 进入软件复位模式 UCB1CTL1 = UCSWRST; // 重置引脚(可选,确保引脚状态正常) P5SEL &= ~0x06; P5DIR &= ~0x06; P5OUT |= 0x06; __delay_cycles(100); P5SEL |= 0x06; }
额外排查点
- 用示波器确认SMCLK频率是否符合预期,分频参数是否计算正确(SCL频率=SMCLK/(BR1*256+BR0))
- 检查从机设备是否上电、地址是否正确(I2C写操作时地址最后一位为0)
- 确认I2C总线上没有其他设备占用总线,或存在硬件短路(SDA/SCL对地短路会导致引脚卡低)
内容的提问来源于stack exchange,提问作者Andrea
相关产品推荐
相关产品推荐

