[2024.06.07.금] 인천인력개발원 하만 세미콘 아카데미
UART(Universal Asynchronous Reciever/Transmittter)
1. 시리얼 통신
- 마이크로컨트롤러에서의 데이터 전송: 비트 단위의 데이터를 핀 단위로 전송
- 데이터 전송 방법
- 병렬 전송: 8개의 핀으로 한 번에 1바이트 데이터 전송
- 연결이 복잡해짐
- 핀 수가 제한적인 마이크로컨트롤러에서는 연결이 불가능할 수 있음 - 직렬 전송: 1개의 핀으로 8번에 나누어 1바이트 데이터 전송
- UART 통신은 시리얼/직렬 통신의 종류
- 병렬 전송: 8개의 핀으로 한 번에 1바이트 데이터 전송
2. 프로토콜
- 컴퓨터(장치) 간의 데이터 통신에서 원활한 송수신을 위해 약속된 신호 송신의 순서, 속도, 데이터 표현법 등의 규약
- UART 통신은 비동기(Asynchronous) 통신
- 별도의 클록을 사용하지 않으므로 약속된 속도로 송수신 수행
- 통신 단위로 보율(baud rate, =스위칭 속도) 사용
3. ATMega128에서의 UART 통신
- 송신(RX, Receive Data)과 수신(TX, Transmit Data)의 2개 핀 사용
- 하드웨어로 지원되는 2개의 UART 통신 포트 포함
- UART0: PE0, PE1 핀
- UART1: PD2, PD3 핀
4. UCSRnA 레지스터
- U2Xn 비트: 2배속 설정
- RXCn(Receive Complete) 비트: 수신 완료
- UDREn(Data Register Empty) 비트: 송신 완료
- UCSRnA 레지스터 비트
- 7비트 - RXCn
- 수신 버퍼(UDRn)에 읽지 않은 문자가 있을 때 1이 되고 버퍼가 비어있으면 0
- UCSRnB 레지스터의 RXCIEn 비트와 함께 사용되어 수신 완료 인터럽트 발생 가능 - 6비트 - TXCn(Transmit Complete)
- 전송 시프트 레지스터에서 데이터를 송신하고 송신 버퍼(UDRn)도 비어있으면 1이 됨
- UCSRnB 레지스터의 TXCIEn 비트와 함께 사용되어 송신 완료 인터럽트 발생 가능 - 5비트 - UDREn(USART Data Register Empty)
- 송신 버퍼(UDRn)가 비어 데이터를 받을 준비가 되면 1이 됨
- UCSRnB 레지스터의 UDRIE0비트와 함께 사용되어 송신 데이터 레지스터 준비 완료 인터럽트 발생 가능 - 4비트 - FEn(Frame Error)
- 수신 데이터가 없는 경우 수신값은 HIGH 상태, 데이터 프레임 수신이 시작되는 시점에서 LOW 상태로 변경
- 데이터 프레임 수신 종료 후 정비 비트를 수신할 때 수신값이 다시 HIGH 상태
- 마지막에 프레임의 끝을 나타내는 신호를 수신하지 못하여 프레임 수신에 오류 발생 시 1의 값을 가짐 - 3비트 - DDRn(Data Overrun Error)
- 수신 버퍼가 가득 찬 상태에서 수신 시프트 레지스터에 새 문자가 수신되고, 그 다음 문자의 시작 비트가 검출되는 Overrun 상황 발생 시 1의 값 - 2비트 - UPEn(USART Parity Error)
- 수신 버퍼에 지정된 문자 데이터에 패리티 오류가 발생한 경우 1의 값
- 패리티 비트 사용 설정된 경우에만 사용 가능 - 1비트 - UZXn(Double the USART Transmission Speed)
- 비동기 전송 모드에서만 사용
- 2배속 모드면 1, 1배속 모드면 0의 값 - 0비트 - MPCMn(Multi Processor Communication Mode)
- 1개의 마스터 프로세스가 여러 개의 슬레이브 프로세서에게 특정 어드레스를 전송하여 1개의 슬레이브만을 지정, 데이터 전송하여 멀티프로세서 통신 모드 시 1의 값
- 7비트 - RXCn
5. UCSRnB 레지스터
- 송수신 활성화 레지스터: 디폴트는 금지 상태
- UCSRnB 레지스터 비트
- 7비트 - RXCIEn(RX Complete Interrupt Enable): 수신 완료 인터럽트 발생 허용
- 6비트 - TXCIEn(TX Complete Interrupt Enable): 송신 완료 인터럽트 발생 허용
- 5비트 - UDRIEn(USART Data Register Empty Interrupt Enable): 송신 데이터 레지스터 준비 완료 인터럽트 발생 허용
- 4비트 - RXENn(RX Enable): UART 수신기의 수신 기능 활성화
- 3비트 - TXENn(TX Enable): UART 송신기의 송신 기능 활성화
- 2비트 - UCSZn2(USART Character Size): UCSRnC 레지스터와 함게 전송 데이터의 비트 수 결정
- 1비트 - RXB8n(Receive Data Bit 8): 데이터가 9비트인 경우 수신 데이터의 아홉 번째 비트(8번 비트) 저장을 위해 사용. 반드시 UDRn 레지스터보다 먼저 읽어야 함
- 0비트 - TXB8n(Transmit Data Bit 8): 데이터가 9비트인 경우 송신 데이터의 아홉 번째 비트(8번 비트) 저장을 위해 사용. 반드시 UDRn 레지스터보다 먼저 써야 함
6. UCSRnC 레지스터
- 통신 설정 관련 레지스터
- UCSRnC 레지스터 비트
- 6비트 - UMSELn: 0이면 비동기 USART(=UART), 1이면 동기 USART
- 5비트, 4비트 - UPMn1, UPMn0
- 3비트 - USBSn: 0이면 1비트, 1이면 2비트
- 2비트, 1비트 - UCSZn1, UCSZn0
- 0비트 - UCPOLn
실습 1. UART
1. Solution 우클릭 - Add - New Project 생성 - "test06-UART"
2. Board - ATMega128 선택
3. 위에서 생성한 프로젝트 우클릭 - Set As A StartUp Project
4. 코드 작성
더보기
/*
* test06-UART.c
*
* Created: 2024-06-07 오전 10:36:22
* Author : user
*/
#include <avr/io.h>
#include <avr/delay.h>
void initUART0(){//BaudRate 설정 9600N81
UBRR0H = 0; //상위 UBRRn 비트는 0
UBRR0L = 207; //하위 UBRRn 비트를 207로 설정 -> Baud Rate : 9600
UCSR0A |= (1 << 1); //0000 0010b 2배속 설정
UCSR0B |= (1<<RXEN0) | (1<<TXEN0); //RX, TX Enable
UCSR0C |= 0x06; //Data Bit : Default 8 (x11x) 0000 0100b N81
//Stop Bit : 1 0xxx
}
void send(char c){//설정된 포트를 이용하여 1Char을 send
// while ( 1 ){
// if(UCSR0A & ( 1<<UDRE0 ) == 1) break; //wait until data empty bit = 1
// };
while(!(UCSR0A & (1<<UDRE0))); //wait until data empty bit = 1
UDR0 = c; //send
}
int main(void)
{
initUART0(); //Initialize
char a = '0';
while (1) {
send(a++); //보낼때마다 a를 증가시켜 0부터 증가하며 데이터 전송
_delay_ms(1000); //1000milli(=1) second delay
if(a >= '9') a = '0'; //a가 0~9를 반복
}
}
5. TeraTerm을 통해 UART 통신 확인
- 프로그래밍 시 ISP/UART 스위치를 ISP로 설정 후 프로그래밍
- 프로그래밍 완료 후 TeraTerm 확인 시 스위치를 UART로 바꿔 통신 실행
5. 문장을 송신하기 위한 코드 작성
더보기
/*
* test06-UART.c
*
* Created: 2024-06-07 오전 10:36:22
* Author : user
*/
#include <avr/io.h>
#include <avr/delay.h>
void initUART0(){//BaudRate 설정 9600N81
UBRR0H = 0; //상위 UBRRn 비트는 0
UBRR0L = 207; //하위 UBRRn 비트를 207로 설정 -> Baud Rate : 9600
UCSR0A |= (1 << 1); //0000 0010b 2배속 설정
UCSR0B |= (1<<RXEN0) | (1<<TXEN0); //RX, TX Enable
UCSR0C |= 0x06; //Data Bit : Default 8 (x11x) 0000 0100b N81
//Stop Bit : 1 0xxx
}
void uPutc(char c){//설정된 포트를 이용하여 1Char을 send
// while ( 1 ){
// if(UCSR0A & ( 1<<UDRE0 ) == 1) break; //wait until data empty bit = 1
// };
while(!(UCSR0A & (1<<UDRE0))); //wait until data empty bit = 1
UDR0 = c; //send
}
void uPuts(char *str){//설정된 포트를 이용하여 1string을 send
while(*str) uPutc(*str++); //str길이만큼 str의 한글자씩 출력\
// while(1){
// if(*str == 0) break;
// uPutc(*str);
// str++;
// }
}
int main(void)
{
initUART0(); //Initialize
char a = '0';
uPuts("안녕하세요\r\n");
while (1) {
uPutc(a++); //보낼때마다 a를 증가시켜 0부터 증가하며 데이터 전송
_delay_ms(1000); //1000milli(=1) second delay
if(a >= '9') a = '0'; //a가 0~9를 반복
}
}
6. 문자열을 Buffer 공간에 넣어서 출력: buf공간 선언 및 main 함수 변경
더보기
}
unsigned char buf[1024];
void bPrint(){ //고정된 메모리 공간 buffer 내의 문자열 촐력
uPuts(buf);
}
int main(void)
{
initUART0(); //Initialize
char a = '0';
int i = 0;
uPuts("안녕하세요\r\n");
while (1) {
//uPutc(a++); //보낼때마다 a를 증가시켜 0부터 증가하며 데이터 전송
sprintf(buf, "ATmega128 터미널 출력 테스트... #%d\r\n", i++); bPrint();//buf공간 내의 값을 i를 증가시키며 하나식 출력
_delay_ms(1000); //1000milli(=1) second delay
//if(a >= '9') a = '0'; //a가 0~9를 반복
}
}
7. TeraTerm 확인
GitHub에 로컬 디렉토리 업로드
1. cmd 실행
2. git이 설치된 폴더로 이동(IncheonHarman2024)
3. git commit -m 1입력
4. git push 입력
실습 2. UART 이용한 가변저항 출력
1. 저번 시간 실습의 가변저항 출력 코드와 융합하여 코드 작성
더보기
/*
* ADC.c
*
* Created: 2024-05-31 오후 4:33:58
* Author : user
*/
#include <avr/io.h>
#include "myHeader.h"
#include <avr/delay.h>
#include <avr/interrupt.h>
int cint = 0; tcnt = 0;
void initUART0(){//BaudRate 설정 9600N81
UBRR0H = 0; //상위 UBRRn 비트는 0
UBRR0L = 207; //하위 UBRRn 비트를 207로 설정 -> Baud Rate : 9600
UCSR0A |= (1 << 1); //0000 0010b 2배속 설정
UCSR0B |= (1<<RXEN0) | (1<<TXEN0); //RX, TX Enable
UCSR0C |= 0x06; //Data Bit : Default 8 (x11x) 0000 0100b N81
//Stop Bit : 1 0xxx
}
void uPutc(char c){//설정된 포트를 이용하여 1Char을 send
// while ( 1 ){
// if(UCSR0A & ( 1<<UDRE0 ) == 1) break; //wait until data empty bit = 1
// };
while(!(UCSR0A & (1<<UDRE0))); //wait until data empty bit = 1
UDR0 = c; //send
}
void uPuts(char *str){//설정된 포트를 이용하여 1string을 send
while(*str) uPutc(*str++); //str길이만큼 str의 한글자씩 출력\
// while(1){
// if(*str == 0) break;
// uPutc(*str);
// str++;
// }
}
unsigned char buf[1024];
void bPrint(){ //고정된 메모리 공간 buffer 내의 문자열 촐력
uPuts(buf);
}
void initADC(unsigned char ch){
ADMUX |= (1 << REFS0); //AVCC를 기준 전압으로 선택하는 코드. REFSn이 기준 전압 설정. <<는 shift 의미
ADCSRA |= 0x07; //분주비 설정(하위 3비트)
ADCSRA |= 1 << ADEN; //ADC 활성화
ADCSRA |= 1 << ADFR; //Free-Running mode 설정
ADMUX = (ADMUX & 0xE0) | ch;
ADCSRA |= 1 << ADSC;
}
int main(void)
{
initUART0();
initADC(0); //1: ch number
int i = 0;
while (1)
{
while(!(ADCSRA & (1<<ADIF))); //ADCStateResistor이 읽을 준비가 되지 않았다면 기다려라
int cnt = ADC;
sprintf(buf, "가변저항 값: %d\r\n", cnt); bPrint();
_delay_ms(1000);
}
}
2. TeraTerm 출력 확인
'하만(Harman) 세미콘 반도체 설계 과정 > 임베디드 시스템을 위한 SW 구조설계' 카테고리의 다른 글
하만(Harman) 세미콘 아카데미 56일차 - SW 구조설계(Git 다운로드, GitHub 설정) (2) | 2024.05.31 |
---|---|
하만(Harman) 세미콘 아카데미 17일차 - SW 구조설계(주방 타이머 설계 이어서) (24) | 2024.03.29 |
하만(Harman) 세미콘 아카데미 16일차 - SW 구조설계(8비트 타이머/카운터, 16비트 타이머/카운터, 주방 타이머 설계 실습) (1) | 2024.03.28 |
하만(Harman) 세미콘 아카데미 15일차 - SW 구조설계(Pullup 저항, ATmega128 인터럽트, 스탑워치 설계) (20) | 2024.03.27 |