我正在使用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_AVR\I2C_TWI\I2C_TWI.asm(41,0): error: Operand 1 out of range: 0xb9
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(43,0): error: Operand 1 out of range: 0xb8
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(45,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(51,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(53,0): error: Operand 2 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(60,0): error: Operand 1 out of range: 0xbb
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(62,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(64,0): error: Operand 2 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(72,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(78,0): error: Operand 1 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_TWI.asm(80,0): error: Operand 2 out of range: 0xbc
D:\ATMEL_AVR\I2C_TWI\I2C_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
答案 0 :(得分:1)
在AVR中,通常所有I / O寄存器都从地址0x0020
开始映射到内存空间中
in
和out
指令只能与前64个指令一起使用(具有0x20 ... 0x5F的存储器地址)
sbi
,cbi
,sbis
和sbic
还有更多限制,只能与前32个I / O注册(内存地址0x20 ... 0x3F)一起使用。请参阅AVR Instruction Set Manual
在datasheet to ATmega2560的第33页“寄存器摘要”的第401页中,您可以看到TWI寄存器的地址为0xB8至0xBD,即,无法使用in
和out
来访问它们说明。您必须使用STS
和LDS
。
即LDS R21, TWCR
代替IN R21, TWCR
等。
此外,访问前64个寄存器时请务必小心。确保相应的名称定义了它们的I / O,而不是RAM地址。即PORTA应该等于0x02(in
/ out
指令的IO地址),而不是0x22(RAM地址或PORTA,当使用in
或out
访问时,其等于到EEARH寄存器)。