یادداشت های یک مهندس

۱ مطلب با کلمه‌ی کلیدی «TWI» ثبت شده است

I2C_circuit

سلام

یکی از قابلیت هایی که 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



حامد فاضل
۲۷ آذر ۹۳ ، ۲۱:۵۹ موافقین ۰ مخالفین ۰ ۱ نظر