AVR UART 비동기 통신 사용자 함수 문자 비교 LED ON/OFF 제어하기 - AVR 연습

2013.10.14 22:13




현재 군 복무중인 상태입니다.



USART레지스터를 정리했으니, 다음은 역시 간단하게 LED를 사용해서 UART통신을 통한 제어를 해보겠습니다. UART는 이 통신방식으로 지원되는 모듈들이 많아서 상당히 범용적으로 사용되는 통신이여서 꼼꼼하게 가겠습니다.

그나저나 고3이여서 포스팅이 느립니다. 그나마 틈틈이 하고 있어여 :-)



사용된 회로도를 볼까요!




모듈측은 원래 사용하던 LED에 추가로 PC와 AVR모듈사이에 USB to UART 장치 혹은 UART 직렬포트가 있는 컴퓨터의 경우 MAX232라는 IC를 통해 AVR과 연결해서 통신할수 있습니다.

저는 이전에 아두이노에 사용하려고 만들어 뒀던 CP2012를 사용한 USB to UART 장치를 통해서 AVR 모듈과 연결해서 테스트 해보았습니다. ~~ 그럼 소스보기로 ...~


 갑자기 노트북 쓰려니까 적응안되서 혼났습니다. 키적응도 안되고... ㅎ



CodeVision AVR용 소스코드 


#include <tiny2313.h>    // Tiny2313 입출력 관련 헤더파일을 포함합니다.

#include <delay.h>    // 지연함수 관련 헤더파일을 포함합니다.


char rx_char(void)    // 문자형 rx_char 수신 사용자 함수를 생성합니다.

{

while((UCSRA&0x80) == 0);    // 문자 수신이 완료될 때까지 대기 UCSRA의 RXC가 비트1 이 되면 다음라인으로

return UDR;    // UDR 수신데이터 반환

}


void tx_char(char tx_data)    // 문자형 tx_char 송신 사용자 함수를 생성합니다.

{

while((UCSRA&0x20) == 0);    // UDR레지스터가 빌 때까지 대기 UCSRA의 UDRE가 비트1 이 되면 다음라인으로

UDR = tx_data;    // UDR레지스터에 입력한 tx_data 입력합니다.

}


void main(void)    // 메인함수를 호출합니다.

{

char  i, data;    // 문자형 변수 i, data를 생성합니다.


DDRB=0xFF;    // B포트 8비트 전체를 출력으로 설정합니다.

PORTB=0x00;    // B포트 8비트 전체의 초기값을 논리0 (0V)로 설정합니다.


UCSRA=0x00;    // UART설정 레지스터A 별도 설정 없음

UCSRB=0x18;    // UART설정 레지스터B RXEN과 TXEN을 비트1로 설정해서 송수신기능을 활성화 합니다.

UCSRC=0x06;    // UART설정 레지스터C UCSZ1과 UCSZ0을 비트1로 설정해서 8비트 데이터 전송으로 설정합니다.

UBRRH=0x00;    // UBBR 통신속도 설정레지스터 상위 바이트로 8비트를 초과하지 않아 UBRRL에 모두 입력됩니다.

UBRRL=0xCF;    // UBRR 통신속도 설정레지스터 하위 바이트로 8Mhz크리스탈 2400bps속도로 207로 설정합니다.


while(1)    // 아래구문을 무한 반복합니다.

{

data = rx_char();    // data 변수에 rx_char 사용자 함수사용으로 수신된 데이터를 저장합니다.

if(data=='y')    // data변수와 문자y가 같으면

{

PORTB=0xFF;    // B포트 전체 논리1 (5V)를 출력합니다.

tx_char('_');    // tx_char 사용자 함수 사용으로 _문자를 송신합니다.

tx_char('o');    // tx_char 사용자 함수 사용으로 o문자를 송신합니다.

tx_char('k');    // tx_char 사용자 함수 사용으로 k문자를 송신합니다.

}

if(data=='n')    // data변수와 문자n과 같으면

{

PORTB=0x00;    // B포트 전체 논리0 (0V)를 출력합니다.

tx_char('_');    // tx_char 사용자 함수 사용으로 _문자를 송신합니다.

tx_char('o');    // tx_char 사용자 함수 사용으로 o문자를 송신합니다.

tx_char('k');    // tx_char 사용자 함수 사용으로 k문자를 송신합니다.

}

if(data=='b')    // data변수와 문자b가 같으면

{

for(i=0;i<3;i++)    // 아래구문을 3번 반복합니다.

{

PORTB=0xFF;    // B포트 전체 논리1 (5V)를 출력합니다.

delay_ms(200);    // 위 상태를 0.2초 유지합니다.

PORTB=0x00;    // B포트 전체 논리0 (0V)를 출력합니다.

delay_ms(200);    // 위 상태를 0.2초 유지합니다.

}

tx_char('_');    // tx_char 사용자 함수 사용으로 _문자를 송신합니다.

tx_char('o');    // tx_char 사용자 함수 사용으로 o문자를 송신합니다.

tx_char('k');    // tx_char 사용자 함수 사용으로 k문자를 송신합니다.

}

}

}



AVR Studio용 소스코드


#include <avr/io.h>    // AVR 입출력 관련 헤더파일을 포함합니다.

#define F_CPU 8000000UL    // 사용하고 있는 크리스탈 주파수 값을 상수로 설정합니다.

#include <util/delay.h>    // 지연 함수 관련 헤더파일을 포함합니다.


char rx_char(void)    // 문자형 rx_char 수신 사용자 함수를 생성합니다.

{

while((UCSRA&0x80) == 0);    // 문자 수신이 완료될 때까지 대기 UCSRA의 RXC가 비트1 이 되면 다음라인으로

return UDR;    // UDR 수신데이터 반환

}


void tx_char(char tx_data)    // 문자형 tx_char 송신 사용자 함수를 생성합니다.

{

while((UCSRA&0x20) == 0);    // UDR레지스터가 빌 때까지 대기 UCSRA의 UDRE가 비트1 이 되면 다음라인으로

UDR = tx_data;    // UDR레지스터에 입력한 tx_data 입력합니다.

}


int main(void)    // 메인함수를 호출합니다.

{

char  i, data;    // 부호없는 문자형 변수 i, data를 생성합니다.


DDRB=0xFF;    // B포트 8비트 전체를 출력으로 설정합니다.

PORTB=0x00;    // B포트 8비트 전체의 초기값을 논리0 (0V)로 설정합니다.


UCSRA=0x00;    // UART설정 레지스터A 별도 설정 없음

UCSRB=0x18;    // UART설정 레지스터B RXEN과 TXEN을 비트1로 설정해서 송수신기능을 활성화 합니다.

UCSRC=0x06;    // UART설정 레지스터C UCSZ1과 UCSZ0을 비트1로 설정해서 8비트 데이터 전송으로 설정합니다.

UBRRH=0x00;    // UBBR 통신속도 설정레지스터 상위 바이트로 8비트를 초과하지 않아 UBRRL에 모두 입력됩니다.

UBRRL=0xCF;    // UBRR 통신속도 설정레지스터 하위 바이트로 8Mhz크리스탈 2400bps속도로 207로 설정합니다.


while(1)    // 아래 구문을 무한 반복합니다.

{

data = rx_char();    // data 변수에 rx_char 사용자 함수사용으로 수신된 데이터를 저장합니다.

if(data=='y')    // data변수와 문자y가 같으면

{

PORTB=0xFF;    // B포트 전체 논리1 (5V)를 출력합니다.

tx_char('_');    // tx_char 사용자 함수 사용으로 _문자를 송신합니다.

tx_char('o');    // tx_char 사용자 함수 사용으로 o문자를 송신합니다.

tx_char('k');    // tx_char 사용자 함수 사용으로 k문자를 송신합니다.

}

if(data=='n')    // data변수와 문자n과 같으면

{

PORTB=0x00;    // B포트 전체 논리0 (0V)를 출력합니다.

tx_char('_');    // tx_char 사용자 함수 사용으로 _문자를 송신합니다.

tx_char('o');    // tx_char 사용자 함수 사용으로 o문자를 송신합니다.

tx_char('k');    // tx_char 사용자 함수 사용으로 k문자를 송신합니다.

}

if(data=='b')    // data변수와 문자b가 같으면

{

for(i=0;i<3;i++)    // 아래구문을 3번 반복합니다.

{

PORTB=0xFF;    // B포트 전체 논리1 (5V)를 출력합니다.

_delay_ms(200);    // 위 상태를 0.2초 동안 유지합니다.

PORTB=0x00;    // B포트 전체 논리0 (0V)를 출력합니다.

_delay_ms(200);    // 위 상태를 0.2초 동안 유지합니다.

}

tx_char('_');    // tx_char 사용자 함수 사용으로 _문자를 송신합니다.

tx_char('o');    // tx_char 사용자 함수 사용으로 o문자를 송신합니다.

tx_char('k');    // tx_char 사용자 함수 사용으로 k문자를 송신합니다.

}

}


return 0;    // 정상종료 값 0을 리턴합니다.

}



소스코드 동작 구성


생각보다 동작에 대한 구성은 어려움이 없습니다. 먼저 문자 수신 함수인 rx_char()은 UCSRA레지스터 즉 UART의 제어를 담당하는 레지스터 A중 RXC비트는 UCSRA 7번 비트인데요. 이 비트는 UART전송시 받은 데이터를 저장하는 UDR레지스터에 데이터가 수신이 완료되면 RXC비트가 1로 변하는데요. 다시 소스코드로 돌아와 while구문은 조건문이 거짓이면 while문을 빠져나오게 되는데, while((UCSRA&0x80) == 0)은 RXC비트가 1이 되면 0과 같지 않아 거짓이 되므로 다음 구문으로 넘어가고 다음구문은 return UDR;로 함수 사용시 수신된 데이터를 반환합니다.


송신 함수 tx_char도 마찬가지고 UCSRA레지스터의 UDRE비트는 UDR레지스터가 비었을 때 1이 되는데, 이 UDR레지스터에 쓰기를 하면 전송용 레지스터로 변경됩니다. 따라서 while((UCSRA&0x20) == 0)을 통해 UDRE비트가 1이 되면, 조건문이 거짓이게 되므로, while문을 빠져 나오고 UDR레지스터에 입력데이터 tx_data를 쓰기해서 UART로 전송하고 마지막으로 return 0; 값으로 정상 종료 합니다.



하이퍼 터미널 설정


먼저 컴퓨터에 별도의 시리얼 통신용 터미널 프로그램이 없다면 가볍게 무설치 하이퍼터미널을 다운로드 합니다.


 하이퍼터미널 다운로드 - 구글 드라이브로 연결됩니다.


실행시 위치정보 등록 창이 뜨면서 전화번호를 등록하라는 질의 창이 나오지만, 취소를 누르는데, 역시 정말 취소하시겠냐는 물음이 나옵니다. 여기서도 (예)를 눌러줍니다.

이 후 적당한 이름을 입력해서 새 연결을 생성합니다. 연결을 생성하고 나면 역시 위치정보 등록 창이 뜨는데, 불필요 하므로 역시 취소를 눌러줍니다.




연결에 사용할 통신 포트를 선택합니다. USB to UART 장치를 이용해서 만든 포트는 임의로 지정되기 때문에 연결한 직렬포트가 맞는지 확인 후 연결합니다.

(메인보드에 자체 지원하는 직렬포트는 Max232 IC로 TTL레벨로 변환 후 사용하고, COM1 또는 COM2 중 하나 입니다.)




AVR과 통신하고자 하는 속도를 선택합니다. AVR에서 레지스터 설정시에 2400Bps로 설정했기 때문에 비트/초는 2400으로 설정하고, 데이터 전송 비트는 8비트로 설정했기 때문에 데이터 비트는 8비트 패리티는 없음 정지비트는 1로 설정하고 흐름제어는 없음으로 설정합니다.




하이퍼터미널에서는 입력되는 문자가 표시가 안되기 때문에 설정이 필요한데요. 파일 > 속성 > 상단 설정 > ASCII설정 에서 ASCII 보내기 쪽은 필요에 따라 줄 끝에 LF(Line Feed)를 붙여 보냄 체크, 입력된 문자를 터미널 창에 표시 체크, ASCII 받기에서 받는 줄 끝에 LF(Line Feed) 붙임을 체크 합니다.




이후에 문자를 입력해서 전송이 되는지 동작이 되는지 테스트를 해봅니다.^





동작영상




소문자 y를 누르면 B포트 LED 전체가 들어오고, 소문자 n을 누르면 B포트 LED 전체가 꺼지고 소문자 b를 누르면 B포트 LED 전체가 3번 깜박이는 것을 확인 해 볼수 있습니다.

생각보다 장치가 많이 필요해서 애먹었지만, 문자비교 LED제어 포스팅 끝... 입니다. :-)




BinGoon AVR/AVR 연습, Tutorial , , , , , , ,

  1. Blog Icon
    SB.H

    잘보고 갑니다^^ 고3이시라고요? 고3인데 이정도 지식이라니 감탄사가 절로 나오네요. 앞으로도 자주 들어올께요

  2. 감사합니다.^ 가끔 블로그 방문해 주세요.^^

  3. Blog Icon
    ky.y

    안녕하세요! BinGoon님. 질문 한가지 더 드릴께요.
    이 소스에서 UCSRA의 레지스터가 CONTROL & STATUS의 기능을 갖고 있고 그래서 소스에
    UCSRA=0x00; 로 하셨는데 이렇게 초기화를 할 필요가 있는지요? 가령 자동으로 클리어 되지 않는지요?
    그리고 좋은 하루 되셔요^^

  4. 또 와주셨네요 ㅎㅎ
    자동으로 초기화 되는것이 맞습니다. 다만 사용되는 레지스터를 이론에서 모두 소개하고 이해를 돕기위해서 사용되는 레지스터를 전부 입력해서 쓰고 있습니다.^^

  5. Blog Icon
    ky,y

    안녕하세요! BinGoon님
    바뻐서 오랫만에 들어 왔네요^^ 질문하나 더 하문 귀찮겠지요?? 그래도 질문 드려요~~
    좀 이해가 안가는게 인터페이스에서 cp2012가 max232를 대체 한건가요? 아니면 pc에 시리얼 포트(9핀)가 있으면 직접 avr칩의 RX와 TX를 연결하라는 건가요?
    그림에 직접 pc에 연결이 되어서요?
    지금까지의 답변에 너무 감사하고 염치없이 또 질문 드립니다. 감사합니다.
    건강에 유의 하세요~~

  6. 최근에 일이 많아지면서 정신이 없어 답글을 늦게 작성합니다.
    질문 주신 부품에 대한 질문은 먼저 MAX232의 경우 컴퓨터에서 나오는 약10~12V의 RS232 고전압신호를 5V의 낮은 전압 신호로 변경시켜서 AVR과 통신할수 있도록 보조하는 역할을 합니다. AVR은 TTL 레벨에서만 동작하기 때문에 전압레벨의 변환을 해주는 IC이지요, 그리고 CP2102는 USB to UART로 변환하는 소자로 RS232 포트가 없는 컴퓨터라면 USB를 통해서 가상으로 포트를 생성해 낼수 있는 IC입니다. 이 IC를 사용시에는 RX, TX선이 TTL레벨로 입출력 하기 때문에 직결 연결 하시면 되고, RX -- TX, TX -- RX로 크로스 연결 해주셔야 합니다. 참고하시기 바랍니다.^

  7. Blog Icon
    SBY

    너무 자세하게 주석까지 달아 놓으시고,, 훌륭한 자료입니다.
    앞으로 자주 와서 볼꼐요.. 지식의 깊이가 보이네요.
    기대가 됩니다.~~

  8. 최근에 새 포스팅을 올리지 않아서 좀 그렇지만, 계속해서 좋은 정보 올리도록 노력하겠습니다.^

  9. Blog Icon
    최규진

    많이 배워갑니다 ㅎㅎ
    아참 ATmega128 기종을 가지고 따라하니까 코드에 에러가 떴었는데, 알고보니 UDR이나 UCSRA 대신 UDR0 UCSR0A 로 써줘야 하더군요. 혹시 안되시는분들 참고하시길 ㅎ

  10. 안녕하세요.^^
    도움되셨다니 제가 감사드립니다.
    계속해서 블로그 관리해 나갈 수 있도록 노력하겠습니다.^

  11. Blog Icon
    오중헌

    제가본 사이트중에서 최고 잘 정리되어 있는듯 합니다.
    고딩이신데 존경스럽습니다 -0-;
    앞으로도 많이 참고 하겠습니다. 감사합니다

  12. 안녕하세요. 방문해 주셔서 감사드립니다.^^
    계속 참고할수 있는 포스팅 하도록 노력하겠습니다. 현재는 조금 바쁜시기이고, 타지에 살고 있어 제한되는 부분이 많지만, 계속해서 블로그 살릴수 있도록 노력하겟습니다.^

  13. Blog Icon
    오중헌

    char rx_char()에서

    return UDR; 하는 순간

    RXC가 0으로 되나요?

  14. 안녕하세요.^^
    질문 주신 부분은 사용하시는 AVR의 데이터 시트에 보시면 자세하게 나와있지만, 대부분 AVR은 공통사항입니다. RXC비트의 경우 'UDR레지스터에서 데이터를 읽지 않았을 경우 Set (논리1)로 설정하며, 데이터를 읽었을 경우 Clear(논리0)으로 설정한다고 되어있습니다. 따라서 return UDR;의 경우 함수 종료 시점에서 데이터를 읽어 불러왔으므로, Clear(논리0) 되었기 때문에 RXC가 0이 되는것이 맞다고 할 수 있습니다.

    뭔가 설명이 어렵게 되었네요, 간단히 하면 읽지 않은 경우 1로 설정되며, 읽었을 경우에는 0으로 되는 것이 맞습니다. 그럼 프로젝트 하시는데 도움 되시길 바랍니다.^^

  15. Blog Icon
    siwlsdl

    avr studio에는 원래 시리얼통신하는 창이 없어서 하이퍼터미널을 설치해주는거에요??
    코드비전에는 창누르면 바로 확인할 수 있어서 편했는데 처음으로 avr studio깔아서 써보는데
    시리얼통신못찾아서 ㅠㅠ헤매고있어요 ㅠㅠ

  16. Blog Icon
    emma

    고딩이신데 존경스럽네요.

  17. Blog Icon
    choijunho

    코드비젼에서 소스를 넣어서 돌리려고하는데 define 에러가 뜨네요 ㅠㅠ

  18. 현재 atmega에서 그냥 1초마다 문자 하나를 출력하게끔 코드를 작성하고 작동시켰으나 pc 측에서 받아들이는 결과를 보면 이상한 문자가 1초마다 잡힙니다.
    avrfreak을 돌아다니면서 의심가는 문제원인으로는 atmega 칩 내부 오실레이터가 8Mhz가아닌 틀어진 주파수로 작동하여서 uart 통신 오류율을 넘어가서 작동이 안되는 것일 수도 있다고 하더군요.
    혹시 내부 오실레이터를 사용하여서 문제에 봉착하신 적은 없으신가요?

    현재 저의 상황을 적은 제 블로그 글입니다: https://kwagjj.wordpress.com/2015/01/30/uart-avr-pc-test/

  19. 혹시 RFID 관련 자료도 있나요 ?
    실험중인데 여러가지 막히는게 있어서 여쭤봅니다.

티스토리 툴바