Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проблема с TWI
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Страницы: 1, 2, 3, 4, 5, 6
bodja74
Вот простейший код еще для слейва.
Будет работать в паре с кодом мастера ,что приводил выше.

Проверка $A0 это рестарт без стопа,ее можно внести повторив код например
обработчика старта,Но если мастер не делает рестарт это в принципе и не нужно.

Код
; TWI Slave
; Specify Device.
.include "m8def.inc"

      
.equ    SP     =$3D                      
                    
; Variable Declarations
.def temp     = r16
.def W        = r24    
.def X        = r26
.def Y        = r28
.def Z        = r30

.cseg                ; CODE segment.

.org 0          
                rjmp PROG        ; origin.
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        rjmp TWI_Finished;Вектор прерывания TWI
        reti
           
                          
PROG:           ldi r16,$F0    ;Инициализация стека
            out SP,r16
            
                ldi temp,$00    ;Инициализация TWI
        out TWSR,temp
                ldi temp,$00    ;
        out TWBR,temp
                ldi temp,$40
        out TWAR,temp
                ldi temp,$45
        out TWCR,temp

        ldi temp,$FF    ;Подключение порта D
        out DDRD,temp    
        sei        
cycle:        nop
        rjmp cycle            


TWI_Finished:    
        sts $0F1,temp    ;Сохранение помежуточного регистра
        in temp,TWSR
                cpi temp,$60    ;Проверка старт
                breq t1
                in temp,TWSR
                cpi temp,$80    ;Проверка дата
                breq t2

t1:        ldi temp,$C5    ;Обработка старт
        out TWCR,temp
        lds temp,$0F1    ;Востановление промежуточного регистра
        reti

t2:        ldi temp,$C5    ;Обработка дата
        out TWCR,temp
        in temp,TWDR
        out PORTD,temp    ;Выводим  полученный байт в порт D
        lds temp,$0F1    ;Востановление промежуточного регистра
        reti
James D.
bodja74, огромное Вам спасибо за помощь.
Все исправил. Работает.
В слэйве счетчик принимаемых байт не стал задействовать. После приема 1-го байта, и сохранения его в память, вызывается п/п:

Код
;*******************************************************************
TW_NT_n:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait2n: in  temp,TWCR ;Ожидаем ответа от мастера
  sbrs temp,TWINT
  rjmp wait2n

  in  temp,TWSR
  cpi  temp,$80
  brne STOP  ;Переход на STOP, если данные от мастера не получены

  ret
;*******************************************************************

STOP: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  reti


вызывается она столько раз, сколько байт надо принять. Может это и не правильно, но так удобнее. Ругайте...
Подключил второй слэйв. Прогу мастера подправил:

Код
SLA_Wn: ldi  temp,$20;Загрузка адреса слэйв + "WRITE" (или адрес $40 - для второго слэйва)
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEN)
  out  TWCR,temp

wait2n: in  temp,TWCR;Ожидаем ответа от слэйв
  sbrs temp,TWINT
  rjmp wait2n

  in  temp,TWSR;<<<<<<<Эти команды оставил, т.к., я думаю, для двух слэйвов они нужны (?)
  cpi  temp,$18
  brne STOP ;Переход, если ответ от слэйв неверный

;Начинаем передавать данные:

DATA:

;*******************************************************************
;Все данные переданы - STOP (линия приема/передачи переходит в высокоимпедансное состояние)

STOP: ldi  temp,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
  out  TWCR,temp


Данные на первый слэйв передаются. А вот на второй - чтобы сказать наверняка, нужно теперь мастеру со второго слэйва принять данные.
Потом информация выводится на LCD-индикатор, и можно быть уверенным в результате.

Насчет паузы после STOP.
Прога мастер-передатчик запускается около 30 раз в секунду, я думаю, этого достаточно, чтобы не делать специальную паузу.

Как теперь организовать прием мастером данных от слэйв2?
James D.
Сейчас прикинул как сделать.

Мастер:
1. мастер после передачи данных, выдает STOP,
2. пауза,
3. опять настраивает скорость, выдает START,
4. ожидает ответ интерфейса,
5. выдает адрес слэйв2 - $41 в TWDR,
6. ожидает ответ от слэйв2,
7. проверяет код в TWSR=$50, сохраняет полученный байт, иначе STOP,
8. ждет следующий байт, и т.д.
9. STOP.

Правильно?

Слэйв:
1. после приема последнего байта, и получения STOP, ждет следующего прерывания,
2. принимает START+адрес+R,
3. проверяет код в TWSR=$A8, иначе STOP,
4. выдает байт данных,
5. проверяет код в TWSR=$B8, иначе STOP...

Вобщем тут я пока без четкого алгоритма...
bodja74
Цитата(James D. @ Dec 25 2005, 15:15) *
bodja74, огромное Вам спасибо за помощь.
Все исправил. Работает.

Рад слышать что появились здвиги,Теперь можно потихоничку подключать проверку TWSR.
В мастере с этим внимательно.Если Вы занесли вначале программы значение предделителяв TWSR
То и зачение при проверке TWSR увеличиться на столько же.

Цитата
В слэйве счетчик принимаемых байт не стал задействовать. После приема 1-го байта, и сохранения его в память, вызывается п/п:

Дело Ваше,но при этом прога будет крутиться в цикле обработчика,основная прога выполняться не будет.
Цитата
Данные на первый слэйв передаются. А вот на второй - чтобы сказать наверняка, нужно теперь мастеру со второго слэйва принять данные.
Потом информация выводится на LCD-индикатор, и можно быть уверенным в результате.

Насчет паузы после STOP.
Прога мастер-передатчик запускается около 30 раз в секунду, я думаю, этого достаточно, чтобы не делать специальную паузу.

Если между стопом и стартом будет приличная пауза ,пожалуста.
Цитата
Как теперь организовать прием мастером данных от слэйв2?


Тоже самое что и при передаче только адресс указываем $41(20) , $21(10),и не передаем
в TWDR а илвлекаем.
James D.
Мастер:
Код


;*************************
;Передача на слэйв 2:
;*************************

  ldi  temp,$14;Установка скорости передачи= ? kHz
  out  TWBR,temp
  ldi  temp,$00
  out  TWSR,temp

Pusk_Sr:ldi  temp,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
  out  TWCR,temp;Посылка сигнала "START"

wait1r: in  temp,TWCR;Ожидаем ответа интерфейса
  sbrs temp,TWINT
  rjmp wait1r

SLA_Wr: ldi  temp,$40;Загрузка адреса слэйв2 + "WRITE"
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEN)
  out  TWCR,temp

wait2r: in  temp,TWCR;Ожидаем ответа от слэйв2
  sbrs temp,TWINT
  rjmp wait2r

  in  temp,TWSR
  andi temp,$F8
  cpi  temp,$18
  brne STOP_r ;Переход, если ответ от слэйв2 неверный

;Начинаем передавать данные:

DATA_r: out  TWDR,Byte1 ;Отправка: 1-ый байт
  rcall Writer
  out  TWDR,Byte2 ;Отправка: 2-ой байт
  rcall Writer
  
  rjmp STOP_r  ;Передача данных завершена

;*******************************************************************
Writer: ldi  temp,(1<<TWINT)|(1<<TWEN)
  out  TWCR,temp

wait3r: in  temp,TWCR;Ожидаем ответа от слэйв2
  sbrs temp,TWINT
  rjmp wait3r

  in  temp,TWSR
  cpi  temp,$28
  brne STOP_r ;Переход, если ответ от слэйв2 неверный

  ret
;*******************************************************************
;Все данные переданы - STOP (линия приема/передачи переходит в высокоимпедансное состояние)

STOP_r: ldi  temp,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
  out  TWCR,temp

PAUSE: ldi  temp,$40;Пауза, чтобы модуль TWI смог завершить команду СТОП
  ldi  r25,$00
  dec  temp
  cpse temp,r25
  rjmp PAUSE

;*******************************************************************

;*************************
;Прием со слэйв2:
;*************************

  ldi  temp,$14;Установка скорости передачи= ? kHz
  out  TWBR,temp
  ldi  temp,$00
  out  TWSR,temp

  ldi  temp,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
  out  TWCR,temp;Посылка сигнала "START"

waitR1: in  temp,TWCR;Ожидаем ответа интерфейса
  sbrs temp,TWINT
  rjmp waitR1

  ldi  temp,$41;Загрузка адреса слэйв2 + "READ"
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

waitR2: in  temp,TWCR;Ожидаем ответа слэйв2
  sbrs temp,TWINT
  rjmp waitR2

  in  temp,TWSR
  cpi  temp,$40
  brne STOP_RD ;Переход, если ответ от слэйв2 неверный

;*******
;Прием данных:

Data: rcall TW_NT_R  ;Прием: 1-ый байт
  in  temp,TWDR
  sts  Byte1,temp
  rcall TW_NT_R  ;Прием: 2-ой байт
  in  temp,TWDR
  sts  Byte2,temp

  rjmp STOP_RD  ;Передача данных завершена

;*******************************************************************
TW_NT_R:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

waitRr: in  temp,TWCR ;Ожидаем ответа от слэйв2
  sbrs temp,TWINT
  rjmp waitRr

  in  temp,TWSR
  cpi  temp,$50
  brne STOP_RD  ;Переход, если данные от слэйв2 не получены

  ret

;*******************************************************************
STOP_RD:ldi  temp,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
  out  TWCR,temp

Далее выполняется основная программа.
;*******************************************************************


Проблема: дописал для мастера прием данных - мастер стал зависать.
Сейчас выложу прогу слейва2.
James D.
Слэйв2:

Код
;Инициализация TWI:

  ldi  temp,$40 ;Инициализация режима "Приемник" - адрес
  out  TWAR,temp
  ldi  temp,$00
  out  TWSR,temp
  ldi  temp,(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  sei

;***** Основной Цикл: *****

START: rjmp START

;*******************************************************************
;Режим - подчиненный-приемник/передатчик:

TWI_Obr:in  temp,TWSR
  cpi  temp,$60;Проверка принятого адреса от мастера
  breq Address
  cpi  temp,$80;Прием данных
  breq DataR
  cpi  temp,$A8;Передача данных
  breq DataT

  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;*******
Address:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;Прием данных:

DataR: in  Byte1,TWDR ;Прием: 1-ый байт
  rcall TW_NT_n
  in  Byte2,TWDR ;Прием: 2-ой байт

  rjmp STOP_n

;*******************************************************************
TW_NT_n:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait2n: in  temp,TWCR ;Ожидаем ответа от мастера
  sbrs temp,TWINT
  rjmp wait2n

  in  temp,TWSR
  cpi  temp,$80
  brne STOP_n  ;Переход, если данные от мастера не получены

  ret

;*******************************************************************
;Все данные приняты - STOP (линия приема/передачи переходит в высокоимпедансное состояние)

STOP_n: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  reti

;*******************************************************************

;Передача данных:

DataT: out  TWDR,Byte1 ;Отправка: 1-ый байт
  rcall Write
  out  TWDR,Byte2 ;Отправка: 2-ой байт
  rcall Write
  
  rjmp STOP_n  ;Передача данных завершена
;*******************************************************************
Write: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait3n: in  temp,TWCR ;Ожидаем ответа от мастера
  sbrs temp,TWINT
  rjmp wait3n

  in  temp,TWSR
  cpi  temp,$B8
  brne STOP_n  ;Переход, если ответ от мастера неверный

  ret

;*******************************************************************


P.S. Слэйв не зависает.
bodja74
По мастеру похоже все верно.
bodja74
Блин Вроде все верно,
единственно нужно попробовать увеличить паузу она у меня на 400кГц
а здесь приблизительно 60кГц.
И еще,попробуйте этот участок по прерыванию сделась все таки

Write: ldi temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
out TWCR,temp

wait3n: in temp,TWCR ;Ожидаем ответа от мастера
sbrs temp,TWINT
rjmp wait3n

in temp,TWSR
cpi temp,$B8
brne STOP_n ;Переход, если ответ от мастера неверный

ret
James D.
Скорость приема/передачи = 71429 Hz
Паузу увеличил в 4 раза ($FF).
Но мастер зависает все равно.
Сделал для простоты так: мастер передает на слэйв2 один байт и один байт принимает. Связь со слэйв1 оставил, как и было - там мастер только передает около 10 байт.
Я пока не совсем четко понимаю, мастер, после приема последнего байта, должен выдавать NACK? Какие еще коды TWSR надо обрабатывать?

Слэйв переписал:

Код
;*******************************************************************
;Режим - подчиненный-приемник/передатчик:

TWI_Obr:in  temp,TWSR
  cpi  temp,$60;Проверка принятого адреса от мастера
  breq Address
  cpi  temp,$80;Прием данных
  breq DataR
  cpi  temp,$A8;Передача данных
  breq DataT

  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;*******
Address:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;Прием данных:

DataR: in  Byte,TWDR ;Прием

  rjmp STOP_n

;*******************************************************************
TW_NT_n:

;*******************************************************************
;Все данные приняты - STOP (линия приема/передачи переходит в высокоимпедансное состояние)

STOP_n: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  reti

;*******************************************************************

;Передача данных:

DataT: out  TWDR,Byte ;Отправка

  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti
James D.
Не понял... У меня мастер из паузы не выходит:

PAUSE: ldi temp,$FF ;Пауза, чтобы модуль TWI смог завершить команду СТОП
ldi r17,$00
dec temp
cpse temp,r17
rjmp PAUSE

Что за дела?
bodja74
Цитата(James D. @ Dec 25 2005, 23:22) *
Не понял... У меня мастер из паузы не выходит:

PAUSE: ldi temp,$FF ;Пауза, чтобы модуль TWI смог завершить команду СТОП
ldi r17,$00
dec temp
cpse temp,r17
rjmp PAUSE

Что за дела?


Ну так мы же с Вами великие программеры.

PAUSE: ldi temp,$FF ;Пауза, чтобы модуль TWI смог завершить команду СТОП
P: ldi r17,$00
dec temp
cpse temp,r17
rjmp P
James D.
Да ну ё-моё!!! Вот это лажа!!! :-)
James D.
Зависает в мастере здесь:

waitR1: in temp,TWCR ;Ожидаем ответа интерфейса
sbrs temp,TWINT
rjmp waitR1

Twint в "1" не устанавливается.
Petka
Добавьте в код слэйва в обработчик прерываний обработку слудующих событий:
case 0x00:
TWCR=0b11010101;
case 0xF8: // No relevant state information available; TWINT = "0"
James D.
Так правильно?
Не совсем понял, как надо обработать состояние $F8?

Код
;*******************************************************************
;Режим - подчиненный-приемник/передатчик:

TWI_Obr:in  temp,TWSR
  cpi  temp,$60;Проверка принятого адреса от мастера
  breq Address
  cpi  temp,$80;Прием данных
  breq DataR
  cpi  temp,$A8;Передача данных
  breq DataT
  cpi  temp,$00;
  breq Sob_00
  cpi  temp,$F8;
  breq Sob_F8


  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

Sob_00: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWSTO)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

Sob_F8: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWSTO)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

При таком раскладе все равно зависает мастер.
bodja74
Я еще слейв в режиме передатчика не делал (небыло надобности)
Сегодня - завтра разберусь и выложу как точно должно быть.

Скорее всего слейв не правильно обрабатывает прерывание и "затягивает"
ACK ,и из за этого "зависает" TWINT и Мастер соответственно не может продолжить
передачу пакета.
Petka
при событии 0xF8 надо просто выйти из прерывания НИЧЕГО не делая.
bodja74
ВСЕ!!!

Добил.

Думаю разберетесь.

Код мастера

Код
; TWI Master
; Specify Device.
.include "m8def.inc"

      
                    
                    
; Variable Declarations
.def temp     = r16
.def temp_a   = r17
.def adress   = r18
.def data     = r19
.def W        = r24    
.def X        = r26
.def Y        = r28
.def Z        = r30

.cseg                ; CODE segment.

.org 0; origin.

        
                  
PROG:           ldi temp,$04        ; Initialize the stack.
            out SPH,temp
                ldi temp,$5F            
            out SPL,temp
        ldi temp,$00
                out TWBR,temp
                ldi temp,$00
                out TWSR,temp

        ldi temp,$FF
        out DDRD,temp

        ldi   adress,$41;Получаем
                 rcall TWI_START
                rcall TWI_DATA_R_ACK
                rcall TWI_DATA_R_NACK;При при получении последнего байта нужно
        rcall TWI_STOP    ;обязательно указывать NACK
                rcall PAUSE


                ldi   adress,$40       ;Отправляем
                rcall TWI_START
                ldi   data,$FF
                rcall TWI_DATA
                rcall TWI_DATA
                rcall TWI_STOP
                rcall PAUSE

        ldi   adress,$40
                 rcall TWI_START
                rcall TWI_DATA
                rcall TWI_STOP
                rcall PAUSE

        ldi   adress,$41
                 rcall TWI_START
                rcall TWI_DATA_R_ACK
                rcall TWI_DATA_R_NACK
        rcall TWI_STOP
                rcall PAUSE


end:        rjmp end

TWI_START:  
                ldi temp,$A4
                out TWCR,temp
s1:             in  temp,TWCR
                sbrs temp,7
               rjmp s1
            
                out TWDR,adress
                ldi temp,$C4
                out TWCR,temp
s2:             in  temp,TWCR
                sbrs temp,7
                rjmp s2
                ret

TWI_DATA:       out TWDR,data
                ldi temp,$C4
                out TWCR,temp
d1:             in  temp,TWCR
                sbrs temp,7
               rjmp d1  
                ret

TWI_STOP:       ldi temp,$94
                out TWCR,temp
                ret

PAUSE:          ldi temp,$40
              ldi temp_a,$00
p:                dec temp
            cpi temp,$00
                brne p
        ret

TWI_DATA_R_NACK:ldi temp,$84
                out TWCR,temp
d2:             in  temp,TWCR
               sbrs temp,7
                rjmp d2
        in temp,TWDR
        out PORTD,temp
                ret
        
TWI_DATA_R_ACK: ldi temp,$C4
                out TWCR,temp
d3:             in  temp,TWCR
               sbrs temp,7
                rjmp d3
        in temp,TWDR
        out PORTD,temp
                ret


Код слейва

Код
; TWI Slave
; Specify Device.
.include "m8def.inc"

      
                    
                    
; Variable Declarations
.def temp     = r16
.def temp_a   = r17
.def adress   = r18
.def data     = r19
.def W        = r24    
.def X        = r26
.def Y        = r28
.def Z        = r30

.cseg                ; CODE segment.

.org 0          
                rjmp PROG        ; origin.
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        rjmp TWI_Finished
        reti
           
                          
PROG:           ldi r16,$04    ; Initialize the stack.
            out SPH,r16
                ldi r16,$5F            
            out SPL,r16
                ldi temp,$00    ; Инициализация TWI
        out TWSR,temp
                ldi temp,$00    ;
        out TWBR,temp
                ldi temp,$40
        out TWAR,temp
                ldi temp,$45
        out TWCR,temp
                ldi temp,$FF
        out DDRD,temp
        sei        
end:        rjmp end     ; конец программы          


TWI_Finished:    
        sts $0F1,temp
        in temp,TWSR
                cpi temp,$60
                breq t1
                in temp,TWSR
                cpi temp,$80
                breq t2
        in temp,TWSR
                cpi temp,$A8
                breq t3
        in temp,TWSR
                cpi temp,$B0
                breq t3
        in temp,TWSR
                cpi temp,$B8
                breq t4
       
    
                ldi temp,$C5
        out TWCR,temp
        reti



t1:        ldi temp,$C5    ;Определяем Адресс.Мастер передает
        out TWCR,temp
        
        reti

t2:        in temp,TWDR    ;Получаем данные
        out PORTD,temp
        ldi temp,$C5
        out TWCR,temp
        
        reti

t3:        ldi temp,$01    ;Определяем Адресс.Мастер получает 1 байт
        out TWDR,temp
        ldi temp,$C5
        out TWCR,temp
        ldi temp,$01
        out TWDR,temp
        reti

t4:        ldi temp,$02    ;Мастер получает 2 байт и далее
        out TWDR,temp
        ldi temp,$85    ;$85 последний байт, $C5 далее
        out TWCR,temp
        reti


Пробуйте.
James D.
Вроде все исправил, но мастер зависает в том же месте.
Слейв2 не хочет принимать свой адрес.
Вопросы:
1. Почему у вас везде TWBR=0? Значение ведь должно быть не менее 10?
2. В вашей проге мастер сначала принимает 2 байта, отправляет 2 байта, отправляет 1 байт, и, наконец принимает 2 байта. Я же сделал, чтобы мастер отправлял 2 байта, а потом принимал 6 байт (впрочем, до приема дело не доходит). Это же не принципиально важно?
3. В проге слейва, в этом месте:

t3: ldi temp,$01 ;Определяем Адресс.Мастер получает 1 байт
out TWDR,temp
ldi temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
out TWCR,temp
ldi temp,$01
out TWDR,temp
reti

зачем 2 раза заносить значение в TWDR?

Ситуация у меня, наверное, осложняется присутствием на шине 2-х слейвов. В слейве1 прием данных завершается командой:

STOP: ldi temp,(1<<TWINT)|(1<<TWEN)|(1<<TWIE)
out TWCR,temp
reti

Слейв1 ничего не передает мастеру - только принимает. После этого идет передача/прием на слейв2.
bodja74
1.Моя ошибка в мастере(я этот код использовал в симуляторе для ускорения процесса просмотра)
Нужно TWSR=$02 TWBR=$02 ( или по другому по Вашему усмотрению)Для слейва не обязательно,ему все равно с какой скоростью передаются даннные.

2.Да ,не важно ,просто проба разных вариантов.Что нужно учесть я в коментариях написал.

3.Пробовал посто разные варианты заносить данные до и после TWCR,
забыл выбросить 2 отправку когда "чистил" код.

Я еще попробую с двумя слейвами поработать,возможно косяки из за двух слейвов,посмотрим.
bodja74
Вот исправленный код для мастера.
Должен работать с двумя слейвами.
У слейвов код тотже.
Код
; TWI Master
; Specify Device.
.include "m8def.inc"

      
                    
                    
; Variable Declarations
.def temp     = r16
.def temp_a   = r17
.def adress   = r18
.def data     = r19
.def W        = r24    
.def X        = r26
.def Y        = r28
.def Z        = r30

.cseg                ; CODE segment.

.org 0; origin.

        
                  
PROG:           ldi temp,$04        ; Initialize the stack.
            out SPH,temp
                ldi temp,$5F            
            out SPL,temp
        ldi temp,$02
                out TWBR,temp
                ldi temp,$02
                out TWSR,temp

        ldi temp,$FF
        out DDRD,temp



                ldi   adress,$40        
                rcall TWI_START
                ldi   data,$F0
                rcall TWI_DATA
                rcall TWI_DATA
                rcall TWI_STOP
                rcall PAUSE

                ldi   adress,$20        
                rcall TWI_START
                ldi   data,$0F
                rcall TWI_DATA
                rcall TWI_DATA
                rcall TWI_STOP
                rcall PAUSE

        ldi   adress,$41
                 rcall TWI_START
                rcall TWI_DATA_R_ACK
                rcall TWI_DATA_R_NACK
                rcall TWI_STOP
                rcall PAUSE

        ldi   adress,$21
                 rcall TWI_START
                rcall TWI_DATA_R_ACK
                rcall TWI_DATA_R_NACK
                rcall TWI_STOP
                rcall PAUSE

end:        rjmp end

TWI_START:  
                ldi temp,$A4
                out TWCR,temp
s1:             in  temp,TWCR
                sbrs temp,7
               rjmp s1
            
                out TWDR,adress
                ldi temp,$C4
                out TWCR,temp
s2:             in  temp,TWCR
                sbrs temp,7
                rjmp s2
                ret

TWI_DATA:       out TWDR,data
                ldi temp,$C4
                out TWCR,temp
d1:             in  temp,TWCR
                sbrs temp,7
               rjmp d1  
                ret

TWI_STOP:       ldi temp,$94
                out TWCR,temp
                ret

PAUSE:          ldi temp,$40
              ldi temp_a,$00
p:                dec temp
            cpi temp,$00
                brne p
        ret

TWI_DATA_R_NACK:ldi temp,$84
                out TWCR,temp
d2:             in  temp,TWCR
               sbrs temp,7
                rjmp d2
        in temp,TWDR
        out PORTD,temp
                ret
        
TWI_DATA_R_ACK: ldi temp,$C4
                out TWCR,temp
d3:             in  temp,TWCR
               sbrs temp,7
                rjmp d3
        in temp,TWDR
        out PORTD,temp
                ret


Пробуйте.
James D.
Да не получается ничего. Та же беда.
James D.
Сделал, ради эксперимента, еще такой финт.
Мастер пересылает слейву2 2 байта, после этого инициализируется как приемник с адресом $60, а слейв2 - как мастер. Должно переслаться 6 байт. Так вот, один раз прием/передача проходит, а потом мастер опять зависает.
Но все-таки хотелось бы, чтобы мастер передавал/принимал данные как положено - без переинициализации.
bodja74
У вас код слейва2 ,тот же?
Если нет,выкладывайте.
Если у мастера есть проверки TWSR,временно уберите.

Еще не стоит забывать,что у слейва передатчика в 18 раз меньше времени
на обработку прерываения ,чем у слейва приемника,поэтому контроллер слейва
лучше тактировать на максимальной частоте+подпрограмма прерывания должна быть коротенькая.
James D.
Код слейва2:

Код
;Инициализация TWI:

  ldi  temp,$40 ;Инициализация режима "Приемник" - адрес
  out  TWAR,temp
  ldi  temp,$00
  out  TWSR,temp
  ldi  temp,$14
        out  TWBR,temp
  ldi  temp,(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  sei

;***** Основной Цикл: *****

START: rjmp START

;*******************************************************************
;Режим - подчиненный-приемник/передатчик:

TWI_Obr:in  temp,TWSR
  cpi  temp,$60;Проверка принятого адреса от мастера
  breq Address
  cpi  temp,$80;Прием данных
  breq DataR

  cpi  temp,$A8;Передача данных
  breq DataT1
  cpi  temp,$B0;
  breq DataT1
  cpi  temp,$B8;
  breq DataT2

  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  reti

;*******
Address:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  reti

;Прием данных:

DataR: in  Byte_1,TWDR ;Прием: байт 1
  rcall TW_NT_n
  in  Byte_2,TWDR ;Прием: байт 2

  rjmp STOP_n

;*******************************************************************
TW_NT_n:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait2n: in  temp,TWCR ;Ожидаем ответа от мастера
  sbrs temp,TWINT
  rjmp wait2n

  ret

;*******************************************************************
;Все данные приняты - STOP (линия приема/передачи переходит в высокоимпедансное состояние)

STOP_n: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

;*******************************************************************

;Передача данных:

DataT1: out  TWDR,Byte_3 ;Отправка: байт 3
  rcall Write
  out  TWDR,Byte_4 ;Отправка: байт 4
  rcall Write
  out  TWDR,Byte_5 ;Отправка: байт 5
  rcall Write
  out  TWDR,Byte_6 ;Отправка: байт 6
  rcall Write
  out  TWDR,Byte_7 ;Отправка: байт 7
  rcall Write

DataT2: out  TWDR,Byte_8 ;Отправка: байт 8

  ldi  temp,(1<<TWINT)|(1<<TWEN)|(1<<TWIE)   ;последний байт
  out  TWCR,temp

  reti
  
;*******************************************************************
Write: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

wait3n: in  temp,TWCR;Ожидаем ответа от мастера
  sbrs temp,TWINT
  rjmp wait3n

  ret

;*******************************************************************


Код слейва1 такой же, но там только принимаются данные.
James D.
Код слейва 1:

Код
;Инициализация TWI:

  ldi  temp,$20;Инициализация режима "Приемник"
  out  TWAR,temp
  ldi  temp,$00
  out  TWSR,temp
  ldi  temp,(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  sei

;***** Основной Цикл: *****

START: rjmp START



;*******************************************************************
;Режим - подчиненный-приемник:

TWI_Obr:in  temp,TWSR
  cpi  temp,$60;Проверка принятого адреса от мастера
  breq Address
  cpi  temp,$80;Прием данных
  breq Data
  cpi  temp,$00;
  breq Sob_00
  cpi  temp,$F8;
  breq Sob_F8

  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  reti

Sob_00: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWSTO)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

Sob_F8: reti

;*******
Address:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;*******
;Прием данных:

Data: in  Byte_1,TWDR ;Прием: байт 1

Data2: rcall TW_NT_n  ;Прием: байт 2
  in  Byte_2,TWDR

Data3: rcall TW_NT_n  ;Прием: байт 3
  in  temp,TWDR
  sts  Byte_3,temp

  rjmp STOP_n

;*******************************************************************
TW_NT_n:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait2n: in  temp,TWCR ;Ожидаем ответа от мастера
  sbrs temp,TWINT
  rjmp wait2n

  ret

;*******************************************************************
;Все данные приняты - STOP (линия приема/передачи переходит в высокоимпедансное состояние)

STOP_n: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  reti
;*******************************************************************
James D.
Почему-то редактирование сообщений не работает, в слейве2 исправить:
;*******************************************************************
;Все данные приняты - STOP (линия приема/передачи переходит в высокоимпедансное состояние)

STOP_n: ldi temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
out TWCR,temp
reti
bodja74
Вот здесь Вы разрешаете прерывание (1<<TWIE)
Write: ldi temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
out TWCR,temp

wait3n: in temp,TWCR;Ожидаем ответа от мастера
sbrs temp,TWINT
rjmp wait3n

ret
Из за чего могут возникнуть коллизии в программе.

Кроме того нужно проверить возможность вкладывать в обработку прерывания
подппрограмму для второго и последющих батов.Буде работать или нет.

Дальше
DataT1: Здесь мы отправляем только первый байт.
DataT2: Здесь мы отправляем второй ,последуюшие и последний байт.
картошка
Непонимаю радости использовать аппаратный TWI.
Вот отработанный мною годами код к програмной реализации аналога I2C. Может одумаетесь. Особых преимуществ невижу. А на этом коде можно увеличить несущюю CLK cranky.gif .

Определяете четыре константы и все.

.equ DDRX = DDRX (любой порт DDRX - выбора направления)
.equ PINX = PINX (любой порт PINX конечно тотже триады что и DDRX)
.equ XSCL = 0-7
.equ XSDA = 0-7

; Примечание :
; можете цеплять внешние сопротивления и на 1.5 вольта - будет работать. Работала несущая и на 1.5 mbю

InstallI2C:
cbi DDRX,XSCL ; установка линии SCL в 1
cbi DDRX,XSDA ; установка линии SDA в 1
ret
StartI2C:
rcall PausI2C
cbi DDRX,XSDA ; установка в 1
rcall PausI2C
cbi DDRX,XSCL ; установка в 1
rcall PausI2C
sbi DDRX,XSDA ; установка в 0
rcall PausI2C
sbi DDRX,XSCL ; установка в 0
rcall PausI2C
ret
StopI2C:
sbi DDRX,XSDA
sbi DDRX,XSCL
rcall PausI2C
cbi DDRX,XSCL
rcall PausI2C
cbi DDRX,XSDA
rcall PausI2C
ret



; Вход: R24-data и устанавливае фла переноса если ASK=1
DataOutI2C:
ldi r30,8
doq1a: rol r24
brcs doq2a
sbi DDRX,XSDA
rjmp doq3a
doq2a: cbi DDRX,XSDA
doq3a: rcall I2CPulse
dec r30
brne doq1a
cbi DDRX,XSDA
rcall PausI2C
cbi DDRX,XSCL
rcall PausI2C
in r24,PINX
sbi DDRX,XSCL
rcall PausI2C
clc
sbrc r24,XSDA
sec
ret

; Выход: R24-data и устанавливае фла переноса если ASK=1
DataInI2C:
push r30
ldi r30,8
diiq1: rcall PausI2C
cbi DDRX,XSCL
rcall PausI2C
in r31,PINX
sbi DDRX,XSCL
clc
sbrc r31,XSDA
sec
rol r24
dec r30
brne diiq1
rcall PausI2C
sbi DDRX,XSDA ; 0
rcall PausI2C
cbi DDRX,XSCL ; 1
rcall PausI2C
sbi DDRX,XSCL ; 0
rcall PausI2C
cbi DDRX,XSDA ; 0
rcall PausI2C
pop r30
ret

I2CPulse:
rcall PausI2C
sbi DDRX,XSCL
rcall PausI2C
cbi DDRX,XSCL
rcall PausI2C
sbi DDRX,XSCL
rcall PausI2C
ret

PausI2C:
push r30
ldi r30,8
doq33: dec r30
brne doq33
pop r30
ret


Моя будущая веб-страница
bodja74
1 А я не вижу радости в программном TWI.Тоже делал,тоже прошел.
2 Не вижу кода для слейва.
3 Код для мастера обсуждался и работает и куда коротче вашего,при таком раскладе.
4 Преимужества?Как насчет возможности использовать мастер по прерыванию и разгрузить основной проц процентов на 90 ?
5 А как насчет того ,если мы захотим вцепить 2 мастера?Ваш код будет дожидаться когда освободиться шина?Или среагирует при арбитраже?
картошка
Цитата(bodja74 @ Dec 30 2005, 21:02) *
1 А я не вижу радости в программном TWI.Тоже делал,тоже прошел.
2 Не вижу кода для слейва.
3 Код для мастера обсуждался и работает и куда коротче вашего,при таком раскладе.
4 Преимужества?Как насчет возможности использовать мастер по прерыванию и разгрузить основной проц процентов на 90 ?
5 А как насчет того ,если мы захотим вцепить 2 мастера?Ваш код будет дожидаться когда освободиться шина?Или среагирует при арбитраже?


Простите. Недоглядел. blink.gif
bodja74
Без проблем.

Не ошибается тот ,кто ничего не делает.
James D.
Новый вариант слейв2:

Код
TWI_Obr:in  temp,TWSR
  cpi  temp,$60;Проверка принятого адреса от мастера
  breq Address
  cpi  temp,$80;Прием данных
  breq DataR

  cpi  temp,$A8;Передача данных
  breq DataT1
  cpi  temp,$B0;
  breq DataT1
  cpi  temp,$B8;
  breq DataT2

  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;*******
Address:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;Прием данных:

DataR: in  Byte_1,TWDR ;Прием: Byte_1
  rcall TW_NT_n  ;Прием: Byte_2
  in  Byte_2,TWDR

  rjmp STOP_n

;*******************************************************************
TW_NT_n:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait2n: in  temp,TWCR ;Ожидаем ответа от мастера
  sbrs temp,TWINT
  rjmp wait2n

  ret

;*******************************************************************
;Все данные приняты - STOP (линия приема/передачи переходит в высокоимпедансное состояние)

STOP_n: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;*******************************************************************

;Передача данных:

DataT1: out  TWDR,Byte_1 ;Отправка: Byte_1
  rcall Write

  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

DataT2: out  TWDR,Byte_2 ;Отправка: Byte_2
  rcall Write
  out  TWDR,Byte_3 ;Отправка: Byte_3
  rcall Write
  out  TWDR,Byte_4 ;Отправка: Byte_4
  rcall Write
  out  TWDR,Byte_5 ;Отправка: Byte_5
  rcall Write
  out  TWDR,Byte_6 ;Отправка: Byte_6
  rcall Write

  rjmp STOP_n
  
;*******************************************************************
Write: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait3n: in  temp,TWCR;Ожидаем ответа от мастера
  sbrs temp,TWINT
  rjmp wait3n

  ret

;*******************************************************************


Код мастера для передачи/приема на слейв2:

Код
;*************************
;Передача на слейв2:
;*************************

  ldi  temp,$14;Установка скорости передачи= 71429 Hz
  out  TWBR,temp
  ldi  temp,$00
  out  TWSR,temp

Pusk_Sr:ldi  temp,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
  out  TWCR,temp;Посылка сигнала "START"

wait1r: in  temp,TWCR;Ожидаем ответа интерфейса
  sbrs temp,TWINT
  rjmp wait1r

SLA_Wr: ldi  temp,$40;Загрузка адреса слейв2 + "WRITE"
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait2r: in  temp,TWCR;Ожидаем ответа от слейв2
  sbrs temp,TWINT
  rjmp wait2r

;Начинаем передавать данные:

DATA_r: out  TWDR,Byte_1 ;Отправка: Byte_1
  rcall Writer
  out  TWDR,Byte_2 ;Отправка: Byte_2
  rcall Writer
  
  rjmp STOP_r  ;Передача данных завершена

;*******************************************************************
Writer: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait3r: in  temp,TWCR;Ожидаем ответа от слейв2
  sbrs temp,TWINT
  rjmp wait3r

  ret
;*******************************************************************
;Все данные переданы - STOP (линия приема/передачи переходит в высокоимпедансное состояние)

STOP_r: ldi  temp,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
  out  TWCR,temp

PAUSE: ldi  temp,$FF;Пауза, чтобы модуль TWI смог завершить команду СТОП
P_cikl: dec  temp
  cpi  temp,0
  brne P_cikl

;*************************
;Прием со слейв2:
;*************************

  ldi  temp,$14;Установка скорости передачи= 71429 Hz
  out  TWBR,temp
  ldi  temp,$00
  out  TWSR,temp

Pusk_R: ldi  temp,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
  out  TWCR,temp;Посылка сигнала "START"

waitT1: in  temp,TWCR;Ожидаем ответа интерфейса <<< Зависает здесь <<<
  sbrs temp,TWINT
  rjmp waitT1

  ldi  temp,$41;Загрузка адреса слейв2 + "READ"
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

waitR2: in  temp,TWCR;Ожидаем ответа слейв2
  sbrs temp,TWINT
  rjmp waitR2

;*******
;Прием данных:

Data: rcall TW_NT_R  ;Прием: Byte_1
  in  temp,TWDR
  sts  Byte_1,temp
  rcall TW_NT_R  ;Прием: Byte_2
  in  temp,TWDR
  sts  Byte_2,temp
  rcall TW_NT_R  ;Прием: Byte_3
  in  temp,TWDR
  sts  Byte_3,temp
  rcall TW_NT_R  ;Прием: Byte_4
  in  temp,TWDR
  sts  Byte_4,temp
  rcall TW_NT_R  ;Прием: Byte_5
  in  temp,TWDR
  sts  Byte_5,temp

TWI_DATA_R_NACK:
  ldi  temp,(1<<TWINT)|(1<<TWEN)
  out  TWCR,temp

d2:     in  temp,TWCR
  sbrs temp,7
        rjmp d2

        in  temp,TWDR ;Прием: Byte_6
  sts  Byte_6,temp

  rjmp STOP_RD  ;Прием данных завершен

;*******************************************************************
TW_NT_R:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

waitRr: in  temp,TWCR ;Ожидаем ответа от слейв2
  sbrs temp,TWINT
  rjmp waitRr

  in  temp,TWSR
  cpi  temp,$50
  brne STOP_RD  ;Переход, если данные от слейв2 не получены

  ret

;*******************************************************************
STOP_RD:ldi  temp,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
  out  TWCR,temp

PAUSE2: ldi  temp,$FF;Пауза, чтобы модуль TWI смог завершить команду СТОП
P_cikl2:dec  temp
  cpi  temp,$00
  brne P_cikl2

;*******************************************************************


Зависает в цикле waitT1...
bodja74
Как я и предполагал этот участок кода в слейве не работает.

Код
Write: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait3n: in  temp,TWCR;Ожидаем ответа от мастера
  sbrs temp,TWINT
  rjmp wait3n

  ret





Похоже со слейвом нужно работать только через прерывания.

Так что будем делать по методе которую я предлагал раннее.
Делаем да буфера по 16 байт
Адресс приемного $80-$8F оперативке ,указатель регистр Х
Адресс передающего $90-$F,указатель регистр Y
Расположение и размер буферов можно изменить по своему усмотрению

Кстати выяснил что при посылке последнего байта не обязательно указывать TWCR=$85


Вот код

Код
; TWI Slave
; Specify Device.
.include "m8def.inc"
                    
; Variable Declarations
.def temp     = r16
.def temp_a   = r17
.def adress   = r18
.def data     = r19


.cseg                ; CODE segment.

.org 0          
                rjmp PROG    ; origin.
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        reti
        rjmp TWI_Finished
        reti
           
                          
PROG:           ldi r16,$04    ; Initialize the stack.
            out SPH,r16
                ldi r16,$5F            
            out SPL,r16
                ldi temp,$00    ;
        out TWSR,temp
                ldi temp,$00    ;
        out TWBR,temp
                ldi temp,$40
        out TWAR,temp
                ldi temp,$45
        out TWCR,temp
                ldi temp,$FF    ;
        out DDRD,temp
        sei    
cycle:        rjmp cycle            


TWI_Finished:    
        sts $0F0,temp
        in temp,TWSR
                cpi temp,$60
                breq t1
                in temp,TWSR
                cpi temp,$80
                breq t2
        in temp,TWSR
                cpi temp,$A8
                breq t3
        in temp,TWSR
                cpi temp,$B0
                breq t3
        in temp,TWSR    ;
                cpi temp,$B8
                breq t4
       
    
                ldi temp,$C5
        out TWCR,temp
        lds temp,$0F0
        reti



t1:        ldi XH,$00
        ldi XL,$80
        ldi temp,$C5
        out TWCR,temp
        lds temp,$0F0
        reti

t2:             cpi XL,$90
                breq t2_1
        in temp,TWDR
        st X+,temp
        out PORTD,temp
        ldi temp,$C5
        out TWCR,temp
        lds temp,$0F0                    
        reti
t2_1:        in temp,TWDR
        st X,temp
        out PORTD,temp
        ldi temp,$C5
        out TWCR,temp
        lds temp,$0F0                        
        reti

t3:        ldi YH,$00
        ldi YL,$90
        ld temp,Y+
        out TWDR,temp
        ldi temp,$C5
        out TWCR,temp
        lds temp,$0F0
        reti

t4:             cpi YL,$A0
                breq t4_1
        ld temp,Y+
        out TWDR,temp
        ldi temp,$C5
        out TWCR,temp
        lds temp,$0F0    
        reti
t4_1:        ld temp,Y
        out TWDR,temp
        ldi temp,$C5
        out TWCR,temp
        lds temp,$0F0    
        reti
James D.
Огромное спасибо за помощь!
Буду пробовать новый вариант.
С Новым Годом! И удачи!!! santa2.gif
bodja74
И Вас с тем же ,и Вам того же.

Пора водку пить,согреваться до лета,а то в следующем году будем сидеть без газа.Удачи!!!
James D.
Нет, не получилось - мастер зависает в том же месте.
Ниже привожу прогу мастера (передача на слейв1 и передача/прием на слейв2
осуществляются в пределах одного обработчика прерывания таймера (Timer/Counter2 Переполнение)).

Мастер (передача 1-го байта на слейв 1):

Код
To_sl_1:ldi  temp,$14;Установка скорости передачи= 71429 Hz
  out  TWBR,temp
  ldi  temp,$00
  out  TWSR,temp

Pusk_Sn:ldi  temp,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
  out  TWCR,temp;Посылка сигнала "START"

wait1n: in  temp,TWCR;Ожидаем ответа от интерфейса TWI
  sbrs temp,TWINT
  rjmp wait1n

SLA_Wn: ldi  temp,$20;Загрузка адреса слейв1 + "WRITE"
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait2n: in  temp,TWCR;Ожидаем ответа от слейв1
  sbrs temp,TWINT
  rjmp wait2n

;Начинаем передавать данные:

DATA_n: out  TWDR,Byte_1 ;Отправка: Byte 1
  rcall Writen

  rjmp STOP_n  ;Передача данных завершена

;*******************************************************************
Writen: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait3n: in  temp,TWCR;Ожидаем ответа от слейв1
  sbrs temp,TWINT
  rjmp wait3n

  ret
;*******************************************************************
;Все данные переданы - STOP (линия приема/передачи переходит в высокоимпедансное состояние)

STOP_n: ldi  temp,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
  out  TWCR,temp

PAUSE_n:ldi  temp,$40
p:  dec  temp
  cpi  temp,$00
  brne p
;*******************************************************************


После этого идет дальнейшее выполнение программы обработчика таймера.
Далее:
Мастер (передача 1-го байта на слейв2, и прием со слейв2 3-х байт):

Код
;*************************
;Передача на слейв 2:
;*************************

  ldi  temp,$14;Установка скорости передачи= 71429 Hz
  out  TWBR,temp
  ldi  temp,$00
  out  TWSR,temp

Pusk_Sr:ldi  temp,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
  out  TWCR,temp;Посылка сигнала "START"

wait1r: in  temp,TWCR;Ожидаем ответа интерфейса
  sbrs temp,TWINT
  rjmp wait1r

SLA_Wr: ldi  temp,$40;Загрузка адреса слейв 2 + "WRITE"
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait2r: in  temp,TWCR;Ожидаем ответа от слейв 2
  sbrs temp,TWINT
  rjmp wait2r

;Начинаем передавать данные:

DATA_r: out  TWDR,Byte_1 ;Отправка: Byte 1
  rcall Writer

  rjmp STOP_r  ;Передача данных завершена

;*******************************************************************
Writer: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

wait3r: in  temp,TWCR;Ожидаем ответа от слейв 2
  sbrs temp,TWINT
  rjmp wait3r

  ret
;*******************************************************************
;Все данные переданы - STOP (линия приема/передачи переходит в высокоимпедансное состояние)

STOP_r: ldi  temp,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
  out  TWCR,temp

PAUSE: ldi  temp,$FF;Пауза, чтобы модуль TWI смог завершить команду СТОП

P_cikl: dec  temp
  cpi  temp,0
  brne P_cikl

;Прием данных:

  ldi  temp,$14;Установка скорости передачи= 71429 Hz
  out  TWBR,temp
  ldi  temp,$00
  out  TWSR,temp

Pusk_R: ldi  temp,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
  out  TWCR,temp;Посылка сигнала "START"

waitT1: in  temp,TWCR;Ожидаем ответа интерфейса
  sbrs temp,TWINT
  rjmp waitT1

  ldi  temp,$41;Загрузка адреса слейв 2 + "READ"
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

waitR2: in  temp,TWCR;Ожидаем ответа слейв 2
  sbrs temp,TWINT
  rjmp waitR2

;*******
;Прием данных:

Data: rcall TW_NT_R  ;Прием: Byte 1
  in  temp,TWDR
  sts  Byte_1,temp
  rcall TW_NT_R  ;Прием: Byte 2
  in  temp,TWDR
  sts  Byte_2,temp

TWI_DATA_R_NACK:
  ldi  temp,(1<<TWINT)|(1<<TWEN)
  out  TWCR,temp
d2:     in  temp,TWCR
  sbrs temp,7
        rjmp d2
        in  temp,TWDR ;Прием: Byte 3
  sts  Byte_3,temp

  rjmp STOP_RD  ;Прием данных завершен

;*******************************************************************
TW_NT_R:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)
  out  TWCR,temp

waitRr: in  temp,TWCR ;Ожидаем ответа от слейв 2
  sbrs temp,TWINT
  rjmp waitRr

  in  temp,TWSR
  cpi  temp,$50
  brne STOP_RD  ;Переход, если данные от слейв 2 не получены

  ret

;*******************************************************************
STOP_RD:ldi  temp,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
  out  TWCR,temp

PAUSE2: ldi  temp,$FF;Пауза, чтобы модуль TWI смог завершить команду СТОП

P_cikl2:dec  temp
  cpi  temp,$00
  brne P_cikl2

;*******************************************************************




Прога слейв1 (прием 1-го байта):

Код
;*******************************************************************
;Режим - подчиненный-приемник:

TWI_Obr:in  temp,TWSR
  cpi  temp,$60;Проверка принятого адреса от мастера
  breq Address
  cpi  temp,$80;Прием данных
  breq Data
  cpi  temp,$00;
  breq Sob_00
  cpi  temp,$F8;
  breq Sob_F8

  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp

  reti

;***************************************************

Sob_00: ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWSTO)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

Sob_F8: reti

;*******
Address:ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;*******
;Прием данных:

Data: in  Byte_1,TWDR
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;*******************************************************************


Прога слейв2 (прием 1-го байта и передача 3-х байт мастеру):

Код
;*******************************************************************
;Режим - подчиненный-приемник/передатчик:

TWI_Obr:in  temp,TWSR
  cpi  temp,$60;Проверка принятого адреса от мастера
  breq Address
  cpi  temp,$80;Прием данных
  breq DataR

  cpi  temp,$A8;Передача данных
  breq DataT1
  cpi  temp,$B0;
  breq DataT1
  cpi  temp,$B8;
  breq DataT2

  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;*******
Address:ldi  XH,$00
  ldi  XL,$80
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;*************************
;Прием от мастера:
;*************************
;Прием данных:

DataR: cpi  XL,$90
  breq DataR_2
  in  temp,TWDR
  st  X+,temp
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

DataR_2:in  temp,TWDR
  st  X,temp
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;*************************
;Передача мастеру:
;*************************
;Передача данных:

DataT1: ldi  YH,$00
  ldi  YL,$90
  ld  temp,Y+
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

DataT2: cpi  YL,$A0
  breq t4_1
  ld  temp,Y+
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

t4_1: ld  temp,Y
  out  TWDR,temp
  ldi  temp,(1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE)
  out  TWCR,temp
  reti

;*******************************************************************
bodja74
Прогу мастера проверил,работает.По крайней мере та часть ,что представили.

Насчет слейвов ,а где команда sei после инициализации?

Да еще декларация переменных по мастеру Byte_1 это регистр,остальные оперативка?
А то я не сразу вьехал.Предупреждайте.
defunct
Цитата(bodja74 @ Dec 31 2005, 12:47) *
Как я и предполагал этот участок кода в слейве не работает.

Вот код

Код
; TWI Slave
...                    
        sei    
cycle:        rjmp cycle            


TWI_Finished:    
        sts $0F0,temp
...
        lds temp,$0F0    
        reti


Скажите, а какой глубокий смысл (разумеется если он есть) в выделенном фрагменте? Для чего требуется сохранять temp по фиксированному адресу? Имеется ведь стек (команды push/pop), и самое главное если что и требует сохранения в реальной программе, так это в первую очередь SREG, почему же вы его не сохраняете?
James D.
Я привел здесь для слейвов только обработчики прерываний TWI.
После инициализации команда sei имеется.
У мастера Byte_1 и прочие - это или регистры, или ячейки ОЗУ. По смыслу. Я просто не стал приводить те специфические имена, которые использует программа. Чтобы было понятнее. А Byte_1, 2 и т.д. - это значит передаем/принимаем 1-ый байт, или 2-ой байт и т.д.
Говорите работает мастер? Прогу я представил практически в полном объеме - так пробую сейчас. Потом просто добавлю передачу/прием еще нескольких байт, только м всего.
А проверяете в симуляторе? В каком? Я пользуюсь только AVRStudio. Вот проверить бы это все хозяйство через JTAG! Совсем другое дело...
bodja74
Цитата(defunct @ Jan 2 2006, 12:36) *
Скажите, а какой глубокий смысл (разумеется если он есть) в выделенном фрагменте? Для чего требуется сохранять temp по фиксированному адресу? Имеется ведь стек (команды push/pop), и самое главное если что и требует сохранения в реальной программе, так это в первую очередь SREG, почему же вы его не сохраняете?


Никакого смысла сохранения temp в предоставленном коде нет.
Я в этом цикле
cycle: rjmp cycle
присваивал для тестирования разные значения для отправки и использовал соответственно temp.Поэтому сохранял-востанавливал в подпрограмме.
Стек естественно имеется,но я его стараюсь не трогать и оставлять за ним право сохранять вектора возвратов из подпрограмм.
Стараюсь хранить переменные в оперативке.Так конкретно известно где какая переменная находиться.Но это все больше относиться к стилю написания программ.

SREG естественно стоит сохранять и не только его но и регистры X,Y,temp и другие если будут использоваться в подпрограмме.
Посмотрите внимательно на мой код,и скажите нужно ли сийчас все это?

На данном этапе необходимо получить-отправить пару байтов от пары слейвов и убедиться в работоспособности.
Потом естественно все это можно улучшать и вылизывать.
Я уже об этом неоднократно говорил.И не устраиваю здесь "показательные выступления" своего кода.

Теперь James D.
Цитата
А проверяете в симуляторе? В каком? Я пользуюсь только AVRStudio. Вот проверить бы это все хозяйство через JTAG! Совсем другое дело...


Я работаю на ПРОТЕУСЕ,ИМХО самое лучшее что я когда либо встречал.
Проверяю не только на симуляторе,но и на макетке.
Правда на макетке у меня только два МК ,слейв и мастер.
В случае с двумя слейвами проверяю на ПРОТЕУСЕ,но то что я делал на нем ,было без проблем и по жизни .
Предоставленные кода рабочие и если вы добавляете что то свое, будте внимательны.
Нужно предусматривать сохранение-востановление регистров и установку масок если используються несколько прерываний и время на обработку прерывания и т.д. и т.п.
Всего я предусмотреть за Вас я не могу, во многом это зависит от Вас и вашей программы.
James D.
Если кода рабочие, а у меня на макетке не работает, то что же делать?
Можно ли в ПРОТЕУСЕ моделировать более двух МК? Я, наверное, скачаю ПРОТЕУС (где-то на этом форуме встречал ссылку), и попробую. Прога, случайно, не на русском?
Хотя, если честно, эти симуляторы, что-то не внушают мне доверия... ИМХО... Переубедите.
Petka
почему в проге "слейв2" не обрабатываете события $00 и $F8 ? я же говорил что это делать необходимо, иначе шина зависает. не наступайте на мои грабли.
bodja74
Ну как не работает на макетке ?У меня же работает.
Посмотрите инициализацию стека,правильно ли указали вектор прерывания.
В меге32 они могут быть по другому расположены(не смотрел)Все делал под мегу8
Поставте еще паузу у мастера перед инициализацией,возможнослейв позже стартует после включения питания


ПРОТЕУС мною ценится не только из из за симулятора,может многие упускают ,но это по факту
среда разработки.
На нем можно писать программы,составлять проверять на симуляторе принципиальные схемы и экспортировать их в графические форматы со списками элементов,на месте развести печатку с
автотрассировкой и вручную,поддерживает не только AVR но и PIC ,МОТОРОЛА,80с51,80с52
и другие,на все это есть компиллеры.
Кроме того запустить симулятор можно не только с исходника но и с прошивки+МНОГО,МНОГО
одновремено симулируемых контроллеров.(лично проверял пять,больше не нужно было)

Коротче с этой проге можно полностью собрать весь проект со всей необходимой документацией.
А это все весьма удобно.

Естествено не забываю и про макетку,с этого начинал,правда теперь уже прошиваю реже
так как оперативно можно проверить ПРОТЕУСОМ.

Petka
Ну Вы мне скажите зачем слейву проверять промежуточное значение F8,если оно имеет место
когда TWIN=0, а если TWIN=0 то и прерывания нет ,а если пошло то F8 там и не пахнет.
Тоже и по $00 ,если ошибка на шине слейв ничего не определит,а если определит он все равно не
сможет ничего сделать.
Если эти проверки нужны то только для мастера,он заведует шиной и решает что с ней делать.
James D.
Нашел две версии: Proteus 6.5 SP5 (16.52 Mb) и Proteus 6.7 sp 3 (21.59 Mb).
М-да, многовато качать-то... Да еще если и демо окажется, то совсем будет круто...
James D.
Скачал proteus 6.5 SP5. Первое впечатление: очень неплохо задумано! Теперь бы проверить на боевой задаче, как у меня. Интересно, что скажет этот симулятор?
Настораживает только, что это демо версия... Хоть и с крэком...
bodja74, Вы проверяли программы на этом симуляторе? И что, говорит, что все работает?
bodja74
Ну нормально,
Я три месяца лопатил весь интернет,поднял всех на уши,в поисках рабочей версии,
в итоге все равно получил "из рук в руки",а Вы за пол дня ,с инета,и две версии.

Ладно проверим что они "запоют".
Открываем проект File>>>Load Design
Находим папку Samples там куча готовых проектов для примера.
Открываем любой ,нажимаем кнопочку Play(старт),радуемся.
Теперь пробуем удалить-изменить что нибудь несущественное (проводник или резюк)
и запустить заново.Если выдаст ошибку симуляции с ссылкой на ключи,можете считать
что зря старались,если конечно перед этим запускали кряк.
Если все нормально,нажимаем кнопочку ARES ,пробуем нарисовать платку,
Если все нормально, пробуем добавлять в проект всякие элементы (микросхемы,контроллеры и так далее)Все элементы в списке должны добавляться.
Если все Ок,кричим Ура!!!
Пишите свое мыло ,я вам отправлю проекты по Вашей теме.
James D.
ISIS вроде как работоспособный. Проект из Samples (LCD) запускается, можно изменять, сохранять.
А вот с ARES что-то не то. Проект нельзя сохранить. И там нет образцов, как в ISIS.
E-mail: proteus3@yandex.ru Высылайте, посмотрим как пойдет.
bodja74
Да слышал,что к 6.5 не все работает.
Провере добавляются ли все элементы,и работает симуляция аналоговой части.

Пошел паковать и отправлять на мыло.
James D.
Файлы получил, спасибо, буду разбираться.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.