سلام
یکی از قابلیت هایی که AVR داره ارتباط I2C می باشد. کد های زیر برای ارتباط دو AVR از طریق I2C می باشد. کد کاملا خوانا و قابل فهم می باشد. دستورات مربوط به AVRSTUDIO هست.
مستر برای اسلیو 8 بایت ارسال میکند که در در آرایه tran قرار دارد. پس از اتمام ارسال 3 بایت را دریافت میکند که در آرایه recv قرار میگیرد.
موفق باشد.
قسمت مستر (i2cmaster.c (github :
// i2cmaster.c #include <util/twi.h> #define SET(x,y) (x|=(1<<y)) #define CLR(x,y) (x&=(~(1<<y))) #define CHK(x,y) (x&(1<<y)) #define TOG(x,y) (x^=(1<<y)) //global variables #define BUFLEN_RECV 3 uint8_t r_index =0; uint8_t recv[BUFLEN_RECV]; //buffer to store received bytes #define BUFLEN_TRAN 12 uint8_t t_index=0; uint8_t tran[BUFLEN_TRAN]= {1,2,3,4,5,6,7,8,9,10,11,12}; //variable to indicate if something went horribly wrong uint8_t reset=0 //prototypes void handleI2C_master(); //---------------MAIN--------------------------------------------- int main(){ //set bitrate for I2C TWBR = 10 //enable I2C hardware TWCR = (1<<TWEN)|(1<<TWEA)|(1<<TWSTA); while(1){ handleI2C_master(); } } //-----------END MAIN--------------------------------------------- //setup the I2C hardware to ACK the next transmission //and indicate that we've handled the last one. #define TWACK (TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWEA)) //setup the I2C hardware to NACK the next transmission #define TWNACK (TWCR=(1<<TWINT)|(1<<TWEN)) //reset the I2C hardware (used when the bus is in a illegal state) #define TWRESET (TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO)|(1<<TWEA)) //Send a start signal on the I2C bus #define TWSTART (TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTA)) //slave address and SLA signals #define I2C_SLAVE_ADDRESS 0x01 #define SLA_W ((I2C_SLAVE_ADDRESS<<1) | TW_WRITE) #define SLA_R ((I2C_SLAVE_ADDRESS<<1) | TW_READ) void handleI2C_master(){ //keep track of the modus (receiver or transmitter) static uint8_t mode; if(CHK(TWCR,TWINT)){ switch(TW_STATUS){ //start or rep start send, determine mode and send SLA R or W case 0x10: case 0x08: //reset buffer indices t_index =0; r_index =0; //send SLA W or R depending on what mode we want. if(mode == TW_WRITE) TWDR = SLA_W; else TWDR = SLA_R; TWACK; break; //--------------- Master transmitter mode------------------------- case 0x18: // SLA_W acked //load first data TWDR = tran[0]; t_index=1; TWACK; break; //SLA_W not acked for some reason (disconnected?), keep trying case 0x20: TWCR =0; TWSTART; break; case 0x28: //data acked by addressed receiver //load next byte if we're not at the end of the buffer if(t_index < BUFLEN_TRAN){ TWDR = tran[t_index]; t_index++; TWACK; break; } //otherwise, switch mode and send a start signal else { mode = TW_READ; TWSTART; break; } case 0x38: //arbitration lost, do not want //data nacked, could be faulty buffer, could be dc, start over case 0x30: TWCR = 0; TWSTART; break; //-------------------------Master receiver mode------------------- //SLA_R acked, nothing to do for master, just wait for data case 0x40: TWACK; break; //SLA_R not acked, something went wrong, start over case 0x48: TWSTART; break; //non-last data acked (the last data byte has to be nacked) case 0x50: //store it recv[r_index] = TWDR; r_index++; //if the next byte is not the last, ack the next received byte if(r_index < BUFLEN_RECV){ TWACK; } //otherwise NACK the next byte else { TWNACK; r_index =BUFLEN_RECV; } break; case 0x58: //last data nacked, as it should be //switch to other mode, and send start signal mode = TW_WRITE; TWSTART; break; //--------------------- bus error--------------------------------- case 0x00: TWRESET; ; TWSTART; break; } } }
قسمت اسلیو (i2cslave.c (github :
#i2cslave.c #include <util/twi.h> #define SET(x,y) (x|=(1<<y)) #define CLR(x,y) (x&=(~(1<<y))) #define CHK(x,y) (x&(1<<y)) #define TOG(x,y) (x^=(1<<y)) //global variables #define BUFLEN_RECV 12 uint8_t r_index =0; uint8_t recv[BUFLEN_RECV]; //buffer to store received bytes #define BUFLEN_TRAN 3 uint8_t t_index=0; //test bytes to transmit uint8_t tran[BUFLEN_TRAN] = {0x12, 0x34, 0x56}; //variable to indicate if something went horribly wrong uint8_t reset=0 //prototypes void handleI2C(); //---------------MAIN--------------------------------------------- int main(){ //load slave address TWAR = (0x01<<1); //we're using address 0x01 //enable I2C hardware TWCR = (1<<TWEN)|(1<<TWEA); while(1){ handleI2C(); } } //-----------END MAIN--------------------------------------------- //setup the I2C hardware to ACK the next transmission //and indicate that we've handled the last one. #define TWACK (TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWEA)) //setup the I2C hardware to NACK the next transmission #define TWNACK (TWCR=(1<<TWINT)|(1<<TWEN)) //reset the I2C hardware (used when the bus is in a illegal state) #define TWRESET (TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO)|(1<<TWEA)) void handleI2C(){ //check if we need to do any software actions if(CHK(TWCR,TWINT)){ switch(TW_STATUS){ //--------------Slave receiver------------------------------------ //SLA_W received and acked, prepare for data receiving case 0x60: TWACK; r_index =0; break; case 0x80: //a byte was received, store it and //setup the buffer to recieve another recv[r_index] = TWDR; r_index++; //don't ack next data if buffer is full if(r_index >= BUFLEN_RECV){ TWNACK; }else { TWACK; } break; case 0x68://adressed as slave while in master mode. //should never happen, better reset; reset=1; case 0xA0: //Stop or rep start, reset state machine TWACK; break; //-------------- error recovery ---------------------------------- case 0x88: //data received but not acked //should not happen if the master is behaving as expected //switch to not adressed mode TWACK; break; //---------------Slave Transmitter-------------------------------- case 0xA8: //SLA R received, prep for transmission //and load first data t_index=1; TWDR = tran[0]; TWACK; break; case 0xB8: //data transmitted and acked by master, load next TWDR = tran[t_index]; t_index++; //designate last byte if we're at the end of the buffer if(t_index >= BUFLEN_ACC_DATA) TWNACK; else TWACK; break; case 0xC8: //last byte send and acked by master //last bytes should not be acked, ignore till start/stop //reset=1; case 0xC0: //last byte send and nacked by master //(as should be) TWACK; break; //--------------------- bus error--------------------------------- //illegal start or stop received, reset the I2C hardware case 0x00: TWRESET; break; } } }
منبع: pengu.student.utwente.nl