главный колбасист, в вашей задаче чтения данных из 3231 достаточно было обойтись парой вложенных циклов и ветвлений. код получился бы достаточно компактный, но при этом гораздо более читаемый и без повторений одинаковых операций в разных местах...
А вот так запутанно бегать по коду - вы и сами запутаетесь, и код будет нечитаем. И ошибку с ACK/NACK легко можете пропустить.
Ну и экономия ОЗУ актуальна только если оно вам нужно для обработки большого массива каких то данных... Обычно программная память кончается быстрее

Соответственно, код лучше оптимизировать. Например, вот так:
Код: Выделить всё
1. Настройка i2c
2. i = 0
3. IIC_START i2c
4. IIC_SEND (3231_ADDR+i)
5. if (i = 0)
then begin
6. IIC_SEND 0x00 ;адрес, с которого мы будем читать данные из 3231
7. goto 16
end
else begin
8. j = 7 ; число байт, которые надо прочитать
9. Z = (адрес области памяти для чтения из 3231)
10. j = j - 1
11. if (j > 0) then IIC_READ_ASK
else IIC_READ_NASK
12. save DATA -> Z
13. Z = Z + 1
14. if (j > 0) then goto 10
15. end ; конец блока else для if (i=0)
16. i = i + 1
17. if ( i < 2 ) then goto 3
18. IIC_STOP
Я вот тут вам как то накидал в псевдокоде алгоритм чтения данных из 3231 (это "перепевка" из какой то из моих старых программ... Написана на некоем подобии языка высокого уровня, что бы было легче разобраться)
Обратите внимание, в строке 4 адрес 3231 должен задаваться в 8-битном формате - 1101000х (0xD0) - тогда для записи, когда i=0 - как раз уйдет адрес с режимом записи 11010000, а когда i станет 1 - по шине уйдет адрес 11010001 - режим чтения. Т.е. не нужно писать 2 отдельных блока для отправки адреса для записи и адреса для чтения.
Точно так же старт и повторный старт выполнятся в одном месте.
По использованию ОЗУ - нужно только 7 байт для данных из 3231, а так же 2 байта стека для вызова подпрограмм общения с i2c.
По регистрам - ZL/ZH на ссылку в ОЗУ, 2 регистра для i,j - переменных цикла, да пара временных регистров для общения с i2c
IIC_START, IIC_SEND, IIC_READ_ASK, IIC_READ_NASK, IIC_STOP - это подпрограммы работы с модулем i2c для вашего МК. Должны вызываться посредством CALL/RCALL
Сам блок работы с i2c
Спойлер
Код: Выделить всё
;--------------------------------------------------------
; I2C Code
;--------------------------------------------------------
; по мотивам DiHalt'a
;--------------------------------------------------------
; Работа с IIC передатчиком. Предупреждаю -- это быдлокод!
; Несмотря на то, что так делают почти все :)
; Но это медленно и тормозно, особенно в свете использования
; RTOS. Почему? Да потому что использует глухое
; ожидание флага готовности IIC. Вместо того, чтобы отдать
; управление диспетчеру задач. Также нет обработоки ошибок
; и какой либо оценки прошла команда или нет. Просто пример!
;---------------------------------------------------------
; IIS_START — устраивает на шине Start состояние
; IIC_SEND — посылает байт, просто байт. Не важно что это — адрес, данные…
; IIC_READ_ASK — команда противополжная предыдущей — принимает байт в конце дает ACK
; IIC_READ_NASK — тоже принимает байт, но в конце дает NACK, используется для приема последнего байта,
; чтобы дать понять Slave устройству что мы в его услугах больше не нуждаемся.
; IIS_STOP — устраивает на шине Stop состояниеи освобождает линию
;---------------------------------------------------------
; Последовательность инициализации TWI (i2c)-интерфейса
; Рассматривается только Master-режим
; В регистр TWBR, а так же в биты 0,1 (TWPS0:1) регистра TWSR записываются константы для определения скорости шины.
; (констатны можно рассчитать на AVRCalc)
;---------------------------------------------------------
; Последовательность чтения для IIC, на примере обычной EEPROM типа АТ24Схх обычно такая:
; Старт
; Адрес дейвайса[write]
; Адрес ячейки откуда будем читать
; Повторный Старт,
; Адрес девайса [read],
; Байт из адресованой ячейки,
; Байт из адресованой ячейки+1,
; Байт из адресованой ячейки+2
; ….
; Cтоп
;
; Последовательность записи для IIC обычно такая:
; Старт
; Адрес девайса [write]
; Адрес ячейки куда будем писать
; Данные раз
; Данные два
; Данные три
; …..
; Стоп
; [write] & [read] - младший бит адреса. =0 - запись, =1 - чтение
;
;---------------------------------------------------------
; примеры для работы с часами - см. http://easyelectronics.ru/chasy-realnogo-vremeni-pcf8583.html
;---------------------;
; Даем старт на линию I2C
; Портит R16,SREG
IIC_START:
LDI R16,1<<TWINT|1<<TWSTA|1<<TWEN|0<<TWIE
OUT TWCR,R16
IIC_S:
IN R16,TWCR
ANDI R16,1<<TWINT
BREQ IIC_S ; Ждем пока передатчик IIC выполнит старт
RET
;-----------------------------------------------------------------------------
;Посылаем байт (R16) по IIC
; Портит R16,SREG
IIC_SEND:
OUT TWDR,R16
LDI R16,1<<TWINT|1<<TWEN|0<<TWIE
OUT TWCR,R16
IIC_B:
IN R16,TWCR
ANDI R16,1<<TWINT ; Ждем пока передатчик пошлет байт
BREQ IIC_B
RET
;-----------------------------------------------------------------------------
; Принять байт.
; Принятый байт в R16
; Портит SREG
IIC_READ_ASK:
LDI R16,1<<TWINT|1<<TWEN|1<<TWEA|0<<TWIE
OUT TWCR,R16
IIC_R:
IN R16,TWCR
ANDI R16,1<<TWINT
BREQ IIC_R ; Ждем пока байт будет принят
IN R16,TWDR
RET
;-----------------------------------------------------------------------------
; Принять последний байт. Помните я писал о разнице между просто байтом и последним
; байтом? В последнем байте не генерируется ACK!!!
; Принятый байт в R16
; Портит SREG
IIC_RREAD_NACK:
LDI R16,1<<TWINT|1<<TWEN|0<<TWEA|0<<TWIE
OUT TWCR,R16
IIC_R2:
IN R16,TWCR
ANDI R16,1<<TWINT ; Ждем пока байт будет принят
BREQ IIC_R2
IN R16,TWDR
RET
;-----------------------------------------------------------------------------
; Сгенерировать STOP
; Портит R16,SREG
IIC_STOP:
LDI R16,1<<TWINT|1<<TWSTO|1<<TWEN|0<<TWIE
OUT TWCR,R16
IIC_ST:
IN R16,TWCR
ANDI R16,1<<TWSTO
BREQ IIC_ST ; Ждем пока не будет готов стоп.
RET