1) 지식 창고는 본인이 작성한 콘텐츠(팁/노하우/리소스/강좌 등)을 무료 혹은 가상화폐인 납포인트를 통해 공유하는 공간입니다.
2) 본인이 작성한 콘텐츠에 대해서만 지식 창고에 등록할 수 있으며, 저작권에 위배되는 콘텐츠는 사전경고 없이 삭제될 수 있습니다.
3) 콘텐츠 구매 및 첨부파일 다운로드는 회원그룹 '연구원' 이상 가능하오니, 경험치를 쌓아 진급한 후에 이용 부탁드립니다.
4) 무료 콘텐츠의 본문은 구매절차 없이 즉시 이용할 수 있으며, 판매 납포인트가 있는 콘텐츠는 구매 후 이용할 수 있습니다.
5) 콘텐츠 판매에 따른 납포인트 수익은 지정한 비율(50%)에 따라 판매자에게 지급하며, 납포인트 수익을 통해 진급을 빨리할 수 있습니다.
6) 구매 후 평가를 하면 구매 납포인트의 20%를 돌려 드립니다.
판매자 | 까까 | 판매 납포인트 | 무료 | 평점 | 1.0점 / 총 1명 참여 |
---|
/****************************************
* MDA-MULTI SENSOR
* MCU : AVR (ATMEGA128)
* COMPILER : IAR
* FILE NAME : I2C.C
****************************************/
/*****************************************
< 배선 하기 >
PD0,PD1 ==> [SERIAL EEPROM] SCL,SDA
PE0,PE1 ==> [RS-232C] RX,TX
******************************************/
/*****************************************
동작 설명
MDA-Multi MICOM PROGRAMER의 "데이터 통신 윈도우"를 선택하고
화면에서 마우스의 오른쪽 버튼을 클럭 후 "시리얼 초기화"를 선택하고
통신포트 설정 윈도우에서 통신포트를 초기화 한다.
라이트 명령으로 값을 써넣고,
리드 명령으로 값을 확인한다.
예)
W 0010 12 [엔터] -> 0010번지에 12H값, 라이트 성공시 OK! 메세지 디스플레이 된다.
R 0010 [엔터] -> 0010번지의 값이 디스플레이 된다.
******************************************/
#include "iom128.h" // I/O가 정의 되어 있는 헤더 파일
// I2C 핀 정의
#define SCL_DIR DDRD_Bit0 // SCL_DIR 비트
#define SDA_DIR DDRD_Bit1 // SDA_DIR 비트
#define SCL_OUT PORTD_Bit0 // SCL_OUT 비트
#define SDA_OUT PORTD_Bit1 // SDA_OUT 비트
#define SCL_IN PIND_Bit0 // SCL_IN 비트
#define SDA_IN PIND_Bit1 // SDA_IN 비트
// UART 비트 정의
#define UDRE UCSR0A_Bit5 // UDRE 비트
#define RXC UCSR0A_Bit7 // RXC 비트
#define MPCM UCSR0A_Bit0 // MPCM 비트
#define U2X UCSR0A_Bit1 // U2X 비트
#define UCSZ0 UCSR0C_Bit1 // UCSZ0 비트
// 24LC32 상수
#define WR24 0xa4 // 쓰기 명령(1 0 1 A2 1 A0 0)
#define RD24 0xa5 // 읽기 명령(1 0 1 A2 1 A0 1)
// ASCII 코드 및 메시지
__flash unsigned char ASCII[]="0123456789ABCDEF"; // 16진 ASCII 코드
__flash unsigned char ERR_MSG[]="ERROR ? ";
__flash unsigned char OK_MSG[]="OK ! ";
__flash unsigned char NO_HEX[]="Not Hexa. ? ";
__flash unsigned char NO_CO[]="Not Command ? ";
// 데이터 저장 버퍼
unsigned char BUFFER[15]; // 키 입력 버퍼
unsigned int ADDR; // EEPROM 어드레스 상위,하위
unsigned char EDATA; // EEPROM 데이터
unsigned char I2CDATA; // I2C 전송
unsigned char I2CADR; // I2C 어드레스, 방향
unsigned char I2CSTAT; // I2C 스테터스
unsigned char C_FLAG; // 캐리 플래그
void Error(char val)
{
PORTC = val;
while(1);
}
// UART 초기 설정
void SERIAL(void)
{
U2X = 0;
MPCM = 0;
UBRR0H = 0; // 7.3728[MHz]일 경우 9600[bps]
UBRR0L = 47;
UCSR0B = 0x18; // 송신,수신 인에이블
UCSR0C = 0x06;
}
// 송신
void PUT(unsigned char TX_D)
{
while(!UDRE); // 송신 ?
UDR0 = TX_D; // 송신
}
// 수신
unsigned char GET(void)
{
while(!RXC); // 수신 ?
return(UDR0); // 수신
}
// 캐리지 리턴, 라인 피드
void CR_LF(void)
{
PUT(0x0d); // 캐리지 리턴 송신
PUT(0x0a); // 라인 피드 송신
}
// 에러 송신
void ERROR(void)
{
unsigned char i;
CR_LF(); // 캐리지 리턴,라인 피드 송신
for (i =0; i<8; i++){
PUT(ERR_MSG[i]);
}
}
// 에러 송신
void OK(void)
{
unsigned char i;
CR_LF(); // 캐리지 리턴,라인 피드 송신
for (i =0; i<5; i++){
PUT(OK_MSG[i]);
}
}
// 16진 에러 송신
void NOT_HEX(void)
{
unsigned char i;
CR_LF(); // 캐리지 리턴,라인 피드 송신
for (i =0; i<12; i++){
PUT(NO_HEX[i]);
}
CR_LF(); // 캐리지 리턴,라인 피드 송신
}
// 코맨드 에러 송신
void NOT_COMMAND(void)
{
unsigned char i;
CR_LF(); // 캐리지 리턴,라인 피드 송신
for (i =0; i<14; i++){
PUT(NO_CO[i]);
}
CR_LF(); // 캐리지 리턴,라인 피드 송신
}
/* I2C 함수들 */
// 5[ms] 지연 함수
void DELAY(unsigned int i)
{
while(i--);
}
// SCK 주기 함수
void HALF(unsigned char i)
{
while(i--);
}
// I2C 초기 설정
void S_INIT(void)
{
I2CSTAT = 0; // 스테터스 클리어
SCL_OUT = 0; // SCL, SDA 핀 하이 임피던스
SDA_OUT = 0;
SCL_DIR = 0;
SDA_DIR = 0;
}
// 1 바이트 전송
void I2C_WR(void)
{
unsigned char i;
C_FLAG = 0x01;
// 1바이트 전송
for(i=0; i<8; i++){
SCL_DIR = 1; // SCL = "L"
if (I2CDATA & 0x80){ SDA_DIR = 0;} // SDA 개방
else SDA_DIR = 1; // SDA = L
HALF(2); // 1/2 주기
SCL_DIR = 0; // SCL 개방
HALF(2); // 1/2 주기
I2CDATA <<= 1;
I2CDATA |= C_FLAG;
C_FLAG = 0;
}
// 슬레이브 ACK 신호 응답 대기
SCL_DIR = 1; // SCL = "L"
SDA_DIR = 0; // SDA 개방
HALF(2); // 1/2 주기
SCL_DIR = 0; // SCL 개방
while(!SCL_IN); // SCL이 "H"일때 까지 대기
C_FLAG = 0;
if (SDA_IN) { C_FLAG = 1;}
HALF(2); // SDA=H 면 1/2 주기 지연
}
// 스타트 조건, 슬레이브 어드레스 전송
void I2C_ST(void)
{
I2CDATA = I2CADR; // 어드레스 복사
SDA_DIR = 1; // SDA = "L"
HALF(1); // 1/4 주기
I2C_WR(); // 스타트 조건과 슬레이브 어드레스 송신
}
// I2C Repeat 스타트
void REPEAT(void)
{
SCL_DIR = 1; // SCL = "L"
SDA_DIR = 0; // SDA 개방
HALF(2); // 1/2 주기
SCL_DIR = 0; // SCL 개방
HALF(1); // 1/4 주기
I2C_ST(); // 스타트 조건과 슬레이브 어드레스 송신
}
// 데이터 전송
void I2C_DO(void)
{
unsigned char i;
if(!(I2CADR & 0x01)) I2C_WR(); // 쓰기인경우
// STOP 전에 ACK 응답이 없으면 c_flag=1
// ACK 신호가 더 원할 경우 c_flag=0
else{ // 읽기
I2CSTAT <<= 1;
I2CSTAT |= C_FLAG;
C_FLAG = 0;
I2CDATA = 0;
// 데이터 입력
for (i = 0; i < 8 ; i++){
SCL_DIR = 1; // SCL = "L"
HALF(2); // 1/2 주기
SCL_DIR = 0; // SCL 개방
HALF(2); // 1/2 주기
I2CDATA <<= 1;
if (SDA_IN)(I2CDATA |= 0x01); // "1"인 경우
} // for
// ACK 신호 전송
SCL_DIR = 1; // SCL = "L"
if(I2CSTAT & 0x01){
SDA_DIR = 0; // SDA 개방
I2CSTAT = 0;
}
else SDA_DIR = 1; // SDA = "L"
HALF(2); // 1/2 주기
SCL_DIR = 0; // SCL 개방
while(!SCL_IN); // SCL="H"일때 까지 대기
HALF(2); // 1/2 주기
} // else
}
// STOP 조건 전송
void I2C_STP(void)
{
SCL_DIR = 1; // SCL = "L"
SDA_DIR = 1; // SDA = "L"
HALF(2); // 1/2 주기
SCL_DIR = 0; // SCL 개방
HALF(2); // 1/2 주기
SDA_DIR = 0; // SDA 개방
HALF(2); // 1/2 주기
}
// 바이트 리드
void EEREAD(void)
{
I2CADR = WR24; // 디바이스 어드레스, 라이트 셋
I2C_ST(); // 스타트 조건과 어드레스 송신
I2CDATA = (ADDR >> 8); // I2CDATA = ADDRH
I2C_DO(); // 어드레스 상위 전송
I2CDATA = ADDR; // I2CDATA = ADDRL
I2C_DO(); // 어드레스 하위 전송
I2CADR = RD24; // 디바이스 어드레스, 리드 셋
REPEAT(); // 리피트 스타트 조건과 어드레스 송신
C_FLAG = 0x01; // NO ACK 신호 설정
I2C_DO();
I2C_STP(); // STOP 조건 송신
EDATA = I2CDATA; // EDATA에 저장
}
// 바이트 라이트
void EEWRITE(void)
{
unsigned char temp;
I2CADR = WR24; // 디바이스 어드레스, 라이트 셋
I2C_ST(); // 스타트 조건과 어드레스 송신
I2CDATA = (ADDR>>8); // I2CDATA = ADDRH
I2C_DO(); // 어드레스 상위 전송
I2CDATA = ADDR; // I2CDATA = ADDRL
I2C_DO(); // 어드레스 하위 전송
I2CDATA = EDATA; // I2CDATA = EDATA
I2C_DO();
I2C_STP(); // STOP 조건 송신
DELAY(50000); // 5[ms] 지연
// 베리파이
temp = EDATA; // 저장
DELAY(50000); // 5[ms] 지연
EEREAD(); // 읽기
if (temp != EDATA) ERROR(); // 같지 않으면 에러
else OK(); // 같으면 OK
}
// 16진 검사
unsigned char CHECK_HEX(unsigned hexa)
{
if ((hexa < '0') | ((hexa > '9') & (hexa < 'A')) | (hexa > 'F')) return(0xff);
else if (hexa < 0x40) return(hexa & 0x0f);
else return((hexa & 0x0f)+0x09);
}
// EEROM 읽기
void E_READ(void)
{
unsigned char temp2,i;
unsigned long addr_temp;
// 어드레스를 16진으로 변환
addr_temp = 0;
for (i = 2; i < 6; i++){
temp2 = CHECK_HEX(BUFFER[i]);
if(temp2 == 0xff) {
NOT_HEX();
return;
}
else {
addr_temp |= temp2;
addr_temp <<= 4;
}
}
// 어드레스 저장
ADDR = addr_temp >> 4;
// EEROM 읽기
EEREAD();
CR_LF();
PUT(ASCII[(EDATA >> 4) & 0x0f]); // 데이터 상위
PUT(ASCII[EDATA & 0x0f]); // 데이터 하위
CR_LF();
}
// EEROM 쓰기
void E_WRITE(void)
{
unsigned char temp2,i;
unsigned long addr_temp;
// 어드레스를 16진으로 변환
addr_temp = 0;
for (i = 2; i < 6; i++){
temp2 = CHECK_HEX(BUFFER[i]);
if(temp2 == 0xff) {
NOT_HEX();
return;
}
else {
addr_temp |= temp2;
addr_temp <<= 4;
}
}
// 어드레스 저장
ADDR = addr_temp >> 4;
// 데이터를 16진으로 변환
addr_temp = 0;
for (i = 7; i < 9; i++){
temp2 = CHECK_HEX(BUFFER[i]);
if(temp2 == 0xff) {
NOT_HEX();
return;
}
else {
addr_temp |= temp2;
addr_temp <<= 4;
}
}
// 어드레스 저장
EDATA = addr_temp >> 4;
// EEROM 쓰기
EEWRITE();
CR_LF();
}
// 메인
void main(void)
{
unsigned char temp,i;
DDRC = 0xff;
PORTC = 0xff;
SERIAL(); // UART 초기 설정
S_INIT(); // SPI 초기 설정
// 캐리지 리턴 키가 입력될때 까지 루프
do{
i = 0;
do{
temp = GET(); // 수신
PUT(temp); // 송신
BUFFER[i] = temp;
i++;
if (i == 16) i=0; // 버퍼 끝인 경우 초기 값 저장
}while(!(temp == 0x0d));
// 코맨드 해석
temp = BUFFER[0];
if (temp == 'R') E_READ(); // 'R'인 경우 EEROM 읽기
else if (temp == 'W') E_WRITE(); // 'W'인 경우 EEROM 쓰기
else NOT_COMMAND(); // 에러 송신
}while(1);
}