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
24 Ubuntu Server OS 한국어 모드로 설치 후 서버 콘솔에서 한글 깨짐 해결 방법 digipine 2017.10.31 2240
23 [ubuntu, 우분투] sendmail 설치 digipine 2017.11.02 2314
22 CMM / CMMI 란 무엇인가? digipine 2017.10.28 2467
21 LibVLC 미디어 재생기 프로그래밍 방법 C++, QT 엉뚱도마뱀 2018.04.20 2500
20 초고속망 통신사 DNS 서버 주소 모음 - DNS 설정 digipine 2017.11.03 2630
19 WIN CE, GPS - NMEA protocol - GPS Virtual Driver digipine 2017.10.28 2829
18 Xcode 없이 맥에 '명령어 라인 도구(Command Line Tools)'를 설치하는 방법 엉뚱도마뱀 2018.12.26 2859
17 [Linux, OSX] pfctl - Packet FIlter Control 사용법 digipine 2017.11.02 3179
16 OpenAL 사용법 정리 1 digipine 2017.11.01 3397
15 [iOS] Bluetooth로 App을 백그라운드 모드로 실행는 방법 lizard2019 2020.02.11 3514
14 비밀번호 해쉬에 Salt(소금) 첨가하기 file 엉뚱도마뱀 2017.11.23 4272
13 난수발생기 개론 엉뚱도마뱀 2017.11.22 4311
12 공짜 무료 C/C++ 컴파일러들 file digipine 2017.10.28 4376
11 WinPCap과 Ethereal, Wireshark 을 이용한 스니핑(Sniffing) digipine 2017.10.29 5428
» ATmega8 MCU 간의 TWI 기능을 이용한 I2C 통신 digipine 2017.11.02 5986
9 Phabricator 설치 가이드 우분투 16.04 기준 digipine 2017.11.02 6193
8 Photoshop CC 2018 한글 영문 변환 언어팩, 포토샵 언어변경 file 엉뚱도마뱀 2018.07.04 8525
7 FFT (Fast Fourier Transform) 고속 푸리에 변환 예제 소스 digipine 2017.10.29 12544
6 Linux init.d 에서 등록하기. 부팅 시 자동실행 설정 digipine 2017.11.03 12566
5 [Swift, MacOS] 맥 한글 파일명이 윈도우에서 자소 분리되는 현상 해결, NFD, NFC 엉뚱도마뱀 2018.12.11 20072
Board Pagination Prev 1 2 3 4 5 6 Next
/ 6