반응형

이전 강좌에서 LED를 켜고 끄는 간단한 동작을 배웠으니, 이제 LED를 깜빡여보자.^^ C 언어에서는 LED를 점멸시키기 위해 for()문을 이용한 시간지연을 사용했었다. 어셈에서는 for()문을 사용할 수 없으므로 직접 딜레이 루틴을 만들어 주어야 한다. 1초의 시간지연을 만들기 위해 C언어에서는 3줄이면 끝나지만 어셈에서는 코드가 상당히 길다. 하지만, 코드를 살펴보면 패턴이 반복되기 때문에 코드가 길어도 쉽게 이해가능하다. 소스가 길다고 기죽지 말자.^^

 

우선 머신사이클(Machine Cycle)을 계산해야 한다. 머신사이클은 최소 명령 수행 시간이다. 가장 작은 단위의 명령이 수행되는데 걸리는 시간을 머신 사이클이라 한다. 우리는 TY52보드를 사용하고 있고 여기에 쓰이는 크리스탈이 24MHz 짜리이므로 머신 사이클은 (1/24MHz) * 12 = 0.5us 로 계산된다. 즉, 하나의 명령을 수행하려면 0.5us라는 시간이 걸린다는 것이다. 따라서 1사이클 = 0.5us 이다. 아래의 소스 코드를 컴파일해서 생성된 헥사파일을 TY52 보드에 구우면 3개의 LED가 1초마다 깜빡인다.

 

 

;------------------------------------------------------

;

;               LED 깜빡이기 어셈 소스

;

;------------------------------------------------------

              ORG     0000H
              JMP      START

 

              ORG     0035H

 

START:

 

              MOV         P1,   #0FFH      ; LED 끄기
              CALL        D_1S                ; 1초 지연
              MOV         P1,   #0H         ; LED 켜기
              CALL        D_1S                ; 1초 지연
              JMP         START

 

;------------------------------------------------------

 

; 요 위에 까지가 메인 코드이고 아래부터가 딜레이, 시간지연을 만들기 위한 소스이다.

;10us의 시간 지연부터 만들기 시작해서 소스의 맨 밑에 보면 1초까지 딜레이 코드를 만들었다.

; LED를 1초마다 깜빡이기 위해서 1초의 시간지연을 주어야 하는데, 이 1초를 만들려면 아래와 같이 작은 단위의 시간지연부터 만들고 이를 다시 다음 시간지연 루틴에서 불러들여 결국은 1초의 딜레이가 만들어진다. 일단 이 정도로 알아두고, 이렇게 딜레이를 만드는 방법하고 또 한 가지 방법이 있는데, 그 방법은 아직 이해를 못했다.^^; 후에 이해한 다음 추가로 설명할 예정이니, 좀 노가다 같더라도 아래의 방법을 우선 익혀두자^^

 

아래는 10 micro second를 만드는 루틴이다. 이 루틴이 실행되는데 걸리는 시간은 총 20 사이클인데, 실제로 아래의 코드를 보면서 더해보면 18사이클 밖에 보이지 않는다. 책을 보니, 아래에 보이는 코드 외에 2 사이클이 더 소요된다고 한다.^^ 자, 아래의 D_10US 만 파악이 되면, 그 다음 딜레이 루틴부터는 이해가 갈 것이다.

D_10US:        ; 20*(12/CLK) = 10US 
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 NOP  ; 1 cycle
 RET  ; 2 cycle

 

;------------------------------------------------------
 
D_50US:  ; 10US * 5 + 4*(12/CLK) = 52US = 50US
 CALL D_10US       ; 콜이란 명령어가 나왔다. 위에 있는 D_10US 로 가서 10us의 시간을 소비하고 RET를 만나면 이 아래의 코드가 실행된다. 이렇게 5 번 반복하면 50us의 시간이 소비된다.
 CALL D_10US
 CALL D_10US
 CALL D_10US
 CALL D_10US
 RET

 

이 아래의 코드도 같은 패턴이니, 쭉~ 한 번 훑어보길 바란다.^^

;------------------------------------------------------

 

D_100US: ; 50US * 2 + 4*(12/CLK) = 102US = 100US
 CALL D_50US
 CALL D_50US
 RET

 

;------------------------------------------------------

 

D_500US:
 CALL D_100US
 CALL D_100US
 RET

 

;------------------------------------------------------

 

D_1MS:
 CALL D_500US
 CALL D_500US
 RET

 

;------------------------------------------------------

 

D_5MS:
 CALL D_1MS
 CALL D_1MS
 CALL D_1MS
 CALL D_1MS
 CALL D_1MS
 RET

 

;------------------------------------------------------

 

D_10MS:
 CALL D_5MS
 CALL D_5MS
 RET

 

;------------------------------------------------------

 

D_50MS:
 CALL D_10MS
 CALL D_10MS
 CALL D_10MS
 CALL D_10MS
 CALL D_10MS
 RET

 

;------------------------------------------------------

 

D_100MS:
 CALL D_50MS
 CALL D_50MS
 RET

 

;------------------------------------------------------

 

D_500MS:
 CALL D_100MS
 CALL D_100MS
 CALL D_100MS
 CALL D_100MS
 CALL D_100MS
 RET

 

;------------------------------------------------------

 

D_1S:
 CALL D_500MS
 CALL D_500MS
 RET

 

;------------------------------------------------------

 

 END

 

 

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

 

용어설명:

위의 소스에 CALL   D_1S란 코드가 있는데 해석해 보면, D_1S라는 곳으로 가서 명령을 수행하고 RET를 만나면 CALL이 있는 자리로 복귀해서 다음 명령을 실행해라. 이런 의미이다. CALL하고 RET를 같이 외워두자. 소스가 길어졌지만 딜레이에서 다시 딜레이를 만들고 만든 딜레이를 가지고 또 다시 딜레이를 만들어 내는 것이므로 쉽게 이해할 수 있을 것이다.

 

명령어 정리:

MOV: move를 나타내는 명령어로 값을 옮기라는 뜻이다. 어떤 값을 써 넣을 때 사용한다.

CALL: call은 부른다는 뜻으로 딜레이 루틴등등...을 불러서 그리로 분기하여 딜레이 루틴을 수행하고 돌아온다. (분기한 곳에서 RET 명령어를 만나면 복귀한다.)

RET: return의 의미로 복귀를 뜻한다.

JMP: jump를 말한다. 쩜프~ 레이블이 있는 곳이면 어디로든 점프가 가능하다.

NOP: no operation, 아무 것도 하지 않고 다음으로 진행~

 

사실 컴퓨터 내부 구조에 대해 잘 몰라도 C 언어를 가지고 프로그램을 짤 수 있지만, MCU의 하드웨어적인 구조, 컴퓨터 시스템 구조, 스택, 레지스터 등을 좀 더 감각적으로 제어하고 싶다면 어셈블리어 공부가 상당한 도움이 될 것 같다.^^ 또한 운영체제에 관심이 있다거나 MCU에 운영체제를 포팅하려 한다면 어셈공부가 필수적이라 할 수 있겠다.

반응형

+ Recent posts