시스템을 구현하다 보면 통신을 해야 할 일이 자주 발생합니다.
AVR의 기본적인 통신방법인 USART를 사용해 컴퓨터에 데이터를 전송해 보는 방법을 정리해보았습니다.
ATmega128을 사용하였고 좀 더 자세한 내용이 필요하신 분은 ... (더보기)를 클릭하시면 됩니다.
내용 대부분은 윤덕용 박사님의 AVR ATmega128 정복에서 발췌하였으며, 데이터시트를 참고하였습니다.
USART(Universal Synchronous and Asynchronous Receiver and Transmitter)
USART의 특징
1. ATmega128에는 2개의 USART 직렬통신 포트 USART0 및 USART1이 있다.
이것들은 동기 및 비동기 전송 모드에서 모두 전이중 통신이 가능하고, 멀티 프로세서 통신 모드로 동작하는 것도 가능하며,
높은 정밀도의 보레이트 발생기(Baud Rate Generator)를 내장하고 있다.
2.동기식 전송 모드에서 마스터(master)로 동작하는 경우 전송속도를 결정하는데 내부 클록을 사용하지만,
슬레이브(slave)로 동작할 때는 XCKn 단자로 입력되는 외부 클록 신호에 의하여 동작한다.
비동기식 전송 모드에서는 항상 내부의 시스템 클록에의하여 보레이트가 결정된다.
3.전송 데이터는 5~9비트로 설정하고 스톱 비트는 1~2비트로 설정할 수 있으며,
전송중에 패리티 비트를 사용하지 않을 수도 있고
짝수 또는 홀수 패리티(enven or odd parity)를 임의로 설정하여 사용할 수도 있다.
수신 동작에서는 패리티 에러(parity error), 오버런 에러(overrun error) 및
프레임 에러(frame error)를 검출하는 기능을 가지고 있다.
4.USART 직렬통신 포트에서는 송신 완료(TX Complete), 송신 데이터 레지스터 준비완료(TX Data Register Empty),
수신 완료(RX Complete) 등 3가지의 인터럽트를 사용할 수 있다.
레지스터 사용
1. USARTn 입출력 데이터 레지스터(UDRn)
UDRn(USART0 or 1 I/O Data Register) 레지스터는 USARTn 포트의 송수신 데이터 버퍼의 기능을 수행한다.
각 포트의 송신 및 수신 버퍼는 동일한 번지에 위치하지만 내부적으로는 서로 다른 별개의 레지스터로서,
송신할 데이터를 UDRn에 라이트하면 이는 송신 데이터 버퍼 TXBn에 저장되고,
수신된 데이터를 UDRn으로 읽으면 이는 수신 데이터 버터 RXBn에 수신되어 있는 값이 읽혀진다.
전송 데이터 문자를 5~7 비트로 설정하면 송신의 경우에는 사용하지 않는 상위비트들이 무시되고,
수신의 경우에는 이 상위 비트들이 수신부에서 0으로 처리된다.
송신 버퍼는 UCSRnA 레지스터의 UDREn 플랙 비트가 1로 되어 있는 경우에만 라이트할 수 있으며,
UDREn 플랙 비트가 0으로 되어 있는 경우에는 만약 UDRn에 송신 할 데이터를 라이트하더라도 이는 송신부가 무시한다.
정상적으로 UDRn 레지스터의 송신 버퍼에 라이트된 데이터는 송신 시프트 레지스터가 비어있을 경우
자동적으로 이 시프트 레지스터로 옮겨지고, 이것은 TxDn 핀을 통하여 직렬로 송신된다.
수신 버퍼는 2단계의 FIFO로 된 이중 버퍼링 구조를 가지며, 따라서 이는 읽을 때 마다 상태가 변화되므로
이 수신 버퍼에 대하여는 SBI/CBI 명령이나 SBIS/SBIC 명령을 사용하지 않는 것이 좋다.
송신하려는 데이터와 수신한 데이터가 저장되는 레지스터입니다.
송신할때는 레지스터에 데이터를 저장하고,
수신할때는 레지스터에 저장된 값을 읽습니다.
EX)
UDRn=data; // data의 값을 송신
data=UDRn; // UDRn로 수신된 값을 data에 저장
2. USARTn 제어 및 상태 레지스터 A(UCSRnA)
UCSRnA(USART0 or 1 Control and Status Register A) 레지스터는
USARTn 포트의 송수신 동작을 제어하거나 송수신 상태를 저장하는 기능을 수행한다.
비트7의 RXCn(USARTn Receive Complete)은 수신 버퍼에 읽혀지지 않은 수신 문자가 들어 있으면 1로 셋트되고,
CPU가 이를 읽어서 수신 버퍼가 비어있는 상태라면 0으로 클리어되는 상태 플랙이다.
이 비트가 1로 되면 수신완료 인터럽트(Receive Complete Interrupt)를 요청하는데,
이 비트는 수신 버퍼를 읽으면 0으로 클리어된다.
비트6의 TXCn(USARTn Transmit Complete)은 송신 시프트 레지스터에 있는 송신 데이터가 모두 송신되고
UDRn의 송신 버퍼에 아직 새로운 송신 데이터가 라이트되지 않은 상태이면 1로 셋트되는 상태 플랙이다.
이 비트가 1로 되면 송신완료 인터럽트(Transmit Complete Interrupt)를 요청하는데,
이 인터럽트의 처리가 시작되면 이 비트 는 자동으로 0으로 클리어되며,
이 비트를 강제로 클리어하려면 이 비트에 1을 라이트 해야 한다.
비트5의 UDREn(USARTn Data Register Empty)은 UDRn의 송신 버퍼가 비어있어서
새로운 송신 데이터를 받을 준비가 되어 있으면 1로 셋트되는 상태 플랙이다.
이 비트가 1로 되면 송신 데이터 레지스터 준비완료 인터럽트(Data Register Empty Interrupt)를 요청하며,
송신 버퍼에 새로운 데이터를 라이트하면 이 비트는 0으로 클리어된다. 시스템 리셋 후에 디폴트로 이 비트는 1이다.
비트4의 FEn(USARTn Frame Error)은 UDRn의 수신 버퍼에 현재 저장되어 있는 데이터를 수신하는 동안에
프레임 에러가 발생하였음을 나타내는 상태 플랙이다.
프레임 에러는 수신 문자의 첫번째 스톱 비트가 0으로 검출되면 발생한다. 이 플랙은 수신 버퍼 UDRn을 읽을 때까지 유효하며,
UCSRnA 레지스터를 라이트하면 이 비트는 무조 건 0으로 클리어된다.
비트3의 DORn(USARTn Data Overrun Error)은 UDRn의 수신 동작에서
오버런 에러가 발생하였음을 나타내는 상태 플랙이다.
오버런 에러는 UDRn의 수신 버퍼에 현재 읽지 않은 수신 문자가 들어 있는 상태에서
수신 시프트 레지스터에 새로운 데이터 문자가 수신 완료되고
다시 그 다음 수신 데이터인 3번째 문자의 스타트 비트가 검출되면 발생한다.
이 플랙은 수신 버퍼 UDRn을 읽을 때까지 유효하며, UCSRnA 레지스터를 라이트하면 이 비트는 무조건 0으로 클리어된다.
비트2의 UPEn(USARTn Parity Error)은 UDRn의 수신 버퍼에 현재 저장되어 있는 데이터를 수신하는 동안에
패리티 에러가 발생하였음을 나타내는 상태 플랙이다. 패리티 에러는 UCSRnC 레지스터에서 UPMn1 = 1로 하여
패리티 비트를 사용하도록 설정한 경우에만 발생할 수 있다.
이 플랙은 수신 버퍼 UDRn을 읽을 때까지 유효하며, UCSRnA 레지스터를 라이트하면 이 비트는 무조건 0으로 클리어된다.
비트1의 U2Xn(Double the USARTn Transmission Speed)은 비동기 모드에서만 유효한 것으로서
USARTn 포트의 클록 분주비를 16에서 8로 절반만큼 낮추어 전송속도 를 2배 높이는 기능을 수행한다.
비트0의 MPCMn(USARTn Multi-Processor Communication Mode)은 USARTn을 멀티 프로세서 통신 모드로 설정한다.
멀티 프로세서 통신 모드에서는 어드레스 정보 를 포함하지 않는 모든 수신 데이터는 수신부에 의하여 무시된다.
송신부는 이 비트에 의하여 영향을 받지 않는다.
TXCn과 UDREn의 차이는 비어있는 레지스터에 있있습니다. 송신 하려는 데이터가
DATA -> UDR -> TRANSMIT SHIFT REGISTER -> TxD라는 과정으로 송신된다고 생각하면,
TXCn의 경우 송신 시프트 레지스터에 있는 데이터가 전부 비워졌을 때 set 되는 flag이고,
UDREn의 경우 입출력 데이터 레지스터에 있는 데이터가 전부 비워졌을 때 set 되는 flag입니다.
즉, TXCn의 경우 송신 시프트 레지스터의 데이터를 전부 송신단으로 내보네 '송신 완료'되었다는 사실을 알려주는 것이고,
UDREn의 경우 입출력 데이터 레지스터에 있는 데이터를 전부 송신 시프트 레지스터로 내보네
새로 데이터를 받을 '준비 완료'되었다는 사실을 알려주는 것입니다.
위의 Figure 79.를 참고하시면 좀 더 잘 이해가 될 것입니다.
송수신 동작을 제어하거나 송수신 상태를 저장하는 레지스터입니다.
RXCn값을 통해 데이터가 수신된 사실을 확인하고,
UDREn값을 통해 UDRn이 송신 데이터를 받을 준비가 되었는지 확인합니다.
EX)
while(!(UCSRnA&0x80)); // 수신완료될때까지 대기(=수신 버퍼가 채워질때까지 대기)
data=UDRn; // data에 수신 버퍼 값을 저장
while(!(UCSRnA&0x20)); // 송신 데이터를 받을 준비가 될때까지 대기(=송신 버퍼가 피워질때까지 대기)
UDRn=data; // 송신 버퍼에 data 값을 저장(=data 값을 송신)
3. USARTn 제어 및 상태 레지스터 B(UCSRnB)
UCSRnB(USART0 or 1 Control and Status Register B) 레지스터는 USARTn 포트의 송수신 동작을 제어하거나,
전송 데이터를 9비트로 설정한 경우에 전송 데이터의 9번째 비트값을 저장하는 기능을 수행한다.
비트7의 RXCIEn(USARTn RX Complete Interrupt Enable)은 수신완료 인터럽트를 개별적으로 허용하는 비트이다.
이를 1로 설정하고 SREG 레지스터의 I비트가 1이라면 1문자가 수신되어 UCSRnA 레지스터의 RXCn 비트가 1로 되는 경우
수신완료 인터럽트가 발생한다.
비트6의 TXClEn(USARTn TX Complete Interrupt Enable)은 송신완료 인터럽트를 개별적으로 허용하는 비트이다.
이를 1로 설정하고 SREG 레지스터의 I비트가 1이라면 송신 시프트 레지스터가 비어
UCSRnA 레지스터의 TXCn 비트가 1로 되는 경우 송신완료 인터럽트가 발생한다.
비트5의 UDRIEn(USARTn Data Register Empty Interrupt Enable)은
송신 데이터 레지스터 준비완료 인터럽트를 개별적으로 허용하는 비트이다.
이를 1로 설정하고 SREG 레지스터의 I비트가 1이라면 송신 버퍼가 비어 UCSRnA 레지스터의 UDREn 비트가 1로 되는 경우
송신 데이터 레지스터 준비완료 인터럽트가 발생한다.
비트4의 RXENn(USARTn Receiver Enable)은 USARTn 포트의 수신부가 동작하도록 허용한다.
이는 RxDn 핀이 병렬 I/O 포트가 아니라 직렬 데이터 수신 단자로 동작 하도록 설정하며,
에러 플랙 비트 FEn, DORn, UPEn의 동작을 유효하도록 한다.
비트3의 TXENn(USARTn Transmitter Enable)은 USARTn 포트의 송신부가 동작 하도록 허용한다.
이는 TxDn 핀이 병렬 I/O 포트가 아니라 직렬 데이터 송신 단자로 동작하도록 설정하며,
이 비트를 0으로 설정하더라도 이는 송신 시프트 레지스터에 데이터가 남아있을 경우에는
이것이 전송 완료될 때까지 유효하지 않다.
비트2의 UCSZn2(USARTn Character Size)는 UCSRnC 레지스터의 UCSZn1~0 비트와 함께
전송 문자의 데이터 비트수를 설정하는데 사용된다.
비트1의 RXB8n(USARTn Receive Data Bit 8)은 수신 문자가 9비트로 설정된 경우
수신된 문자의 9번째 비트(MSB)를 저장한다. 이는 반드시 UDRn 레지스터보다 먼저 읽혀야 한다.
비트0의 TXB8n(USARTn Transmit Data Bit 8)은 전송 문자가 9비트로 설정된 경우
송신할 문자의 9번째 비트(MSB)를 저장한다. 이는 반드시 UDRn 레지스터보다 먼저 라이트되어야 한다.
포트의 송수신 동작을 제어하는 레지스터입니다.
송수신 관련 인터럽트를 허용하거나, 송수신부가 동작하도록 허용합니다.
EX)
UCSRnB=(1<<RXCIEn) | (1<<RXENn); // 수신완료 인터럽트 허용, 수신부 동작 허용
4. USARTn 제어 및 상태 레지스터 C(UCSRnC)
UCSRnC(USART0 or 1 Control and Status Register C) 레지스터는
USARTn 포트의 송수신 동작을 제어하는 기능을 수행한다.
비트6의 UMSELn(USARTn Mode Select)은 1이면 USARTn 포트를 동기 전송 모드로 설정하고,
0이면 비동기 전송 모드로 설정한다.
비트5~4의 UPMn1~0(USARTn Parity Mode)은 <표 2.3.1〉과 같이 USARTn 포트에서 패리티 모드를 설정한다.
패리티 사용을 설정하면 송신부에서는 자동으로 패리티 비트를 계산하여 전송하며,
수신부에서는 수신된 패리티 비트와 계산한 패리티 비트를 비교하여 일치하지 않으면
UCSRnA 레지스터에서 UPEn=1로 세트한다.
비트3의 USBSn(USARTn Stop Bit Select)은 0이면 USARTn 포트에서 데이터 포맷을 구성하는 스톱 비트를 1개로 설정하고,
1이면 스톱 비트를 2개로 설정한다.
비트2~1의 UCSZn1~0(USARTn Character Size)은 UCSRnB 레지스터의 UCSZn2비트와 함께 USARTn 포트에서
<표 2.3.2>와 같이 전송 문자의 데이터 비트수를 설정한다.
비트0의 UCPOLn(USARTn Clock Polarity)은 동기 전송 모드에서만 유효한 것으로,
이를 0으로 설정하면 TxDn 단자의 송신 데이터는 XCKn 클록의 상승 에지에서 새로운 값이 출력되고,
RxDn 단자의 수신 데이터는 XCKn 클록의 하강 에지에서 검출된다.
그러나, 이를 1로 설정하면 반대로 송신 데이터는 XCKn 클록의 하강 에지에서 새로운 값이 출력되고,
수신 데이터는 XCKn 클록의 상승 에지에서 검출된다.
포트의 송수신 동작을 제어하는 레지스터입니다.
전송 문자의 데이터 비트수를 설정할 수 있습니다.
EX)
UCSRnC=(0<<UCSZn2) | (1<<UCSZn1) | (0<<UCSZn0); // 전송 데이터 길이 8-bit
5. USARTn 보레이트 레지스터(UBRRnH/L)
UBRRnH/L(USART0 or 1 Baud Rate Register) 레지스터는 16비트 중에서 12비트만 유효한 것으로서,
각각 USART0 또는 USART1 포트의 송수신 속도를 설정하는 기능을 수행한다.
즉, 이 레지스터 값은 클록의 분주비로 작용하여 직렬포트의 전송속도인 보레이트를 결정한다.
16비트 레지스터를 라이트하는 경우에는 항상 상위 바이트인 UBRRnH를 먼저 라이트하고
하위 바이트인 UBRRnL을 나중에 라이트해야 한다.
이렇게 설정된 UBBRn 레지스터에 대하여 전송 보레이트를 계산하는 공식이나,
반대로 원하는 보레이트를 설정하기 위한 UBRRn 레지스터의 값을 구하는 공식을 동작모드별로 요약하면 <표 2.3.3〉과 같다.
여기서 전송속도를 나타내는 BAUD의 단위는 bps(bits per second)이며,
UBRRn 은 12비트만을 사용하므로 0~4095 범위의 값을 가질 수 있다.
이 공식에 따라 ATmega128에 16MHz의 시스템 클륵을 사용하는 경우
각 보레이트별로 이에 필요한 UBRRn 레지스터의 값을 계산해보면 <표 2.3.4〉와 같다.
이 표에서는 UBRRn 레지스터의 값을 이와 같이 설정하는 경우
표준 보레이트와 실제로 동작 하는 전송 속도 사이의 오차를 계산하여 제시하였는데,
나중에 설명하는 바와 같이 230.4kbps인 경우를 제외한 모든 전송 속도에서는
거의 동작에 영향을 주지 않는 무시할 수 있는 오차가 된다.
포트의 송수신 속도를 설정하는 레지스터입니다.
EX)
UBRRnH=0; // 16비트 레지스터를 라이트하는 경우에는 항상 상위 바이트를 먼저 라이트합니다.
UBRRnL=51; // 보레이트를 19,200으로 설정하였습니다.
위의 내용을 바탕으로 '1'을 받으면 ON을 내보내고
'0'을 받으면 OFF를 내보내는 프로그램을 짜보겠습니다.
ASCII table을 참고하여 USART_Transmit을 할 수도 있습니다.
이제 컴퓨터와 통신을 하기위해 시리얼 프로그램을 사용합니다.
http://withrobot.com/data/?uid=12&mod=document&pageid=1
위 링크에서 아래와 같은 파일을 받을 수 있습니다.
comportmaster.zip
프로그램을 다운받아 ComPortMaster를 실행하면
이러한 화면이 나오는데 Baudratem, Data bits, Stop bits, Parity는 설정해준대로 맞춰주면 됩니다.
Device의 경우 연결한 포트마다 다르기때문에 장치관리자를 들어가 확인해 주어야 합니다.
저는 포트가 COM4에 물려있어서 저렇게 적었습니다.
Baudrate는 19200으로 설정하였기 때문에 19200을 선택하고,
0과 1만 보내면 되기 때문에 Sand에 0과 1을 입력했습니다.
이상으로 ATmega128을 이용한 USART통신이었습니다.