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

2013.11.24 19:21




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


한 2회 포스팅 정도 더 보게될 사진입니다. 다른사진을 쓰고 싶어도, USB to UART, 모듈로 구성이 비슷해서요.^


사용된 회로도를 볼까요!




역시 2회정도 다음 포스팅에서 계속해서 나올 회로도 입니다. PC부분은 USB to UART 부분과 PC를 통틀어 의미합니다.


 이거 이번 포스팅은 너무 거저 포스팅 하는것 같지만... 가겠습니다. ㅎ



CodeVisionAVR용 소스코드


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

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

#include <string.h>    // 문자열 관련 헤더파일을 포함합니다.


char rx_char(void)    // UART 수신관련 사용자 함수를 생성합니다.

{

while((UCSRA&0x80) == 0);    // UCSRA 레지스터에서 RXC 수신완료 비트가 1이 되면 다음라인으로

return UDR;    // 수신된 8비트 값 UDR 데이터 반환

}


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

{

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

UDR = tx_data;    // UDR 레지스터에 tx_data값 쓰기

}


void rx_string(char *str)    // UART 문자열 수신관련 사용자 함수를 생성합니다.

{

int i=0;    // 초기값이 0인 정수형 변수 i 생성


while((str[i]=rx_char()) != '\n')    // str[i] 배열에 문자수신을 한 후 해당 문자가 개행문자 '\n' 일 때까지

{

i++;    // 변수 i 값 1 증가

}

str[i] = '\0';    // str[i] 배열에 '\0' 널문자 쓰기

}

void tx_string(char *str)    // UART 문자열 송신관련 사용자 함수를 생성합니다.

{

int i=0;    // 초기값이 0인 정수형 변수 i 생성


while(str[i] != '\0')    // str[i] 배열 값이 '\0' 문자일 때까지

{

tx_char(str[i]);    // 문자 송신 함수를 이용 str[i]배열에 저장된 문자 송신

i++;    // 변수 i 값 1 증가

}

}


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

{

unsigned char k;    // 부호없는 문자형 변수 k 를 생성합니다.

char data[6];    // 문자형 배열 data[6]을 생성합니다.


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

PORTB=0x00;    // B포트 전체 초기값을 논리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)    // 아래구문을 무한 반복합니다.   

{

rx_string(data);    // 문자열 수신 사용자 함수 사용 data변수에 문자열 저장

 

if(!strcmp(data, "on"))    // 문자열 비교 함수 strcmp 사용 data배열값과 문자열 "on"이 같으면

{

PORTB=0xFF;    // B포트 전체에 논리1 (5V) 출력

tx_string("Light On");    // 문자열 송신 사용자 함수 사용 "Light On" 문자열 송신

}

if(!strcmp(data, "off"))    // 문자열 비교 함수 strcmp 사용 data배열값과 문자열 "off"이 같으면

{

PORTB=0x00;    // B포트 전체에 논리0 (0V) 출력

tx_string("Light Off");    // 문자열 송신 사용자 함수 사용 "Light Off" 문자열 송신

}

if(!strcmp(data, "blink"))    // 문자열 비교 함수 strcmp 사용 data배열값과 문자열 "blink"이 같으면

{

for(k=0; k<10; k++)    // 아래 구문을 10회 반복

{

PORTB=0xFF;    // B포트 전체에 논리1 (5V) 출력

delay_ms(200);    // 위 상태를 약 0.2초간 유지

PORTB=0x00;    // B포트 전체에 논리0 (0V) 출력

delay_ms(200);    // 위 상태를 약 0.2초간 유지

}

tx_string("Blink OK");    // 문자열 송신 사용자 함수 사용 "Blink OK" 문자열 송신

}

}

}



AVR Studio 4용 소스코드


#include <avr/io.h>    

#define F_CPU 8000000UL    

#include <util/delay.h>   

#include <string.h>


char rx_char(void)    

{

while((UCSRA&0x80) == 0);    

return UDR;  

}


void tx_char(char tx_data)    

{

while((UCSRA&0x20) == 0);    

UDR = tx_data;

}


void rx_string(char *str)

{

int i=0;


while((str[i]=rx_char()) != '\n')

{

i++;

}

str[i] = '\0';

}

void tx_string(char *str)

{

int i=0;


while(str[i] != '\0')

{

tx_char(str[i]);

i++;

}

}



int main(void)

{

unsigned char k;

char data[6];


DDRB=0xFF;    

PORTB=0x00;


UCSRA=0x00;  

UCSRB=0x18;  

UCSRC=0x06;  

UBRRH=0x00; 

UBRRL=0xCF; 


while(1)   

{

rx_string(data);

 

if(!strcmp(data, "on"))

{

PORTB=0xFF;

tx_string("Light On");

}

if(!strcmp(data, "off"))

{

PORTB=0x00;

tx_string("Light Off");

}

if(!strcmp(data, "blink"))

{

for(k=0; k<10; k++)

{

PORTB=0xFF;

_delay_ms(200);

PORTB=0x00;

_delay_ms(200);

}

tx_string("Blink OK");

}

}

return 0;

}




알고리즘


먼저 하이퍼터미널에 대한 사용방법은 이전 포스팅 UART 문자 제어 다음 링크에서 확인하실수 있습니다. 

 AVR UART 문자비교 LED 제어 포스팅


해당 코드의 알고리즘은 기존에 구성한 문자 송수신 함수를 응용해서 문자열을 처리하는데요, 문자열 송신 함수의 경우 "Hello"라는 문자열을 송신하게 되면 입력한 문자열은


str[0]

str[1]

str[2]

str[3]

str[4]

str[5]

H

e

l

l

o

\0


다음 표 처럼 각각 한 문자씩 송신을 하게 됩니다. 그러면 송신함수에서는 기존 문자 송신 함수로 한 문자씩 보내되 문자열의 경우 끝에 문자열 종료를 알리는 \0 (Null문자)가 추가로 쓰여지게 되는데 이값이 들어오면 보내는 것을 종료하면 됩니다.


문자열 수신의 경우에는 PC측에서 문자열을 입력하고 Enter를 누르는 입력을 누름으로서 수신되는 개행문자(\n)이 있어야 합니다. 만약 Hello를 누르고 Enter 입력을 했다면.


str[0]

str[1]

str[2]

str[3]

str[4]

str[5]

H

e

l

l

o

\n


처음에는 다음과 같이 입력되게 됩니다. 그런데 문자열에서는 문자열 끝에 문자열의 끝을 알리는 \0 (Null문자)값이 들어가야 하는데 끝 라인에 Enter (개행문자 \n)가 들어가 있고 배열 참조 변수 i 는 5이므로 str[5]에 \0 널 문자를 덮어씌워 줍니다.



동작영상




AVR 연습 포스팅 또하나 끝~~ 다음에는 인터럽트 방식 UART 포스팅으로 찾아 오겠습니다.^



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

  1. Blog Icon
    이동기

    이거 같게 했는데 왜 안될까요...........ㅠㅠ

  2. 안녕하세요.
    Attiny2313을 사용한 하드웨어가 동일하거나, 다른 시리즈의 AVR로 하드웨어 구성에 이상이 없다면 하이퍼 터미널에서 보내는쪽의 LF(Line Feed)를 붙여 보냄을 꺼보고 문자열을 입력하고 Enter를 눌러보시거나, 켜보고 Enter를 한번 눌러보시기 바랍니다.

    그래도 이상이 있다면 자세한 피드백 주시면 감사하겠습니다.^^

  3. Blog Icon
    이동기

    아 너무 뜬금없게 안된다고했군요..하하하
    저는 지금 mega128 사용하고 있는데요 rx_char, tx_char 는 책에서 본 예제랑 거의 같아서 일단 레지스터 조건 건게 같아가지고 그대로 사용했습니다. tx, rx_char 부분은 이해가 가는데 string 부분에서 \n \0 이해가 가지않습니다.... rx_char, tx_char 만 이용해도 문자열이 UART상으로 옮겨지는건 문제가 되지 않는것 같은데 이걸 조건을 걸려고하니까...머리가 아프네요 ㅠㅠ 그런데 UART통신하는 프로그램은 J1C 5.1이라고 하네요 AVR STUDIO 6.1 사용중이구요~

    아 그리고 strcmp 라는 함수는 어떤역할인지 찾아봤는데 잘 이해가 안가더라구요 조금 쉽게 설명해주실수있을가요...

  4. Blog Icon
    이동기

    해결되었습니다~ 저는 UART프로그램상 전송할때 엔터를 치지않아 \n이 배열에 들어가지 않아 _라고 따로쳐서 대체했어요~ 그런데 while((str[i]=rx_char())!='\n') 이 함수가 str[i]에 rx_char()값을 넣었을때 '\n'이 아니면 와일문을 돈다 아닌가용? 그렇게 해서 계산해보면 led0\n이 들어갔을때 0까지 들어가서 i가 ++되서 str[4]가 되는데 거기서 '\n' 이므로 와일문에 들어가지않아 str[5]가 되지 않지 않나요? 그래서 전 i--; 이걸뺏거든요~ 제가 생각이 틀린건강... 한번 검토해봐주실수있을가요~

  5. 안녕하세요.^^
    질문주신 /0는 Null문자라고 해서 문자열의 끝을 알리는 문자이구요, /n은 개행문자로 줄 바꾸기 또는 Enter입니다. 그리고 strcmp는 입력받은 문자열이 저장된 포인터(메모리시작주소)와 "on"과 같으면 0을 return하는 함수입니다. 메모리 시작주소란 "on"같은 경우 o가 저장된 메모리의 시작 주소를 말하는 것이랍니다.^^

    입력받는 data란 배열도 포인터로 전환하여, 두 메모리 값이 같으면 0으로 return하는 함수라고 알고 있습니다. 오류가 있을수 있을수도 있으니, 참고만 부탁드립니다.

  6. 갑자기 봐서 조금 헛갈리네요 ㅎㅎ
    먼저 while((str[i]=rx_char()) != '\n') 은 /n이 아니라면 계속 i++하면서 Byte데이터를 저장하는데요, 제가 구성한 코드는 on + Enter를 입력했다면, str의 0번지에 o저장, 1번지에 n 저장 후 Enter가 눌리게 되면 2번지에 /n이 쓰여지게 됩니다. 근데 strcmp에서 비교하는 값인 "on"은 0번지 o 1번지 n 2번지 /0로 메모리에 지정되어있는 문자열이기 때문에 입력받은 코드에서 끝라인을 null로 바꿔 주셔야 합니다.

    그런데 코드 보니까 i--; 를 하지않아도 되는데 한것 같네요. ^^;; 제보 감사드립니다. 그렇게 수정하면 이상없이 동작하는 것이 맞나요? 제가 테스트하던 코드를 올린것 같습니다. Feedback 감사드립니다.

  7. Blog Icon
    이동기

    네 저는 i-- 하기전에는 LED0= (엔터로 데이터입력이 아니라 클릭으로 하는것이라 엔터를 =로 대체하였씁니다.) 하면 LED0라고 나와야하는데 LED라고만 뜨고 0이 사라져서 수정해보았습니다~ 요기 블로그에서 정말 많이 배워가는것 같아요...하는일 잘되시길 바라면서~ 다시한번 감사합니다.

  8. 수정사항 제보 감사드립니다.
    파이팅도 감사드리구요.^^ , 계속해서 좋은 정보 올릴수 있도록 조금씩 부품들 가지고 수도권으로 올라오겠습니다. 그 때 까지 잊지 말아주세요.^^

  9. Blog Icon
    방문객

    * 가 메모리의 시작주소인가요? 아니면 해당 메모리 주소에 있는 '값'을 참조하는건가요?

  10. Blog Icon
    halashow

    서울 생활은 잘 적응하시죠?
    문자열을 lcd에 표현하고 싶습니다. 자료를 메일로 보냅니다.

  11. 메일 보내드렸습니다.^^
    부족하지만 도움이 되셨으면 좋겠습니다.

  12. Blog Icon
    halashow

    감사합니다.
    조금씩 조금씩 앞으로 나가고 있습니다.

  13. 가끔 방문해 주세요.^^

  14. Blog Icon
    이민성

    하이퍼터미널에서 UART 비동기 통신을 할 경우 (9600 보더레이트 , 표준)

    이상한 문자가 나타나는 것은 보통 보더레이트가 안맞아서 그런다고 하는데 보통 atmega128은 16Mhz를 쓰기 때문에

    UBRR0H=0x00;
    UBRR0L=0x67;

    보통 0x67 아니면 103이 되지는 않은가요?

  15. 안녕하세요.
    먼저 일주일 단위로 답변을 달고 있어서 조금 늦게 답글을 달게 되었음에 양해 부탁드립니다. UBRR레지스터 값 설정은 해당 AVR데이터 시트에 보시면 표로 정리 해 두었는데요, 8비트 AVR의 경우 거의 같은 값을 사용합니다. 해당 표는 http://binworld.kr/59 포스팅에서 보실수 있구, 16Mhz에 9600bps일 경우 103이 맞는데요, Atmega128에도 적용되는 사항인지는 정확히는 모르겠지만 U2X라는 전송속도를 증가시키는 비트를 1로 설정하셨다면 UBRR 값이 달라질수 있으니 참고하시기 바랍니다.

    그리고 질문 주신 UBRR0L이 LOW 8비트 이므로 ,16진수로 0x67, 10진수로 103 입력하시는게 맞습니다. 혹여 계속해서 에러가 발생하신다면, 코드비전의 코드제네레이터로 레퍼런스코드를 통해서 동작시켜 보신후에 이상이 없다면, 그것을 수정해서 이용하시는 것도 도움이 되실 것 같습니다.

    그리고 저는 Attiny2313과 8Mhz, 9600bps 설정을 했을 때 에러율이 0.2%이지만, 글자가 깨지거나 하는 이상사항은 발견되지 않았습니다. 그리고 한글은 지원하지 않으니 영문으로 재시도 해보시기 바랍니다.

    큰 도움은 드리지 못해서 죄송합니다. 부족하지만 도움되는 답글이 되었기를 바랍니다.

  16. Blog Icon

    비밀댓글입니다

  17. Blog Icon

    비밀댓글입니다

티스토리 툴바