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

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



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

سلام
یکی از مشکلاتی که در اتمل استودیو وجود دارد این است که پروگرمر های محدودی را پشتبانی میکند. این اشکال باعث میشود که برای کامپایل ، از اتمل استودیو استفاده کنیم و برای پروگرم کردن از نرم افزاری دیگر که باعث گیجی  می شود.  برای حل این مشکل باید بصورت دستی پروگرمر را برای اتمل استودیو تعریف کنیم. در این پست پروگرمر AVR911 را برای اتمل استودیو تعریف می کنیم لازم به ذکر است به همین صورت می توان پروگرمر های دیگر را نیز برای اتمل استودیو تعریف کرد.

1- ابتدا نرم افزار AVROSP    را نصب کنید. این فایل، نرم افزار اجرایی پروگرمر AVR911 هست یعنی از طریق  این نرم افزار می توان به پروگرمر دستور داد که چه کاری انجام دهد. این نرم افزار بصورت کامندی (command-lineو فاقد رابط کاربری است جهت اجرای نرم افزار باید از طریق CMD اقدام کنید. 

2-  در یرنامه اتمل استودیو به آدرس زیر رفته:
Tools-->ExternalTool



3- سپس مقادیر زیر را در فیلدهای مربوطه وارد وارد کنید:
Title:
نامی دلخواه مثلا        avr911 

:Command

آدرس نرم افزار مثلا   C:\Program Files\AVROSP.exe


 Arguments:
 -dATmega32 -cCOM2 -pf -vf -if$(ProjectDir)Debug\$(ItemFileName).hex –e

فیلد آخر پارامترهای ورودی نرم افزار هست یعنی به نرم افزار میگوییم چکار انجام بدهد که باید نوع AVR  و پورتی که پروگرمر به آن متصل هست را مشخص کنیم که در اینجا مگا32 و پورت ،COM2  می باشد. جهت اطلاع از پارامترهای ورودی به این فایل مراجعه نمایید.
4- سپس دکمه ok  را زده و خارج شده.


5- حال برای پروگرم نمودن کافی است پس از کامپایل به منوی tools  رفته و رو دکمه ای که هم نام نامی است  که انتخاب نموده بودید کلیک کنید پروگرمر شروع به پروگرم نمودن میکند.
به پروگرم نمودن میکند.
                                                                                                                                              
لازم به ذکر است برخی از پروگرمر های موجود در بازار که با پورت usb  کار می کنند و از پروتکل avr910    پشتیبانی می کنند با نرم افزار ذکر شده نیز می توانند از طریق اتمل استو بصورت مستقیم  AVR را پروگرم نمایند.

حامد فاضل
۲۶ ارديبهشت ۹۳ ، ۱۳:۳۰ موافقین ۰ مخالفین ۰ ۰ نظر