ATmega328P TWI发送起始条件后TWINT未置位导致无限循环问题
ATmega328P TWI接口TWINT位始终未置位问题排查
问题描述
我在使用ATmega328P的TWI接口时遇到异常:程序卡在LED闪烁的无限循环中,LED始终无法关闭。但如果将循环条件改为TRUE,LED能正常关闭,程序也可继续执行。
相关C代码
PASS_T twi_master_tx(U8_T addr, U8_T* data, SIZE_T len) { /* Set TWINT, TWSTA, and TWEN */ TWCR.byte = (1u << 7) | (1u << 5) | (1u << 2); /* Wait for start condition to be sent. */ while (FALSE == TWCR.bits.TWINT) { dsc_led_toggle(DSC_LED_CANBOARD_1); } dsc_led_set(DSC_LED_CANBOARD_1, OFF); ... }
编译生成的汇编代码
1dc6: 84 ea ldi r24, 0xA4 ; 164 1dc8: 80 93 bc 00 sts 0x00BC, r24 ; 0x8000bc <__DATA_REGION_ORIGIN__+0x5c> 1dcc: 80 91 bc 00 lds r24, 0x00BC ; 0x8000bc <__DATA_REGION_ORIGIN__+0x5c> 1dd0: 90 e0 ldi r25, 0x00 ; 0 1dd2: 87 ff sbrs r24, 7 1dd4: 14 c0 rjmp .+40 ; 0x1dfe <twi_master_tx.constprop.15+0x38>
已知信息
- 已确认寄存器
0x00BC(TWCR)被正确设置和读取,且检测的是第7位(TWINT) - 严格遵循datasheet第185页操作,但TWINT始终未置位以标识起始传输完成
- 根据datasheet第180页公式:
SCL频率 = CPU时钟 / (16 + 2 * TWBR * Prescale),将TWBR和Prescale设为0,预期得到1MHz的SCL频率 - 未使用avr-gcc标准库,自行实现用于学习;位字段虽不推荐,但生成的汇编代码是正确的
- 寄存器链接配置如下:
SECTIONS { /* TWI */ TWBR = 0xB8; TWSR = 0xB9; TWAR = 0xBA; TWDR = 0xBB; TWCR = 0xBC; TWAMR = 0xBD; ... }
可能的遗漏排查点
- 检查TWSR预分频位:TWSR寄存器的TWPS1、TWPS0位(前两位)默认可能不为0,需确保这两位被显式写入0。如果预分频位未清零,实际SCL频率会远低于预期,导致TWI硬件无法完成起始条件。
- 确认TWI模块未被电源管理禁用:检查PRR寄存器的PRTWI位,若该位为1会关闭TWI模块电源,导致硬件完全不工作,TWINT无法置位。需将PRTWI位设为0以启用TWI。
- 验证SDA/SCL引脚配置:TWI对应的SDA(PC4)和SCL(PC5)引脚必须配置为输入上拉模式。需确认DDRC的4、5位为0(输入),PORTC的4、5位为1(启用内部上拉电阻)。若引脚配置错误,总线无法正常通信,起始条件无法完成。
- 排查CPU时钟配置:确认CPU实际时钟频率为16MHz,若熔丝位配置错误导致时钟不符(比如使用内部8MHz振荡器),会导致SCL频率计算偏差,TWI硬件无法正常工作。
- 检查TWCR寄存器是否被意外修改:确保后续代码没有意外改写TWCR寄存器,导致TWINT位的检测逻辑失效。
内容的提问来源于stack exchange,提问作者Matt Murphy
相关产品推荐
相关产品推荐

