#include "iom16.h" #include #define BYTE unsigned char #define Uint unsigned int #define _CLI __disable_interrupt() #include "g_decl_M.h" // объявляем глобальные переменные, структуры и функции // ========================================================================== void main(void) // Тестируем Master TWI { BYTE beg,i,kb; beg=15; i=beg; ini_Prt(); // инициируем Входы/выходы tw_init(); // инициируем TWI как Мастер (кто 1-й START, того и тапки) sei(); for(;;) { kb=wait_KB(); if(kb==BuESC) i=0; else if(kb==BuRT) { if(i<17) i++; } if(kb==BuLT) { if(i) i--; } if(kb==BuENT) { if(i==0) tw_SwDev(HL_VEN, DEV_ON); . . . else if(i==15) D_wd=tw_Rd_EPROM(AEP_tk); . . } } } // ========================================================================== void tw_init(void)/**/ // первичн. инициация I2C (TWBR >= 10) { register BYTE state; // SDA, SCL оставляем по умолчанию 00 state=__save_interrupt(); // для возможной переинициализации _CLI; // TWBR = ((F_cpu/F_scl) - 16)/(2*4^TWPS) // при 8 МГц для 100 кГц - 36, для 50 кГц - 72 TWCR=Er_TW=0; // отключение и сброс TWI wait_us(50); tw_clrRx(); tw_clrTx(); clr_D(); TWBR=72; // переинициация TWI //TWDR=0xFF; // Но при этом ставится бит TWWC !!! TWCR = (1<0; i--) {// ждем завершения текущей операции Master 3 ms wait_us(30); if(!(TWCR & (1<0; i--) { if(Tx.ok) break; wait_us(30); } if(!i) err=1; } else {//if(!mo) // ждем конца приема for(i=250; i>0; i--) { if(Rx.ok) break; wait_us(30); } if(!i) err=2; } if(tw_Wait()) // окончание 1-й операции err=3; } return err; } // ======================================================================== BYTE tw_Wait_Sl(BYTE mo)/**/ // ждем Начало/Конец (1/0) слепой зоны Slave // mo=0 - ждем готовность Слэйва // mo=1 - ждем начало слепой зоны { int i,err=0; if(!Er_TW) { if(mo) {// ждем начало слепой зоны for(i=32000; i>0; i--) { wait_us(10); if(TST_MISO) break; } // дождались 1 if(!i) err=1; // Слэйв не отвечает (нет 1) else D.cnt_W0=32000-i; // На время отладки Слэйва делаем ожидание бесконечным } else { // ждем готовность Слэйва for(;;/*i=32000; i>0; i--*/) { wait_us(100/*10*/); if(!TST_MISO) break; } // дождались 0 //if(!i) err=2; // Слэйв долго занят (нет 0) //else D.cnt_W1=32000-i; } } return err; } // ======================================================================== BYTE tw_Send(BYTE cmd, BYTE d1, BYTE d2, BYTE d3)/**/ // Запуск ISR на передачу данных // Младший ниббл команды содержит число дополнительных байт данных // 0-adr, 1-cmd+len 2-4-дополнит. данные { BYTE tw_er=0; TCNT1=0; TCCR1B=2; // запуск TC1 на 1 мкс if(Er_TW) goto _end; if(tw_Wait()) { // ждем готовности Master tw_er=2; goto _end; } if(tw_Wait_Sl(0)) { // ждем готовности Slave tw_er=4; goto _end; } tw_clrTx();//clr_D(); TWCR = (1<>1; MskInSlv=Rx.a[2]; // состояния входов Slave Er.slv=Rx.a[3]; // код ошибки Slave*/ } else Er_TW=0x71;//TWI_ERR+15; // Ошибка обмена пакетом - сбой протокола _end: return Er_TW; } // ======================================================================== // !!!!!!!!!! ВАРИАНТ РАБОТЫ по IRQ (See AVR 315) !!!!!!!!!!!!!!! // (кто сказал START, тот и Мастер) // ======================================================================== // Когда мы передаем данные, и Мастер и Слэйв получает длину пакета из // младшего ниббла второго байта (cmd+len) массива Tx.a[]. // Когда запрашиваем данные, предварительно задаем Rx.len и мастер видит это. // Так как прием данных идет в два этапа: запрос/прием, то Слэйв, после // запроса, в функции post_tw() должен задать соответствующую длину в Tx.len. #pragma vector=TWI_vect __interrupt void twi_ISR(void) { register BYTE bt,st=TWSR & 0xF8; BYTE stp=0, er=0, answ=0, start=0; // Инициация обмена (TWI_START, TWI_REP_START) if((st==0x08) // Был сделан старт, решаем что делать дальше || (st==0x10)) { // обнаружен повторный старт. Можно переключиться // с записи на чтение или наоборот Rx.it=Tx.it=0; // сбрасываем итераторы Rx.st=4; // Статус - "посылаем адрес" TWDR = Tx.a[Tx.it++]; } // посылаем адрес // Передача очередного байта (TWI_MTX_ADR_ACK, TWI_MTX_DATA_ACK) else if((st==0x18) // послали адрес +W, получили ASK, продолжаем || (st==0x28)) { // послали байт, получили ASK, продолжаем. if((Tx.it>=Tx.len) || (Tx.it>=LEN_TWI)) { Rx.st=0x44; // Статус - "Последний байт передачи" Tx.ok=stp=1; // флаг завершения пачки } else { // пока есть, что посылать Rx.st=6; // Статус - "Следующий байт данных" TWDR = Tx.a[Tx.it++]; } // посылаем данные } // Передача 2-х байт: // Master: Slave: // 08 18 28 28 (START adr_W cmd d1) 60 80 80 (ADR_W cmd d1) нет 88 !!! // 85 85 85 94 C5 C5 84 (ACK ACK NACK - STOP) // 66 11 11 xx 66 11 00 (adr cWR_PIN d1) // -------------------------------------------------------------------------- // Начало приема (TWI_MRX_ADR_ACK) else if(st==0x40) { // Послали адрес +R, и ведомый отозвался. Rx.st=3; // Статус - "1-й байт приема" answ=1; } // ответ ASK // Прием очередного байта (TWI_MRX_DATA_ACK) else if(st==0x50) { // приняли байт, что бы ответить, ACK или NACK. Rx.a[Rx.it++] = TWDR; if((Rx.it>=Rx.len) || (Rx.it>=LEN_TWI)) goto _next_Read; else { // пока есть, куда принимать Rx.st=5; // Статус - "Следующий байт приема" answ=1; } // ответ ASK } // Прием последнего байта (TWI_MRX_DATA_NACK) else if(st==0x58) { // приняли байт, сказали NACK, послали STOP Rx.a[Rx.it] = TWDR; _next_Read: Rx.st=0x55; // Статус - "Последний байт приема" Rx.ok = 1; // флаг завершения пачки stp=1; } // STOP // Master: запрос/прием cmd + 3 байта: // SR: 08 18 28 _ 08 40 50 50 50 50 (..START, ADDR_R, BYTE...) // CR: 85 85 94 - 85 C5 C5 C5 C5 94 // DR: 66 60 xx - 67 67 60 D1 D2 D3 // 0 1 2 3 4 5 6 7 8 // -------------------------------------------------------------------------- else if(st==0x38) { // TWI_ARB_LOST пришел другой мастер Rx.st=0x10; // Статус - "попытка ReSTART" start=1; } else { // 0x00: // TWI_BUS_ERROR Ошибка Шины - неожиданный START или STOP // 0x20: // TWI_MTX_ADR_NACK послали адрес+W, и тишина. // 0x48: // TWI_MRX_ADR_NACK послали адрес+R, и тишина // 0x30: // TWI_MTX_DATA_NACK послали байт, и тишина. // 0xF8 // TWI_NO_STATE Информация о статусе недоступна TWINT=0 er=st; } if(!er) { bt=(1<=D_ST_LEN) D.i=0; TWCR=bt; } // void twi_ISR(void) // ======================================================================== // ======================================================================== /* Неформальное, но более понятное описание кодов состояний от ДиХальт для режима Master (1-й послал состояние START, потому и Master): 0x08 TWI_START - Start Был сделан старт. Теперь мы решаем что делать дальше, например послать адрес ведомого 0x10 TWI_REP_START - ReStart Был обнаружен повторный старт. Можно переключиться с записи на чтение или наоборот. От логики зависит. Штатная передача: 0x18 TWI_MTX_ADR_ACK - SLA+W+ACK Мы отправили адрес с битом записи, а в ответ получили ACK от ведомого. Значит можно продолжать. 0x28 TWI_MTX_DATA_ACK - Byte+ACK Мы послали байт и получили подтверждение, что ведомый его принял. Продолжаем. 0x30 TWI_MTX_DATA_NACK - Byte+NACK Мы послали байт, но подтверждение не получили. Видимо ведомый уже сыт по горло нашими подачками или он захлебнулся в данных. Либо его ВНЕЗАПНО посреди передачи данных украли инопланетяне. Штатный прием: 0x40 TWI_MRX_ADR_ACK - SLA+R+ACK Послали адрес с битом на чтение, а ведомый отозвался. Хорошо! Будем читать. 0x50 TWI_MRX_DATA_ACK - Receive Byte Мы приняли байт. И думаем что бы ответить ведомому. ACK или NACK. 0x58 TWI_MRX_DATA_NACK - Receive Byte+NACK Мы приняли байт от ведомого и сказали ему "иди NACK!" И он обиженый ушел, освободив шину. 0x48 TWI_MRX_ADR_NACK - SLA+R+NACK Крикнули в шину «Эй ты, с адресом ХХХ, почитай нам сказки» А в ответ "Иди NACK!" В смысле на запрос адреса с битом чтения никто не откликнулся. Видимо не хотят или заняты. Также может быть никого нет дома. Ошибки обмена: 0x00 TWI_BUS_ERROR - Bus Fail Автобус сломался... эээ в смысле аппаратная ошибка шины. Например, внезапный старт посреди передачи бита. 0x20 TWI_MTX_ADR_NACK - SLA+W+NACK Мы отправили адрес с битом записи, а нас послали NACK. Обидно, сгенерим ошибку или повторим еще раз. 0x38 TWI_ARB_LOST - Collision А у нас тут клановые разборки — пришел другой мастер, по хамски нас перебил, да так, что мы от возмущения аж заткнулись. Ничего I’l be back! До встречи через n тактов! */ /* Слегка правленый пример из AVR315 switch (st) { case 0x08: // TWI_START Был сделан старт, решаем что делать дальше case 0x10: // TWI_REP_START обнаружен повторный старт. // Можно переключиться с записи на чтение или наоборот S.it=0; // сбрасываем итератор S.iSt=0; case 0x18: // TWI_MTX_ADR_ACK послали адрес +W, получили ASK, продолжаем case 0x28: // TWI_MTX_DATA_ACK послали байт, получили ASK, продолжаем. if(S.it