logo

English

이곳의 프로그래밍관련 정보와 소스는 마음대로 활용하셔도 좋습니다. 다만 쓰시기 전에 통보 정도는 해주시는 것이 예의 일것 같습니다. 질문이나 오류 수정은 siseong@gmail.com 으로 주세요. 감사합니다.

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

by digipine posted Nov 02, 2017
?

Shortcut

PrevPrev Article

NextNext Article

Larger Font Smaller Font Up Down Go comment Print
?

Shortcut

PrevPrev Article

NextNext Article

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 •

List of Articles
No. Subject Author Date Views
104 ALM의 등장 배경, 오해와 진실 digipine 2017.10.28 376
» ATmega8 MCU 간의 TWI 기능을 이용한 I2C 통신 digipine 2017.11.02 5986
102 AWS EC2 Ubuntu 용 Docker 설치 스크립트 digipine 2021.09.01 345
101 Bitbucket에서 SSH 키 등록하고 사용하는 방법 (맥/리눅스) file lizard2019 2023.06.22 858
100 C/C++ struct 패딩(padding) 원리 이해 lizard2019 2019.03.04 2149
99 Certbot으로 무료 인증서 발급 받기 digipine 2020.09.03 522
98 CMM / CMMI 란 무엇인가? digipine 2017.10.28 2467
97 Compile FFmpeg on Ubuntu, Debian, or Mint digipine 2017.11.02 327
96 Docker Compute Engine Ubuntu에서 Docker 설치 방법 lizard2019 2021.04.15 463
95 Docker 모든 컨테이너를 Stop 또는 Remove 하는 방법 digipine 2021.09.01 202
94 Docker에서 Phabricator 최신버전 설치 및 버전 확인 방법 file lizard2019 2021.04.15 1400
93 FFServer RTSP Audio Server Config digipine 2023.05.12 224
92 FFT (Fast Fourier Transform) 고속 푸리에 변환 예제 소스 digipine 2017.10.29 12544
91 gcc thread and mutex 사용법 lizard2019 2019.02.27 1198
90 Git Commit 취소 관련 명령어 정리 1 digipine 2017.11.02 1327
89 Git Commnd 사용법 정리 digipine 2017.11.02 263
88 Git Http Backend Upload Size 설정 - Http 500 Error 해결 digipine 2017.11.02 2074
87 Git 서버 구축 - 우분투[Ubuntu] digipine 2017.11.02 307
86 git 환경 설정 및 명령어 정리 digipine 2017.11.03 425
85 Golang Channel 사용법 정리 digipine 2021.10.22 414
Board Pagination Prev 1 2 3 4 5 6 Next
/ 6