본문 바로가기
공부,일/atmega328P

atmega328P TWI(I2C) 통신 (3) 실습

by fromnothing1 2021. 8. 7.

SCL = PC5

SDA = PC4

 

 


실습 프로그램 소개 

(대충읽고 코드를 보면서 다시 보기 바란다. )

2개의 아두이노 우노 보드로 TWI 통신을 한다. 

 

1대는 마스터 모드로 ,1대는슬레이브 모드로 작동한다. 

 

1. 마스터 송신 모드로 0x01 을 전달한다. 

2. 슬레이브 수신 모드로 0x01 을 전달 받는다. 

3. 마스터 수신 모드로 데이터를 요청한다. 

3. 슬레이브 송신 모드로 받은 0x01 의 데이터를 토글해서 돌려준다. 

4. 마스터는 토글된 데이타를 1bit 시프트 시켜준다. 

 

아두이노는 받은 데이터로 PORTD에 달려있는 불을 킨다. 

(코드 상으로는 8개의 포트를 모두 조절하고 있지만 LED 가 없어서 4개씩만 사용하였다.)

 

슬레이브의 어드레스는 0x20 으로 하겠다.

풀업 저항 구하기 

 

위 의 공식을 계산해보면 Vcc 5v 

기준 풀업저항 최솟 값은 1533.33 옴이다.  1킬로 옴 밖에 없어서 직렬로 2킬로 옴을 만들어서 사용하겠다 .

 

cf) 사실 내부 풀업저항을 사용한다면 (20 ~ 50k 옴) 상관 없지만 외부 풀업을 사용해 보겠다. 

TWBR 값 구하기

계산해보면  TWBR 이 72 일때 100Khz 가 나온다. (분주비 1일때)

데이타 시트에 보면 data transfer speed 는 400Khz 까지 가능하다고 나와 있음으로 100Khz 를 사용하겠다.

 

레지스터 초기 값 확인 

void setup() 
{
  Serial.begin(9600);
  Serial.print("TWBR : ");
  Serial.println(TWBR,BIN);
  Serial.print("TWSR : ");
  Serial.println(TWSR,BIN);
  Serial.print("TWCR : ");
  Serial.println(TWCR,BIN);
  Serial.print("TWCMR : ");
  Serial.println(TWAMR,BIN);              
}

  void loop() 
{
}

TWSR 는 초기화를 해준다. 

 

Master T code

다른 부분은 상관없지만 

setup 에 delay 는 조금 길게 줘야한다. 

보통 실험에서는 마스터와 슬레이브에 동시에 전원을 주곤 하는데 

슬레이브가 먼저 동작하고 있어야지 밑의 프로그램이 정상적으로 동작한다. 

void TWI_start(void);
void TWI_repeated_start(void);
void TWI_init_master(void);
void TWI_write_address(unsigned char);
void TWI_read_address(unsigned char);
void TWI_write_data(unsigned char);
void TWI_read_data(void);
void TWI_stop(void);

unsigned char address=0x20;
unsigned char read=1, write=0;
unsigned char write_data=0x01, recv_data;

void setup() 
{
  delay(2000);
  DDRD=0xff;
  TWI_init_master();  // Function to initialize TWI  
}

void loop() 
{
    if(write_data==0x00) write_data=1;
    
    TWI_start();// Function to send start condition
    TWI_write_address(address+write); // Function to write address and data direction bit(write) on SDA
    TWI_write_data(write_data);      // Function to write data in slave
    TWI_stop(); // Function to send stop condition

    delay(10);

    TWI_start(); 
    TWI_read_address(address+read); // Function to write address and data direction bit(read) on SDA
    TWI_read_data(); // Function to read data from slave 
    TWI_stop();
    
    delay(1000);
    write_data = (write_data<<1);
}

void TWI_read_data(void)
{
    TWCR=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte transmitted
    while((TWSR & 0xF8) != 0x58); // Check for the acknoledgement
    recv_data=TWDR;
    PORTD=recv_data;
}

void TWI_read_address(unsigned char data)
{
    TWDR=data; // Address and read instruction
    TWCR=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte received
    while((TWSR & 0xF8)!= 0x40);  // Check for the acknoledgement
}

void TWI_init_master(void) // Function to initialize master
{
    TWBR=72; // Bit rate
    TWSR=(0<<TWPS1)|(0<<TWPS0); // Setting prescalar bits
}
 
void TWI_start(void)
{
    // Clear TWI interrupt flag, Put start condition on SDA, Enable TWI
    TWCR= (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); 
    while(!(TWCR & (1<<TWINT))); // Wait till start condition is transmitted
    while((TWSR & 0xF8)!= 0x08); // Check for the acknowledgement
}
 
void TWI_write_address(unsigned char data)
{
    TWDR=data; // Address and write instruction
    TWCR=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte transmitted
    while((TWSR & 0xF8)!= 0x18);  // Check for the acknoledgement
}
 
void TWI_write_data(unsigned char data)
{
    TWDR=data; // put data in TWDR
    TWCR=(1<<TWINT)|(1<<TWEN);    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT))); // Wait till complete TWDR byte transmitted
    while((TWSR & 0xF8) != 0x28); // Check for the acknoledgement
}
 
  
void TWI_stop(void)
{
    // Clear TWI interrupt flag, Put stop condition on SDA, Enable TWI
    TWCR= (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); 
    while(!(TWCR & (1<<TWSTO)));  // Wait till stop condition is transmitted
}

Slave S code 

TWI_match _xx 함수를 보면 알수 있는데 TWSR 레지스터에 값을 받을때까지 계속해서 TWINT 를 clear 해주고 다시 1로  set 될때까지 기다리면서 TWI 가 동작하도록 해줘야 한다. 

 


void TWI_init_slave(void);
void TWI_match_read_slave(void);
void TWI_read_slave(void);
void TWI_match_write_slave(void);
void TWI_write_slave(void);
 
unsigned char write_data,recv_data;

void setup() 
{
    DDRD=0xff;
    TWI_init_slave(); // Function to initilaize slave
}

void loop() 
{
    TWI_match_read_slave(); //Function to match the slave address and slave dirction bit(read) 
    TWI_read_slave(); // Function to read data

    write_data=~recv_data; // Togglem the receive data
 
    TWI_match_write_slave(); //Function to match the slave address and slave dirction bit(write) 
    TWI_write_slave();       // Function to write data
}
 
void TWI_init_slave(void) // Function to initilaize slave
{
    TWAR=0x20; // Fill slave address to TWAR
}

void TWI_match_write_slave(void) //Function to match the slave address and slave dirction bit(write) 
{
    while((TWSR & 0xF8)!= 0xA8) // Loop till correct acknoledgement have been received
    {
        // Get acknowlegement, Enable TWI, Clear TWI interrupt flag
        TWCR=(1<<TWEA)|(1<<TWEN)|(1<<TWINT); 
        while (!(TWCR & (1<<TWINT)));  // Wait for TWINT flag
    }
}

void TWI_write_slave(void) // Function to write data
{
    TWDR= write_data;           // Fill TWDR register whith the data to be sent 
    TWCR= (1<<TWEN)|(1<<TWINT);   // Enable TWI, Clear TWI interrupt flag 
    while((TWSR & 0xF8) != 0xC0); // Wait for the acknowledgement
}



void TWI_read_slave(void)
{
    // Clear TWI interrupt flag,Get acknowlegement, Enable TWI
    TWCR= (1<<TWINT)|(1<<TWEA)|(1<<TWEN); 
    while (!(TWCR & (1<<TWINT))); // Wait for TWINT flag
    while((TWSR & 0xF8)!=0x80); // Wait for acknowledgement
    recv_data=TWDR; // Get value from TWDR
    PORTD=TWDR; // send the receive value on PORTB
}
 
void TWI_match_read_slave(void) //Function to match the slave address and slave dirction bit(read)
{
    while((TWSR & 0xF8)!= 0x60)  // Loop till correct acknoledgement have been received
    {
    // Get acknowlegement, Enable TWI, Clear TWI interrupt flag
    TWCR=(1<<TWEA)|(1<<TWEN)|(1<<TWINT); 
    while (!(TWCR & (1<<TWINT)));  // Wait for TWINT flag
    }
}

 

 

코드 출처: 

https://www.engineersgarage.com/how-to-use-i2c-twi-two-wire-interface-in-avr-atmega32-part-36-46/

 

How to use I2C / TWI (Two Wire Interface) in AVR ATmega32- (Part 36/46)

This article explores the TWI interfacing between two ATmega32 controllers. Readers are advised to go through TWI Communication and TWI registers[[wysiwyg_imageupload::]]of ATmega32 before going further. Generally modes 1 & 3 and modes 2 & 4 are us

www.engineersgarage.com

참고로 위는 atmel studio 에서 작성 한것 같다 나는 아두이노 스케치를 사용해서 구현 했다.

댓글