본문 바로가기
대한상공회의소 스마트팩토리 교육/IoT 디바이스 개발

[IoT 디바이스 개발] AVR(ATmega128A)«수업-8» : 디지털 데이터 출력(DDR 레지스터 / PORT 레지스터 / 비트연산자(논리, 이동))

by 나는영하 2022. 2. 9.

※ 주의사항 

본 블로그는 수업 내용을 바탕으로 제가 이해한 부분을 정리한 블로그입니다.
본 내용을 참고로만 보시고, 틀린 부분이 있다면 지적 부탁드립니다!

감사합니다😁

 

안녕하세요!!

 

여태까지 마이크로컨트롤러에 대해 쉽고 재밌게 접근하기위해 ATmega2560이 탑재된

'Arduino MEGA'를 사용해서 다양한 입출력 소자를 제어하는 프로그래밍을 배웠다면

이제부터는 마이크로컨트롤러에 대해 심층적으로 배우기 위해 ATmega128A를 활용해서 프로그래밍 해보겠습니다. Arduino의 프로그래밍 방법은 교육용에 초점을 두었다면 ATMEL Studio의 AVR 프로그래밍 방법은 조금 더 실무에 가깝다고 생각하면 될 것 같습니다.

 

오늘은 아래와 같은 내용을 확인해보겠습니다.

 

디지털 데이터 출력

DDR 레지스터

PORT 레지스터

비트연산자(논리, 이동)


마이크로컨트롤러(ATmega128A)에 대한 구성과 전용 레지스터 등에 대한 내용,

시리얼 통신(UART)을 하기 위한 코드와 관련 레지스터에 대해서도 간략히 배웠으나 본 블로그에는 정리하지 않았습니다. (내용이 어렵기도하고 조금 더 독학이 필요한 부분이라 생각해서 생략😥 추후에 기회가 된다면 정리해보겠습니다.)  

1. 비트연산자

1-1. 비트 논리 연산자와 비트 이동 연산자

구분 연산자 종류 결과
비트 논리 연산자 a & b 비트 AND a와 b의 비트 단위 AND
a | b 비트 OR a와 b의 비트 단위 OR
a ^ b 비트 XOR a와 b의 비트 단위 XOR
~a 비트 NOT a의 비트 단위 NOT(1의 보수)
비트 이동 연산자 a << n 왼쪽으로 이동 a를 왼쪽으로 n비트 이동하고 오른쪽은 0으로 채움
a >> n 오른쪽으로 이동 a를 오른쪽으로 n비트 이동하고 왼쪽은 0으로 채움

※ 연산자를 사용한 비트연산의 예시😁

- 초기값 : a = 0b1101 / b = 0b0101

(이제부터 바이너리(2진수)로 연산결과를 산출하며 '0b'는 생략하겠습니다.)

- AND 연산 : a & b = 0101

- OR 연산 : a | b = 1101 

- XOR 연산 : a ^ b = 1000

- NOT 연산 : ~a = 0010

- 비트 이동 연산 : a << 2 = 0100

(비트 이동 연산을 수행하면 이동한 비트만큼 반대쪽은 0으로 자동 채워집니다.

사라지는 비트에 대해서 자동으로 반대편에서 나오게 할라면(원형이동연산) 함수적으로 사용자가 설정해주어야 합니다.

이는 아래의 "3-4. LED 패턴 제어(비트 시프트 + 원형 이동 연산)" 에서 확인해보겠습니다.)

 

1-2. 비트연산의 종류 4가지

1) 비트 세트

비트 세트는 특정 위치의 비트만을 1로 설정하고 나머지는 현재 값을 그대로 유지하는 연산

비트 OR 연산자를 통해 원하는 위치의 비트를 1로 설정하고 나머지는 0으로 설정한 후 연산을 수행하면 해당하는 비트만 1로 세트하고 나머지 비트는 원본을 유지하게 된다.

비트번호 7 6 5 4 3 2 1 0
a X X X X X X X X
b 0 0 0 1 1 0 0 0
비트 세트
(OR연산)
X X X 1 1 X X X

※ 위의 표에서 말하는 X는 0 또는 1을 뜻한다.

 

위의 표를 프로그램 코드로 나타내면 아래와 같다.

(1) a = a | 0b00011000;

(2) a = a | 0x18;

(3) a = a | (0x03 << 3);

위의 3가지 방법은 모두 동일한 연산을 수행한다.

 

2) 비트 클리어

비트 클리어는 특정 위치의 비트를 0으로 설정하고 나머지는 현재 값을 그대로 유지하는 연산

비트 AND 연산자을 수행하면 0과 AND 시킨 결과는 항상 0이 되고, 1과 AND 시킨 결과는 현재 값이 그대로 유지되므로 원하는 위치의 비트를 0으로 만들 수 있다.

비트번호 7 6 5 4 3 2 1 0
a X X X X X X X X
b 1 1 1 0 0 1 1 1
비트 클리어
(AND연산)
X X X 0 0 X X X

위의 표를 프로그램 코드로 나타내면 아래와 같다.

(1) a = a & 0b11100111;

(2) a = a & 0xE7;

(3) a = a & ~(0x03 << 3); (or연산에서 NOT 연산자 추가)

위의 3가지 방법은 모두 동일한 연산을 수행한다.

 

3) 비트 반전

비트 반전은 특정 위치의 비트만 반전시키고 나머지는 현재 값을 그대로 유지하는 연산
비트번호 7 6 5 4 3 2 1 0
a X X X X X X X X
b 0 0 0 1 1 0 0 0
비트 반전
(XOR연산)
X X X ~X ~X X X X

위의 표를 프로그램 코드로 나타내면 아래와 같다.

(1) a = a ^ 0b00011000;

(2) a = a ^ 0x18;

(3) a = a ^ (0x03 << 3);

위의 3가지 방법은 모두 동일한 연산을 수행한다.

 

4) 비트 검사/읽기

비트 검사/읽기는 특정 위치의 비트 값만을 알아내는 연산
비트번호 7 6 5 4 3 2 1 0
a X X X X X X X X
b 0 0 0 1 1 0 0 0
비트 검사
(AND연산)
0 0 0 X X 0 0 0

 


 

2. 디지털 데이터 출력을 위한 레지스터

2-1. DDR 레지스터

DDR레지스터의 사용은 Arduino에서 봤을때 pinMode 함수라고 생각하면 쉽다.

즉, 사용하고자 하는 포트의 핀(비트)를 INPUT이나 OUTPUT으로 설정하는 레지스터이다.

 

ATmega128A에서 I/O포트는 총 7개 포트가 있으며 이중 A~F포트는 8비트(8핀)로 구성되어있고

G 포트는 5비트(5핀)로 구성되어 있다.

DDRA 레지스터의 구조
DDRG 레지스터 구조

초기값은 모두 0으로 설정되어 있으며 0은 INPUT(입력), 1은 OUTPUT(출력)으로 설정된다.

 

예시로 B포트의 3번,4번 비트를 OUTPUT으로 설정하고 싶다면 

▸ DDRB = 0x18;

이란 코드를 통해서 설정이 가능하다.

 

2-2. PORT 레지스터

PORT 레지스터의 사용은 Arduino에서 봤을때 DigitalWrite 함수라고 생각하면 쉽다.

즉, 원하는 포트의 핀(비트)에 값을 부여할 수 있다.

PORTA 레지스터의 구조(A~E포트는 동일한 구조이다)
PORTG 레지스터의 구조

예시로 C포트의 7번,1번,0번 핀에 1을 출력하고 싶다면

▸ PORTC = 0x83;

이란 코드를 통해서 원하는 비트에 원하는 값을 출력할 수 있다.


 

3. 디지털 데이터 출력(LED 제어)

마이크로컨트롤러(ATmega128A) 보드와 8개의 LED핀 연결 

3-1. LED 8개 일괄 점멸

1) 코드 설명

※ Line 1, 2, 3은 아래의 4개 예시에서 공통으로 사용되고 main문만 변경 될 예정

- Line 1 : 마이크로컨트롤러의 동작 주파수를 정의한다.

ATmega128A는 16Mhz로 동작시키기때문에 이에 해당하는 값을 정의하였으며, 

int 타입은 2바이트로 65,536 까지만 표현할 수 있어서 16M의 값을 표현할 수없다.

따라서 상수 뒤에 'L'을 붙여 long 타입으로 바꾸어서 정의하였음

- Line 2 : 마이크로컨트롤러에 따른 레지스터 이름과 레지스터 비트 이름등이 정의되어 있는 헤더파일

- Line 3 : 시간 지연 함수 _delay_ms를 사용하기 위한 헤더파일

밀리초 단위 뿐만 아니라 마이크로초 단위의 지연시간을 설정할 수 있는 _delay_us 함수도 사용 가능하다.

- Line 8 : DDR 레지스터를 통해 A포트의 8핀을 전부 OUTPUT으로 설정한다.

- Line 10 ~ 16 : 무한반복문(Arduino의 loop() 함수부와 같음)

A포트의 0번~7번 비트를 0과 1을 1초 간격으로 번갈아가면서 출력한다. 

 

3-2. LED 패턴 제어(비트 시프트)

1) 코드 설명

- Line 127 : 비트 시프트 연산자(<<)를 활용해서 LED를 1개씩 점등하고 소등하는 동작 수행

- Line 128 : if 문을 통해 8개의 LED를 전부 한번씩 동작하고 나면 다시 처음 0번 비트를 점등하도록 하는 조건문 추가

 

3-3. LED 패턴 제어(비트 시프트 + 배열)

1) 코드 설명

- Line 160 : 배열 변수를 선언해서 점등하고자 하는 LED의 패턴을 배열형태로 저장

- Line 168 : 나머지 연산자를 사용해서 0번 배열 부터 7번 배열까지 반복해서 수행

3-4. LED 패턴 제어(비트 시프트 + 원형 이동 연산)

1) 이동연산과 원형 이동 연산 구분

- 이동 연산 : 비트 이동 연산자를 통해 비트를 이동하게되면 이동 후 가장자리의 비트는 자동으로 0으로 채워진다.

ex) 0000 0101 → 오른쪽으로 1비트 이동 → 0000 0010

- 원형 이동 연산 : 비트 이동 연산자를 수행해도 가장자리의 비트가 다시 처음으로 돌아오게 된다.

ex) 0000 0101 → 오른쪽으로 1비트 이동 → 1000 0010

 

2) 코드 설명

- Line 177 : 비트 이동시 사라지는 비트를 저장하는 변수

- Line 178 : 비트 이동시 사라지는 비트를 다시 처음 위치로 돌리기 위한 변수

- Line 180 : 비트 이동

- Line 181 : 비트 이동한 결과값이랑 Line 178의 변수와 or 연산 수행

 

3-5. LED 패턴 제어(심화)

원형 이동 연산을 사용하여 다음 표와 같은 패턴이 0.5초 간격으로 반복되어 표시되는 프로그램을 작성해보자.

패턴 PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0
1 X             X
2   X         X  
3     X     X    
4       X X      
5     X     X    
6   X         X  

 

해결하지 못한 심화 문제 ㅠ..

추후에 다양한 지식을 습득하고 추가로 시간을 할애해서 풀어보도록 하겠습니다..

댓글