본문 바로가기

공부/마이크로컨트롤러

[PIC] 16F84A 명령어 / (어셈블러) 프로그램 예제 설명

이 글은 스네일엔 스네이크(http://www.snailnsnake.co.kr)에서 불펌한 글입니다..


원칩 마이컴 PIC16F84(A)의 개요, 프로그램 메모리, 데이터 메모리 + SFR, 워킹 레지스터의 설명으로 16F84(A) 하드웨어 부분을 마쳤습니다. 충분하다고 할 수는 없지만 대략적인 큰 줄기는 다루었다고 생각됩니다. 그렇지만 이렇게 거북이 걸음으로 나가서는 언제 강의가 끝나고 프로젝트가 완료될지 알 수 없습니다. 절제와 집중 그리고 선택의 미덕이 필요한 시점인 것 같습니다. ^^

이번 장에서는 소프트웨어를 다루어야 할 차례로 16F84(A)의 명령어와 가장 간단한 예제 프로그램을 함께 분석해 보겠습니다. 프로그램을 배우는 효율적인 방법은 실제 예제를 분석하고 따라 해 보는 것입니다. 절대로 명령어를 달달 외우는 것이 아닙니다.

비록 16F84(A)는 명령어가 35개 뿐으로 마이컴 중에서도 꼬마에 속하지만, 이 명령어들로 작성되는 프로그램은 분명히 하나의 언어체계를 갖추고 있습니다. 작은 미니 언어지요... 그러므로 언어 습득에 관한 일반적 황금률과 금기도 16F84(A)의 학습에 마찬가지로 적용됩니다.

※ 마이크로칩사의 마이컴 패밀리들은 하바드 구조를 채택하여 적은 명령어 수 (35개)와 빠른 동작을 보여줍니다. (단 명령어 길이가 14비트로 데이터 비트 (8bit) 보다 길다) 그러나 동작과 기능면에서는 타 회사의 마이컴들에 뒤지는 일은 없습니다.

일반적으로 새로운 언어를 배울 때 단어와 문법에만 의존하지 말라고 합니다. 언어를 익히려면, 그 언어가 태어나고 자라난 지역의 환경과 문화를 이해하는 것이 중요합니다. 지금까지 우리는 많은 시간과 노력을 들여가며 마이컴을 이해하려고 노력해 왔습니다. 이 모든 작업이 멀리는 전체 마이컴 언어, 가깝게는 16F84(A)의 명령어를 이해하기 위한 사전 포석이 아니겠습니까? ^^

하나만 더 말씀드리지요. 언어는 하나의 약속입니다. 인간의 언어는 사회적 약속, 수학은 자연과의 약속, 마이컴 언어는 마이컴 하드웨어와의 약속... 언어가 상대와의 약속이므로, 언어는 모방을 통해서 배우는 것이 효율적 입니다. 언어를 단어(명령어)와 문법을 사용해서 임의로 만들면 일종의 창조가 됩니다. 창조의 결과가 논리적으로 타당하다 해도 "남 과의 약속"이라는 명제는 만족시킬 수 없습니다. 같은 이유로 컴퓨터나 마이컴 언어를 배울 때도 다른 사람들이 작성한 프로그램을 통해 배워가는 것이 바람직합니다.

-----------------------------------------------------------------------------------------------------

▶ 16F84(A)의 명령어 세트 (instruction set) : 총 35 개

위 그림에서 보면, 16F84(A)의 35 개 명령어는 다시 5 개의 그룹으로 분류됩니다. 1. 자료전송 명령, 2. 산술/논리연산 명령, 3. 비트조작 명령, 4. 흐름제어 명령, 5. 기타 명령의 다섯가지 입니다.


▶ 16F84(A)의 자료전송 (Data Transfer) 명령

자료전송 명령이란 워킹 레지스터(w), SFR, 데이터 메모리간에 8 비트 자료를 이동시키는 명령입니다. ^^


1. MOVLW Π k → MOV (옮겨) + L (숫자) + W (워킹 레지스터), 숫자의 내용은 k자리에 씁니다.

사용 예) MOVLW Π b'00001111' : w 의 내용이 이진수 00001111이 되도록 하여라... (어흠...!)

자세히 보면 명령어에서의 k 가 "사용 예"에서는 b'00001111' 로 대치되어 있는 것을 볼 수 있습니다.

※ 그림에서 "" 표시는 예제에 사용된 명령어 입니다. (모두 11개 입니다)

※ " Π " 기호의 의미는 한 칸 이상 띄우라는 뜻입니다.

※ 명령어는 소문자로 써도 상관 없습니다. (즉 MOVLW → movlw도 O.K)


2. MOVWF
Π f → MOV (옮겨) + W (워킹 레지스터의 내용) + F (SFR, 데이터 메모리), 어떤 SFR, 데이터 메모리인지는 f 자리에 씁니다.

사용 예) MOVWF Π TRISA : w 내의 이진수 내용을 TRISA로 옮겨라... (어흠...!)


3. MOVF
Π f, d → MOV (옮겨) + F (SFR, 데이터 메모리의 내용) 결과는 d = 0 이면 워킹 레지스터, d = 1 이면 자기 자신에게로 다시 옮깁니다. 어떤 SFR, 데이터 메모리인지는 f 자리에 씁니다.

사용 예) MOVF Π PORTA, 0 : PORTA 내의 이진수 내용을 w로 옮겨라... (어흠...!)

멍청하게 다시 자기 자신한테 옮기는 이유는 뭘 까요? (이 명령으로 STATUS 레지스터 내의 Z, DC, C 비트가 변할 수 있으므로 필요할 때가 있습니다)

※ Z 비트 : w 나 SFR 에서의 계산결과가 0 인 경우, Z=1로 된다.
※ DC 비트 : BCD 계산결과에 하위 4 번째 비트가 자리올림이 발생한 경우, DC=1로 된다.
※ C 비트 : w 나 SFR 에서의 계산결과 중에 자리올림이나 자리빌림이 발생한 경우, C=1로 된다.

※ 왕초보 강의에는 STATUS 레지스터를 자세히 다루지 않습니다. (계산 명령에 사용되기 때문)


4. CLRW → CLR (지워) + W (워킹 레지스터의 내용)

사용 예) CLRW : 워킹 레지스터 내의 이진수를 00000000으로 만들어라... (어흠...!)


5. CLRF Π
f → CLR (지워) + F (SFR, 데이터 메모리의 내용), 어떤 SFR, 데이터 메모리인지는 f 자리에 씁니다.

사용 예) CLRF Π PORTA : PORTA 내의 이진수를 00000000으로 만들어라... (어흠...!)


6. SWAPF
Π f, d → SWAP(교환해) + F (SFR, 데이터 메모리의 상, 하 4비트) 결과는 d = 0 이면 워킹 레지스터, d = 1 이면 자기 자신에게로 다시 옮깁니다. 어떤 SFR, 데이터 메모리인지는 f 자리에 씁니다.


여기까지만 정확히 이해하고 나면 나머지는 같은 형태가 반복 될 뿐입니다. 어떻습니까? 그렇게 어렵지는 않죠? 하나하나 찬찬히 짚어 보면서,
16F84(A) 명령어가 가지고 있는 일정한 패턴을 찾아 보십시오. 그 일정한 패턴이 바로 문법입니다. ^^


▶ 16F84(A)의 산술/논리 연산 (Arithmetic and Logic) 명령 (1)

산술/논리연산 명령이란 메모리 내용 (8비트)으로 계산을 수행하는 명령입니다. 두 개의 메모리가 필요한 명령의 경우에 두 개중 하나의 메모리는 반드시 워킹 레지스터(w)가 되어야 합니다. ^^


명령어의 ADD (더해), SUB (빼), AND (논리합을 계산해), IOR (논리곱을 계산해), XOR (배타적 논리곱을 계산해)... 는 부분만 다를 뿐 나머지 내용은 앞의 자료전송 명령의 항목과 같습니다.

※ AND : 0 ∩ 0 0 , 0 ∩ 1 0 , 1 ∩ 0 0 , 1 ∩ 1 1 (∩ 는 AND), 0 와 1은 비트를 의미

※ IOR : 0 ∪ 0 0 , 0 ∪ 1 1 , 1 ∪ 0 1 , 1 ∪ 1 1 (∪ 는 IOR)

※ XOR : 0 ∪ 0 0 , 0 ∪ 1 1 , 1 ∪ 0 1 , 1 ∪ 1 0 (∪ 는 XOR)

※ 논리연산 표가 보기 어려워서 죄송~ -_-


▶ 16F84(A)의 산술연산 (Arithmetic and Logic) 명령 (2)

명령어의 INC (1 증가시켜), DEC (1 감소시켜), RL (각 비트의 자리를 왼쪽으로 밀어), RR (각 비트의 자리를 오른쪽으로 밀어), COM (각 비트를 보수로 만들어)... 는 부분만 다를 뿐 나머지 내용은 앞의 자료전송 명령의 항목과 같습니다.

※ RL, RR 명령의 경우 연산대상이 되는 w 나 SFR의 각 비트는 자리옮김을 합니다. 이 때 최상위 비트는 STATUS의 C 비트 (C 플래그)가 됩니다. - 자세한 내용은 데이터북이나 다른자료 참조.

※ 보수를 만든다는 말은 각 비트의 0 → 1 로, 1 → 0 로 만든다는 뜻입니다.


▶ 16F84(A)의 비트조작 (Bit Operations) 명령

비트조작 명령이란 w 나 SFR 레지스터 내용 (8비트) 중의 특정 비트 값만을 변경하는 명령입니다. ^^


1. BCF
Π f, b → B (비트) + C (0 으로 만들어라) + F (w 나 SFR, 데이터 메모리에 있는), 어떤 SFR, 데이터 메모리인지는 f 자리에 쓰고, 어떤 비트인지는 b 자리에 씁니다.

사용 예) BCF Π STATUS, 5 : STATUS 내의 5 번째 비트 값을 0 로 만들어라... (어흠...!)


2. BSF Π f, b → B (비트) + S (1 로 만들어라) + F (w 나 SFR, 데이터 메모리에 있는), 어떤 SFR, 데이터 메모리인지는 f 자리에 쓰고, 어떤 비트인지는 b 자리에 씁니다.

사용 예) BSF Π STATUS, 5 : STATUS 내의 5 번째 비트 값을 1 로 만들어라... (어흠...!)


※ " Π " 기호의 의미는 한 칸 이상 띄우라는 뜻입니다.

※ 명령어는 소문자로 써도 상관 없습니다. (즉 MOVLW → movlw도 O.K)


▶ 16F84(A)의 프로그램 흐름제어 (Directing a Program Flow) 명령

프로그램 흐름제어 명령이란, (하나씩 다음 번지로 진행하는) 진행 순서를 바꾸어 주는 명령입니다. ^^

9 개의 명령으로 구성된 흐름제어 명령은 (조건문을 만들어) 상황에 따라 프로그램 흐름을 변경하는 명령, 무조건 프로그램 흐름을 변경하는 명령, 서브루틴에 사용되는 명령의 3 가지 분류로 나누어 집니다.


▦ (조건문을 만들어) 상황에 따라 프로그램 흐름을 변경하는 명령 (4 가지)

1. BTFSC Π f, b → B (비트) + T (검사해) + F (w 나 SFR, 데이터 메모리에 있는) + S (다음 번지의 명령은 스킵(무시)해라) + C (만약 검사한 비트가 0 이면), 어떤 SFR, 데이터 메모리인지는 f 자리에 쓰고, 어떤 비트인지는 b 자리에 씁니다.

사용 예) BTFSC Π PORTA, 4 : PORTA의 4 번째 비트 값이 0 인지 시험해 보고, 그 결과에 따라 프로그램 진행 순서를 정하도록 하여라... (어흠...!)


2. BTFSS Π f, b → B (비트) + T (검사해) + F (w 나 SFR, 데이터 메모리에 있는) + S (다음 번지의 명령은 스킵(무시)해라) + S (만약 검사한 비트가 1 이면), 어떤 SFR, 데이터 메모리인지는 f 자리에 쓰고, 어떤 비트인지는 b 자리에 씁니다.

사용 예) BTFSS Π PORTA, 4 : PORTA의 4 번째 비트 값이 1 인지 시험해 보고, 그 결과에 따라 프로그램 진행 순서를 정하도록 하여라... (어흠...!)


3. DECFSZ Π f, d → DEC (1 만큼 빼) + F (w 나 SFR, 데이터 메모리의 내용) + S (다음 번지의 명령은 스킵(무시)해라) + Z (만약 w 나 SFR, 데이터 메모리의 내용이 0 이면) 결과는 d = 0 이면 워킹 레지스터, d = 1 이면 자기 자신에게로 다시 옮깁니다. 어떤 SFR, 데이터 메모리인지는 f 자리에 씁니다.

사용 예) DECFSZ Π w, 4 : 워킹 레지스터의 이진 값을 1 만큼 빼고, 그 결과에 따라 프로그램 진행 순서를 정하도록 하여라... (어흠...!)


4. INCFSZ Π f, d → INC (1 만큼 더해) + F (w 나 SFR, 데이터 메모리의 내용) + S (다음 번지의 명령은 스킵(무시)해라) + Z (만약 w 나 SFR, 데이터 메모리의 내용이 0 이면) 결과는 d = 0 이면 워킹 레지스터, d = 1 이면 자기 자신에게로 다시 옮깁니다. 어떤 SFR, 데이터 메모리인지는 f 자리에 씁니다.

사용 예) INCFSZ Π w, 4 : 워킹 레지스터의 이진 값을 1 만큼 더하고, 그 결과에 따라 프로그램 진행 순서를 정하도록 하여라... (어흠...!)

▦ 무조건 프로그램 흐름을 변경하는 명령 (1 가지)

5. GOTO Π k → GOTO (지시번지로 무조건 점프해라), 번지는 k 자리에 영문자로 라벨을 만들어 씁니다.

사용 예) GOTO Π START : START 라는 라벨이름을 가진 번지로 점프하여라... (어흠...!)


▦ 서브루틴에 사용되는 명령 (4 가지)

6. CALL Π k → CALL (지시한 번지를 호출해라), 번지는 k 자리에 영문자로 라벨을 만들어 씁니다.

사용 예) CALL Π LOOP : LOOP 라는 라벨이름을 가진 서브루틴을 호출하여라... (어흠...!)


7. RETURN 서브루틴의 마지막 줄에 사용하는 명령어로 서브루틴에서 복귀합니다.

8. RETLW Π k 서브루틴의 마지막 줄에 사용하는 명령어, k 값을 워킹 레지스터에 가지고 복귀합니다.

9. RETFIE 인터럽트로 호출된 서비스 프로그램의 마지막 줄에 사용하는 명령어입니다. 의미는 동일...


※ " Π " 기호의 의미는 한 칸 이상 띄우라는 뜻입니다.

※ 명령어는 소문자로 써도 상관 없습니다. (즉 MOVLW → movlw도 O.K)


▶ 16F84(A)의 기타 (Other Instructions) 명령

NOP 명령은 아무 일도 하지 않습니다. 그저 1 싸이클 (cycle) 동안 쉽니다. ^^ 마이컴도 쉰대요... 글쎄...

※ 1 싸이클 (cycle) : 16F84(A)에서는 4 클럭을 의미합니다. 4 MHz 클럭인 경우는 1㎲가 지연됩니다.


워치독 타이머(CLRWDT), 슬립모드(SLEEP) 명령은 자세한 설명을 하지 않습니다.
자세한 내용은 데이터북이나 다른 자료를 참조하여 주십시요.

-----------------------------------------------------------------------------------------------------

▶ 16F84(A)의 어셈블러 프로그램 예제

16F84(A)의 35 개 명령어에 대한 설명의 마무리로 어셈블러로 작성된 예제 프로그램을 살펴 보겠습니다. 이 프로그램은 먼저 시간에 소개한 타겟회로에 사용될 첫번째 프로그램이기도 합니다. ^^

※ 마이크로칩사가 개발하여 배포하는 MPLAB과 내장 어셈블러를 사용하려면 그림에 나타난 내용 외에 몇 항목이 추가로 필요합니다.

1. 첫번째 줄의 "org 0x00"의 "org"는 어셈블러의 예약어로, 명령어가 저장되는 16F84(A) 프로그램 메모리의 위치를 지정하는 역할을 맡습니다. "org" 뒤의 숫자가 0x00 이므로, 어셈블러는 다음에 오는 명령부터 16F84(A)의 기계어로 번역한 후 0x00 번지에서 부터 차례로 저장합니다. 앞 장에서 언급했듯이 16F84(A)에 전원이 들어가거나 리셋으로 초기화 되면 프로그램은 0x00 번지부터 시작하게 됩니다. 따라서 반드시 프로그램 메모리의 0x00 번지부터 명령어가 저장되어야 합니다.

2. 마지막 9 번째 줄에서 "loop"라는 이름의 라벨을 볼 수 있습니다. 9 번째 줄의 goto 명령어는 자기자신으로 점프할 것을 요구하므로 프로그램은 영원히 9 번째 줄을 빠져나갈 수 없게 됩니다. 즉 무한루프에 빠져 든 것입니다. 이 예제 프로그램은 2 번째 줄에서 7 번째 줄까지 16F84(A)의 포트 A(RA0 - RA4)를 입력으로 포트 B(RB0 - RB7)를 출력으로 정의하고, 8 번째 줄에서 RB7을 "1"로 세트하여 LED를 점등합니다. 그리고 나면 프로그램에서 계획된 모든 임무가 완수 되므로 무한루프에서 대기하도록 되어 있습니다.

※ 프로그램의 2 번째 줄과 7 번째 줄에서 먼저 시간에 소개한 "SFR 페이지 전환"이 사용 되었습니다.

※ 먼저 시간의 타겟 회로도를 보면 RA4 (포트 A의 5 번째 비트) 단자가 스위치 입력단자로 설계되어 있습니다. RA4 (포트 A의 5 번째 단자)를 입력으로 정하려면, TRISA의 5 번째 비트를 "1"로 세팅하면 됩니다. ("0"는 출력, "1"은 입력을 의미) 따라서 나머지 RA0 ~ RA3 단자는 출력으로 정해진 것을 알 수 있습니다.

※ 같은 논리로 포트 B의 8 단자는 (RB0 ~ RB7) 전부 출력단자가 되었다는 것을 알 수 있습니다.

3. 명령어의 우측에는 세미콜론(";")을 사용하여 주석을 달고 있습니다. 세미콜론의 우측은 어셈블러가 무시하는 영역으로 약속되어 있습니다. 한글을 사용하여 주석을 달 수도 있습니다. ^^

4. 어셈블러를 비롯한 컴퓨터 언어로 프로그램을 작성할 때, 에디터 화면에 줄을 잘 맞추어 명령어를 기술하는 것이 프로그램을 잘 짜는 첫번째 요령입니다. 탭 키를 십분 활용하는 것이 좋습니다.

5. 프로그램을 잘 짜는 두번째 요령은 주석을 많이 달아두는 것입니다. 프로그램 작성은 논리와 집중을 요구하는 작업입니다. 그러므로 하루만 지나도 프로그램 내용을 다시 기억해 내기 힘들어 지는 경우가 왕왕 있습니다. 머리가 암만 좋아도 소용 없습니다. ^^

기억이 나지 않으면 프로그램의 아이디어를 처음부터 논리적으로 하나하나 되 살려 내와야 합니다. 진도가 나가도 시원치 않은 판에 뒤로 돌아가려니 괴롭기가 한이 없습니다. 이러한 불상사를 막으려면 프로그램을 작성할 때 설명을 열심히 적어두어야 합니다. 설명을 달아놓은 문장이 곧 주석입니다.


자 이제 이론은 그만... 실전으로 들어갑시다. 화이팅!!!

-----------------------------------------------------------------------------------------------------

- 계속 -