ATmega8 MCU 간의 TWI 기능을 이용한 I2C 통신

by digipine posted Nov 02, 2017
?

Shortcut

PrevPrev Article

NextNext Article

ESCClose

Larger Font Smaller Font Up Down Go comment Print

두개의 ATmega8 MCU 간의 TWI 기능을 사용하여 데이터 전달을 하는 프로그램을 작성합니다.
 

IC1 을 마스터로 지정하고 IC2 를 슬레이브로 지정해서 하이퍼터미널로 입력된 데이터를 시리얼 통신으로 IC1 에 전달하고, IC1 은 다시 TWI 로 IC2 에 데이터를 전달합니다.

IC2 는 전달받은 데이터를 LCD 에 표시하고, 다시 IC1 으로 TWI 를 통해서 전달하면 IC1 은 이 데이터를 시리얼 통신으로 하이퍼터미널에 전달해서 표시하는 프로그램입니다.

(AT24C02 칩은 소켓에서 제거하세요.)

 

코드비젼(CodeVision) 에서 작성한 프로그램은 아래와 같습니다.

 

마스터 (IC1) 의 프로그램입니다.

 

// I/O register definitions for ATmega8
#include <mega8.h>
#include <delay.h>
#include <stdio.h>
#define ESC 0x1b

typedef unsigned char byte;

byte twi_master_read(byte addr)
{
        byte dat;
       
        TWCR = 0xa4;                    // START
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x08));
        TWDR = (addr << 1) | 1;
        TWCR = 0x84;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x40));
        TWCR = 0x84;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x58));
        dat = TWDR;
        TWCR = 0x94;
        return dat;
}

void twi_master_write(byte addr, byte dat)
{
        TWCR = 0xa4;                    // START
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x08));
        TWDR = addr << 1;               // ADDRESS
        TWCR = 0x84;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x18));
        TWDR = dat;                     // WRITE
        TWCR = 0x84;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x28));
        TWCR = 0x94;
}

void main(void)
{                     
        byte ch;

        UCSRB |= 0x08;
        UCSRB |= 0x10;
        UBRRL = 5;      // X-Tal=11.0592MHz BAUD=115200

        DDRC = 0x0f;

        TWBR = 12;
        TWSR = 0x00;
        printf("\n\rEnter a character....");
        do {
                ch = getchar();
                PORTC = ~ch;
                twi_master_write(0x38, ch);

                delay_us(100);
                ch = twi_master_read(0x38);
                if (ch == ESC) putchar('\f');
                else putchar(ch);
        } while(1);
}

 

슬레이브 (IC2) 의 프로그램입니다.

 

// I/O register definitions for ATmega8
#include <mega8.h>
#include <delay.h>

#define lcd_inst_wr     (PORTC = 0x04)
#define lcd_data_wr     (PORTC = 0x05)
#define lcd_data(i)     (PORTD = i)
#define ESC 0x1b
typedef unsigned char byte;

void lcd_iw(byte inst)
{
        lcd_inst_wr;
        lcd_data(inst);
        delay_us(40);
        PORTC &= 0xfb;
       
        lcd_inst_wr;
        lcd_data(inst<<4);
        delay_us(40);
        PORTC &= 0xfb;
        delay_ms(2);
}

void lcd_dw(byte dw)
{
        lcd_data_wr;
        lcd_data(dw);
        delay_us(40);
        PORTC &= 0xfb;

        lcd_data_wr;
        lcd_data(dw<<4);
        delay_us(40);
        PORTC &= 0xfb;
}

void init_lcd(void)
{
        lcd_iw(0x20);
        lcd_iw(0x28);
        lcd_iw(0x06);
        lcd_iw(0x0e);
        lcd_iw(0x01);
}                  

void lcd_str(char *str)
{
        while(*str){
                lcd_dw(*str++);
        }
}

byte twi_slave_read(byte addr)
{
        byte dat;
       
        TWAR = addr << 1;
        TWCR = 0x44;                    // SLAVE
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x60));
        TWCR = 0xc4;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x80));
        dat = TWDR;                     // READ
        TWCR = 0xc4;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0xa0));
        TWCR = 0xc4;
        return dat;
}

void twi_slave_write(byte addr, byte dat)
{
        TWAR = addr << 1;
        TWCR = 0x44;                    // SLAVE
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0xa8));
        TWDR = dat;
        TWCR = 0xc4;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0xc0));
        TWCR = 0xc4;
}

void main(void)
{                     
        byte ch;
        char *str1 = "<TWI(I2C) - TWI>";
        DDRC = 0x07;
        DDRD = 0xf0;

        init_lcd();

        lcd_str(str1);
        lcd_iw(0xc0);
       
        TWSR = 0x00;
       
        do {
                ch = twi_slave_read(0x38);
                if (ch == ESC) lcd_iw(0xc0);
                else           lcd_dw(ch);

                delay_ms(1);
                twi_slave_write(0x38, ch);
        } while(1);
}

 

AVR-GCC 에서 작성한 프로그램은 아래와 같습니다.

 

마스터 (IC1) 의 프로그램입니다.

 

// I/O register definitions for ATmega8
#include <avr/io.h>
#include <stdio.h>
#define ESC 0x1b

typedef unsigned char byte;

void delay_us(unsigned int time_us)
{
        unsigned int i;
        for(i=0; i<time_us; i++){ // 4 cycle +
                asm("PUSH R0"); // 2 cycle +
                asm("POP R0"); // 2 cycle +
                asm("PUSH R0"); // 2 cycle +
                asm("POP R0"); // 2 cycle + =12 cycle for 11.0592MHZ
//              asm("PUSH R0"); // 2 cycle +
//              asm("POP R0"); // 2 cycle = 16 cycle = 1us for 16MHz
        }
}
void delay_ms(unsigned int time_ms)
{
        unsigned int i;
        for(i=0; i<time_ms;i++)
                delay_us(1000);
}

int uart_putchar(char c)
{
        if (c == '\n')
                uart_putchar('\r');
        loop_until_bit_is_set(UCSRA, UDRE);
        UDR = c;
        return 0;
}

int uart_getchar(void)
{
        char c;
        loop_until_bit_is_set(UCSRA, RXC);
        c = UDR;
        return c;
}

byte twi_master_read(byte addr)
{
        byte dat;
       
        TWCR = 0xa4;                    // START
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x08));
        TWDR = (addr << 1) | 1;
        TWCR = 0x84;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x40));
        TWCR = 0x84;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x58));
        dat = TWDR;
        TWCR = 0x94;
        return dat;
}

void twi_master_write(byte addr, byte dat)
{
        TWCR = 0xa4;                    // START
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x08));
        TWDR = addr << 1;               // ADDRESS
        TWCR = 0x84;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x18));
        TWDR = dat;                     // WRITE
        TWCR = 0x84;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x28));
        TWCR = 0x94;
}

int main(void)
{                     
        byte ch;
        FILE    *fp;

        fp = fdevopen(uart_putchar, uart_getchar, 0);
        UCSRB = 0x18;
        UBRRL = 5;      // X-Tal=11.0592MHz BAUD=115200

        DDRC = 0x0f;

        TWBR = 12;
        TWSR = 0x00;
        printf("\n\rEnter a character....");
        do {
                ch = getchar();
                PORTC = ~ch;
                twi_master_write(0x38, ch);

                delay_us(100);
                ch = twi_master_read(0x38);
                if (ch == ESC) putchar('\f');
                else putchar(ch);
        } while(1);
}


슬레이브 (IC2) 의 프로그램입니다.

 

// I/O register definitions for ATmega8
#include <avr/io.h>

#define lcd_inst_wr     (PORTC = 0x04)
#define lcd_data_wr     (PORTC = 0x05)
#define lcd_data(i)     (PORTD = i)
#define ESC 0x1b
typedef unsigned char byte;

void delay_us(unsigned int time_us)
{
        unsigned int i;
        for(i=0; i<time_us; i++){ // 4 cycle +
                asm("PUSH R0"); // 2 cycle +
                asm("POP R0"); // 2 cycle +
                asm("PUSH R0"); // 2 cycle +
                asm("POP R0"); // 2 cycle + =12 cycle for 11.0592MHZ
                asm("PUSH R0"); // 2 cycle +
                asm("POP R0"); // 2 cycle = 16 cycle = 1us for 16MHz
        }
}
void delay_ms(unsigned int time_ms)
{
        unsigned int i;
        for(i=0; i<time_ms;i++)
                delay_us(1000);
}

void lcd_iw(byte inst)
{
        lcd_inst_wr;
        lcd_data(inst);
        delay_us(40);
        PORTC &= 0xfb;
       
        lcd_inst_wr;
        lcd_data(inst<<4);
        delay_us(40);
        PORTC &= 0xfb;
        delay_ms(2);
}

void lcd_dw(byte dw)
{
        lcd_data_wr;
        lcd_data(dw);
        delay_us(40);
        PORTC &= 0xfb;

        lcd_data_wr;
        lcd_data(dw<<4);
        delay_us(40);
        PORTC &= 0xfb;
}

void    htoa(byte hh)
{
        byte    temp;

        temp=hh;
        hh &= 0xf0;     hh >>= 4;
        if (hh >= 10)   hh += 7;   
        hh += '0';
        lcd_dw(hh);

        hh=temp;
        hh &= 0x0f;
        if (hh >= 10)   hh += 7; 
        hh += '0';
        lcd_dw(hh);
}

void init_lcd(void)
{
        lcd_iw(0x20);
        lcd_iw(0x28);
        lcd_iw(0x06); //entry mode set
        lcd_iw(0x0e); //display on, cursor on, blink off
        lcd_iw(0x01); //clear display
}                  

void lcd_str(char *str)
{
        while(*str){
                lcd_dw(*str++);
        }
}

byte twi_slave_read(byte addr)
{
        byte dat;
       
        TWAR = addr << 1;
        TWCR = 0x44;                    // SLAVE
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x60));
        TWCR = 0xc4;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0x80));
        dat = TWDR;                     // READ
        TWCR = 0xc4;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0xa0));
        TWCR = 0xc4;
        return dat;
}

void twi_slave_write(byte addr, byte dat)
{
        TWAR = addr << 1;
        TWCR = 0x44;                    // SLAVE
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0xa8));
        TWDR = dat;
        TWCR = 0xc4;
        while(((TWCR & 0x80) == 0x00) || ((TWSR & 0xf8) != 0xc0));
        TWCR = 0xc4;
}

int main(void)
{                     
        byte ch;

        DDRC = 0x07;
        DDRD = 0xf0;
       
        init_lcd();

        lcd_str("<TWI(I2C) - TWI>");
        lcd_iw(0xc0);
       
        TWSR = 0x00;
       
        do {
                ch = twi_slave_read(0x38);
                if (ch == ESC) lcd_iw(0xc0);
                else           lcd_dw(ch);

                delay_ms(1);
                twi_slave_write(0x38, ch);
        } while(1);
}

 
TAG •

Articles

1 2 3 4 5 6