AVR TWI (I2C) 问题:操作数 1 超出范围



我正在使用Atmega2560和24c16A EEPROM来测试I2C代码。对于每个状态转换,控制器通过更改状态寄存器 TWSR 来响应。发送启动条件后,EEPROM响应,然后对器件地址和写入指令(SLA+R/W)进行响应,状态寄存器更新正常。但是当我传输接下来的 8 位时,而不是 ACK(发送 ACK 的数据字节),状态更改为重复启动。代码如下。我永远找不到可能的解决方案来使其工作。

.include "./m2560def.inc"
.list
.cseg
.org 0x00
jmp inicio      ; PC = 0x0000   RESET
inicio:
LDI R21, HIGH(RAMEND)           ;Set Up Stack
OUT SPH, R21
LDI R21, LOW(RAMEND)    
OUT SPL, R21
CALL I2C_INIT                   ;Initialize TWI(I2C)
CALL I2C_START                  ;Transmit START condition
LDI  R27, 0b11010000            ;SLA(0b1001100) + W(0)
CALL I2C_WRITE                  ;Write R27 ato the I2C bus
LDI  R27, 0b11110000            ;Data to be transmitted
CALL I2C_WRITE                  ;Write R27 ato the I2C bus
CALL I2C_STOP                   ;Transmit STOP condition
HERE: RJMP HERE
;----------------------------I2C_INIT-----------------------------
I2C_INIT:
LDI    R21, 0              
OUT    TWSR, R21           ;Set prescaler bits to 0
LDI    R21, 0x47           ;R21 = 0x47
OUT    TWBR, R21           ;Fclk = 50 KHz (8 MHz Xtal)
LDI    R21, (1<<TWEN)      ;R21 = 0x04
OUT    TWCR, R21           ;HEnable TWI (I2C)
RET
;----------------------------I2C_START-----------------------------
I2C_START: 
LDI    R21, (1<<TWINT)|1<<(TWSTA)|(1<<TWEN)
OUT    TWCR, R21           ;Transmit START condition
WAIT1:  
IN     R21, TWCR           ;Read Control Register TWCR into R21
SBRS   R21, TWINT          ;Skip the next line if TWINT is 1
RJMP   WAIT1               ;Jump a WAIT1 if TWINT is 1
RET  
;----------------------------I2C_WRITE -----------------------------
I2C_WRITE:
OUT    TWDR, R27           ;Move the byte into TWRD
LDI    R21,  (1<<TWINT)|(1<<TWEN)
OUT    TWCR, R21           ;Configure TWCR to send TWDR
WAIT3:
IN     R21, TWCR           ;Read Control Register TWCR into R21
SBRS   R21, TWINT          ;Skip the next line if TWINT is 1
RJMP   WAIT3               ;Jump a WAIT3 if TWINT is 1
RET
;----------------------------I2C_STOP------------------------------
I2C_STOP:
LDI    R21, (1<<TWINT)|1<<(TWSTO)|(1<<TWEN)
OUT    TWCR, R21           ;Transmit STOP condition
RET
;----------------------------I2C_READ------------------------------
I2C_READ:
LDI    R21,  (1<<TWINT)|(1<<TWEN)
OUT    TWCR, R21   
WAIT2:
IN      R21, TWCR           ;Read Control Register TWCR into R21
SBRS    R21, TWINT          ;Skip the next line if TWINT is 1
RJMP    WAIT2               ;Jump a WAIT2 if TWINT is 1
IN      R27, TWCR           ;Read received data into R21
RET

输出为

D:ATMEL_AVRI2C_TWII2C_TWI.asm(41,0): error: Operand 1 out of range: 0xb9
D:ATMEL_AVRI2C_TWII2C_TWI.asm(43,0): error: Operand 1 out of range: 0xb8
D:ATMEL_AVRI2C_TWII2C_TWI.asm(45,0): error: Operand 1 out of range: 0xbc
D:ATMEL_AVRI2C_TWII2C_TWI.asm(51,0): error: Operand 1 out of range: 0xbc
D:ATMEL_AVRI2C_TWII2C_TWI.asm(53,0): error: Operand 2 out of range: 0xbc
D:ATMEL_AVRI2C_TWII2C_TWI.asm(60,0): error: Operand 1 out of range: 0xbb
D:ATMEL_AVRI2C_TWII2C_TWI.asm(62,0): error: Operand 1 out of range: 0xbc
D:ATMEL_AVRI2C_TWII2C_TWI.asm(64,0): error: Operand 2 out of range: 0xbc
D:ATMEL_AVRI2C_TWII2C_TWI.asm(72,0): error: Operand 1 out of range: 0xbc
D:ATMEL_AVRI2C_TWII2C_TWI.asm(78,0): error: Operand 1 out of range: 0xbc
D:ATMEL_AVRI2C_TWII2C_TWI.asm(80,0): error: Operand 2 out of range: 0xbc
D:ATMEL_AVRI2C_TWII2C_TWI.asm(83,0): error: Operand 2 out of range: 0xbc
Assembly failed, 12 errors, 0 warnings

这些错误中涉及的代码行包括:

OUT    TWSR, R21
OUT    TWBR, R21
OUT    TWCR, R21
OUT    TWCR, R21
IN     R21, TWCR   
OUT    TWDR, R27
OUT    TWCR, R21
IN     R21, TWCR
OUT    TWCR, R21
OUT    TWCR, R21
IN     R21, TWCR
IN     R27, TWCR

在 AVR 中,通常所有 I/O 寄存器都映射到内存空间,从地址0x0020开始

inout指令只能与其中的前 64 条一起使用(0x20...0x5F内存地址)sbicbisbissbic有进一步的限制,只能与前32个I/O寄存器一起使用(内存地址0x20...0x3F).请参考 AVR 指令集手册

在 ATmega2560 的数据表第 33 节"寄存器摘要"第 401 页中,您可以看到 TWI 寄存器具有0xB8 0xBD的地址,即无法使用inout指令访问它们。你必须使用STSLDS. 即LDS R21, TWCR而不是IN R21, TWCR等。

此外,访问前 64 个寄存器时始终要小心。确保相应的名称定义其 I/O 而不是 RAM 地址。即 PORTA 应等于 0x02(in/out指令的 IO 地址)而不是0x22(RAM 地址或 PORTA,当使用inout访问时,等于 EEARH 寄存器)。

最新更新