我使用的ATmega328P TWI接口如下。
问题是它进入无限循环来选通LED,并且永远不会关闭LED。如果我将条件更改为
TRUE
,则会关闭 LED 并继续。
我已经明确说明了正在设置哪些位;让我知道更多详细信息会有帮助。
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)正在被设置,寄存器正在被读取,并且TWINT位(7)正在被测试。
我错过了什么?我以为我严格遵循数据表(特别是第 185 页),但 TWINT 从未被设置为指示 START 传输结束。
根据数据表(第180页),SCL频率= CPU时钟/(16 + 2 * TWBR * Prescale)。我将 TWBR 和 Prescale 设置为 0,所以我应该得到 16-MHz / 16 = 1-MHz。
注意: 我没有使用 avr-gcc 标准库,我使用自己的标准库,因为这是一个学习练习。我知道不建议使用位字段,但我认为我们看到生成的程序集是正确的。这是我的寄存器的链接方式:
SECTIONS {
/* TWI */
TWBR = 0xB8;
TWSR = 0xB9;
TWAR = 0xBA;
TWDR = 0xBB;
TWCR = 0xBC;
TWAMR = 0xBD;
...
查看第 199 页的数据表:
第 5 位 – TWSTA:
TWI 启动条件位 当应用程序希望成为 2 线串行总线上的主设备时,将 TWSTA 位写入 1。 TWI 硬件 检查总线是否可用,如果空闲,则在总线上生成 START 条件。不过,如果巴士不是免费的, TWI 等待直到检测到停止条件,然后生成新的启动条件以声明总线主状态。 当 START 条件发送后,TWSTA 必须由软件清零。
如果您想检查启动条件,您必须轮询此位
while (!TWCR & (1<<TWSTA))
{
asm volatile("NOP");
}
将启动条件写入总线后,TWSTA 标志表示可以完成传输...