유리한과 함께하는 AVR로 임베디드 개념쌔우기 - #7. 시리얼 통신 !!
아..정말 미안하다.
귀차니즘이 극에 달해서 조낸 오래 쉰것같다..
쥐도새도 모르게 싸려고 했는데..
밑에 햏햏횽 때문에 쌀수가 없었다. 제기랄.
날이 갈수록 소스가 길어진다.
이해해주길 바래.
오늘 할것은 PC와 avr간의 통신이야.
USART / UART 라는 놈이지.
usart는
The Universal Synchronous and Asynchronous serial Receiver and Transmitter
되시겠다.
직렬 동기/비동기화 통신 되시겠고..
uart는
The Universal Asynchronous serial Receiver and Transmitter
비동기 직렬되시겠다.
stop, start 비트가 존재해서
먼저 비트 보내주면 수신대기상태로 들어가고
레지스터 셋팅된대로 데이터 받아들여서 처리해주는 놈 되시겠다.
쉽게 생각하면.. 모뎀이랑 비슷하다.ㅋ
언제나 말하지만 개념쌔우기지 avr 심화 강좌가 아니야.
인터럽트는 RX 인터럽트만 사용할거고..
UART0만 사용할거다.
바로 소스랑 주석 나간다.
#include<avr/io.h>
#include<avr/interrupt.h>
#include<util/delay.h>
#include<stdio.h>
#define F_CPU 16000000UL //16MHz
void uart0_init(unsigned long BaudRate);
int putch(char ch);
void putstr(char* str);
int main(void)
{
cli(); // clear interrupt. sei()와 더불어 사용. 크리티컬섹션의 역할.
uart0_init(38400); // uart0 initialize. baudrate = 38400
fdevopen(putch, NULL); // 반드시 함수의 return형은 int, arg는 char형이어야 함
DDRA=0xFF; // PORTA 출력핀으로 설정
PORTA=0x01;
sei(); // set enable interrupt
while(1);
return 0;
}
void uart0_init(unsigned long BaudRate)
{
// Not Double mode, Not multi_communication
UCSR0A=0x00;
// 0b 1001 1000 RXCIE,TXCIE,UDRIE,RxEN,TxEN,xxx
UCSR0B=0x98;
UCSR0C=0x06;
// Setting BaudRate
UBRR0H=0x00;
UBRR0L=(F_CPU/BaudRate/16 - 1);
}
int putch(char ch)
{
if (ch == \'\\n\') //개행문자..
putch(\'\\r\');
while((UCSR0A&0x20)==0x00); // 스트림 버퍼가 비면
UDR0=ch; // 데이터 날려줌
return 0;
}
void putstr(char* str)
{
while(*str) putch(*str++);
}
ISR(USART0_RX_vect)
{
char buf;
buf=UDR0;
switch(buf)
{
case \',\' :
PORTA=PORTA<<1;
if(!PORTA)PORTA=0x80;
break;
case \'.\' :
PORTA=PORTA>>1;
if(!PORTA)PORTA=0x01;
break;
case \'a\' :
putstr("Hell\'o World!!\\n");
break;
case \'s\' :
printf("Now PORTA is %#04x\\n",PORTA);
break;
default :
break;
}
}
뭐 필요한 사람은 첨부된 소스 / makefile 가져가라. 컴파일은 make all 하면 되시겠다.
프로그램을 설명하자면.. 터미널로 ,랑.을 찍으면 LED가 한칸씩 왔다리 갔다리 하고..
a를 누르면 터미널상에 Hell\'o World!! 가 찍히고..
s를 누르면 터미널상에 현재 PORTA의 값을 출력해주는 놈이다.
일단 실행 화면.

원래는 TeraTerm을 주로사용하지만..
실행 동영상. 내방이다.ㅋ
이 소스에서 중요한곳은 딱 두군데.
void uart0_init(unsigned long BaudRate);
ISR(USART0_RX_vect);
겠지?
지금까지 착실하게 공부했으면 ISR(USART0_RX_vect)가 뭐하는 놈인지는
벌써 감이 팍!! 올게다.
ISR(USART0_RX_vect)는 데이터 수신이 완료되면 호출되는 인터럽트 서비스 루틴이다.
(혹시나 꼬꼼화를 위해 사족을 붙이자면.. RX는 수신 TX는 송신 되시겠다.)
void uart0_init(unsigned long BaudRate)
{
// Not Double mode, Not multi_communication
UCSR0A=0x00;
// 0b 1001 1000 RXCIE,TXCIE,UDRIE,RxEN,TxEN,xxx
UCSR0B=0x98;
UCSR0C=0x06;
// Setting BaudRate
UBRR0H=0x00;
UBRR0L=(F_CPU/BaudRate/16 - 1);
}
일단 USART에 대해 데이터 시트를 먼저 펴보는 기민함을 보여라.
172~198페이지니까 잘 보도록 해라. 귀찮아서 캡쳐는 생략한다.
UCSR은 USART Control and Status Register. 감이 오지?
A,B,C 세가지가 있다.
A는 거진 status 레지스터라 리드 전용이라고 봐도 무방하다.
double 모드랑 multi processor 설정하는게 있는데..
나도 잘 모르니 패스.
UCSRnB는 좀 중요하다.
// 0b 1001 1000 RXCIE,TXCIE,UDRIE,RxEN,TxEN,xxx
라고 친절히 주석도 달려있지?
인터럽트 관련 셋팅이다.
MSB 수신완료인터럽트/송신완료인터럽트/버퍼엥꼬 인터럽트/Rx활성화/
Tx활성화/캐릭터사이즈/rx data bit/tx data bit LSB
인데.. 자세한건 역시 데이터 시트 찾아봐라.
뒷쪽 세개는 주석에도 xxx라고 표시했듯이 별로 중요치 않다.
우리는 송수신 다쓰고 수신 인터럽트를 사용한다.
UCSR0C=0x06;
0x06은 0b0000 0110 이지?
데이터 시트 뒤져봐라.
캐릭터 사이즈 8bit로 셋팅한거다.
더이상의 자세한 설명은 생략한다?
UBRR 은 baudrate. 즉, 통신속도 설정이다.
(보통 1200 2400 4800 9600 14400 19600 38400 59600 129600 bps(bit per sec)다..)
데이터 시트에 클럭별 속도설정에 관한 내용이 좌악~ 나와있다.
간단하게 식으로 요약하면
UBRR0L=(F_CPU/BaudRate/16 - 1);
되시겠다.
모르겠으면 닥치고 외우자.
근데 보통 저렇게 해서 라이브러리로 만들어놓고 함수 불러다 쓴다.
뭐 이정도로 정리하자.
uart는 방식이 이렇다.
먼저 start bit 로 1비트를 날려주면 그걸 받고 대기모드로 들어간다.
그다음 통신속도 맞춰서 한비트씩 순서대로 날려준다. (FIFO방식으로 기억한다.)
그리고 끝난다는 표시로 stop bit 날려주고..
레지스터 셋팅으로 데이터 비트의 갯수도 바꿀수 있고,
뒤에 패리티비트도 추가시킬수 있다.(오류검증) odd,even 원하는대로..
비동기 통신 보다보면
rs-232네 rs-485네 뭐네 하는 말들이 자주 나오는데..
컴퓨터 시리얼 포트는 rs-232를 쓴다.
뭐 크게 다를건 없고.. 전압이 다르다.
그래서 그냥 uart보다는 232가 멀리가고
232보다는 485가 멀리가는거다.
485부터는 멀티드랍이라고 1대n 통신도 가능하다.
자세한건 각자 검색해보도록!
자, 다음으로 넘어가서..
PORT의 입출력은 어떻게 한다고 했지?
PORTx=data 로 출력하고
data=PINx; 로 입력받는다고 했다.
근데 uart는 더 단순하다.
UDRn..막강하다.(우린 uart0를 사용하니 UDR0다. ATMega128은 2개의 포트를 제공한다,)
수신은 data=UDR0;
송신은 UDR0=data;
위치따라 달라진다. 웃기는 놈이다.ㅋ
UDR0를 얘기하는데 (UCSR0A&0x20) 를 무시하고 지나갈수는 없겠지?
UCSRnA의 5번째 비트는 버퍼가 비어있으면 0, 차있으면 1이다.
쉽게 말해서 수신완료되면 0되고
송신 완료되면 0으로 떨어지는 놈이다.
수신은 몰라도 송신할때는 꼭 신경써줘야 된다.
int putch(char ch)
{
if (ch == \'\\n\') //개행문자..
putch(\'\\r\');
while((UCSR0A&0x20)==0x00); // 스트림 버퍼가 비면
UDR0=ch; // 데이터 날려줌
return 0;
}
에서 처럼 빌때까지 기다려줘야 된다.
안그러면 데이터가 깨져서 날라가겠지?
fdevopen(putch, NULL); // 반드시 함수의 return형은 int, arg는 char형이어야 함
는 printf를 사용하기 위해서 쓴건데..
인자로 함수를 넘겨준다.
저걸 잘 이용하면 간단하게 printf로 LCD에 출력할수도 있단거다.
참 편한 세상이지.
어쨌든 a누르면 문자열이 그냥 날라가고
s누르면 printf 호출해서 날라간다.
그냥 보여주려고 다르게 만든거니 신경쓰지 말자.
일단은 졸리니..
정리를 하게될지 그냥 닥치고 이대로 냅둘지는 모르겠지만..
수정은 나중에..
그럼 다음시간에 봐요~
p.s 혹시 무협 좋아하는 횽 없어?
난 취미생활로 무협드라마를 본다..
짱께들 스케일이 커서 그런지 무협드라마 만들었다 하면 기본 40부작이라 ㅎㄷㄷ해.
06 신조협려 41부작중에서.. 40화는 내가 대본/싱크작업한건데..(자막에 내 닉 나온다.)
무미랑전기도 한편인가 두편은 내가 싱크작업한거고..
뭐 그냥 그렇다고.
댓글 영역
획득법
① NFT 발행
작성한 게시물을 NFT로 발행하면 일주일 동안 사용할 수 있습니다. (최초 1회)
② NFT 구매
다른 이용자의 NFT를 구매하면 한 달 동안 사용할 수 있습니다. (구매 시마다 갱신)
사용법
디시콘에서지갑연결시 바로 사용 가능합니다.