본문 바로가기
코스웨어/11년 내장형하드웨어

[내장형]김동화_2011년_9월6일_일일보고서

by 알 수 없는 사용자 2011. 9. 6.
728x90
반응형
ARM

- main 함수 이외 모든 함수를 각각의 역할에 맞추어 분리하였다.
 → 각각의 헤더파일과 .c 파일을 따로 분리하여 생성하고 main함수에 포함시켰다.
⇒ 출력 확인 (Keyboard 숫자키 '1' 입력시 LED ON/OFF)

⇒ 출력 확인 (Keyboard 숫자키 '2' 입력시 문자열 출력)

 


- 타이머 / 카운터 (TIMER/COUNTER)

⇒ AT91SAM7S256에는 동일한 구조와 기능의 16비트 타이머/카운터(Timer/Counter) 채널 TC0 ~ TC2를 가지고 있다. 이들 3개의 채널은 서로 독립적으로 동작하며, 이벤트 카운트(event counting), 주파수 측정(frequency measurement), 시간 간격 측정(interval measurement), 시간 지연(delay timing), 펄스 발생(pulse generation), PWM 출력등의 기능을 수행할 수 있다.

⇒ 각 채널은 3개의 외부 클록 입력, 5개의 내부 클록 입력, 2개의 다기능 I/O 신호 단자 등을 가지고 있으며, 또한 각 채널은 내부 인터럽트를 발생시킬 수 있다.

⇒ 사용자가 타이머/카운터 채널을 사용하려면 해당 채널의 기능을 제어하는 I/O 레지스터를 사용해야 하며, 타이머/카운터 블록 제어 레지스터 TC_BCR과 타이머/카운터 블록 모드 레지스터 TC_BMR 등 2개의 I/O 제어 레지스터는 이들 3개 채널에 공통으로 사용된다.

<타이머/카운터의 구성 블록도>


⇒ 위의 그림은 타이머/카운터의 내부 구성이다. 여기서 TCLK0~TLCKS2는 각 채널에 입력되는 외부 클록 단자이며, TIOA0~TIOA2와 TIOB0~TIOB2는 각 채널에 해당하는 다기능 I/O 단자인데 이것들은 기능은 사용자가 설정하여 사용할 수 있다. TIOA0~TIOA2와 TIOB0~TIOB2는 캡쳐 모드에서는 타이머/카운터 트리거 입력단자로 사용되고, 파형발생 모드에서는 타이머/카운터 입/출력 단자로 사용된다. 이들 신호를 사용하려면 병렬 입출력 제어기(PIO)에서 Peripheral B로 설정해야 한다.

⇒ 한편, 내부신호 TIMER_CLOCK0~TIMER_CLOCK5는 각각 마스터 클록을 분주한 주파수 신호 MCK/2, MCK/8, MCK/32, MCK/128, MCK/1024(분주비)이며, XC0~XC2는 각 채널의 클록 입력신호이다. 또한, SYNC는 3개의 채널을 동시에 동작시키기 위한 동기 입력 신호이다.

⇒ 타이머/카운터는 기본적으로 클록이 공급되지 않는 상태에 있으므로 이를 사용하려면 먼저 전력관리 제어기(PMC)에서 클록을 공급하도록 설정해야 한다.

⇒ 타이머/카운터에서는 각 채널별로 여러 가지 인터럽트를 발생할 수 있는데, 이를 사용하기 위해서는 먼저 인터럽트 제어기를 설정해야 한다.


- 소스 작성

⇒ Timer.h와 Timer.c 파일을 생성한다.

⇒ makefile에 컴파일 옵션을 추가한다.

OBJS+= lowlevel.o main.o lcd.o led.o interrupt.o dbgu.o timer.o


timer.o: timer.c

        $(CC) -c $(CCFLAGS) timer.c -o timer.o

 

⇒ timer.h

 → Channel Control Register인 TC0_CCR의 레지스터 주소를 추가한다.(0번 타이머 카운터)

 → Interrupt Status Register인 TC0_IDR의 레지스터 주소를 추가한다.

 → Interrupt Disable Register인 TC0_CMR의 레지스터 주소를 추가한다.

 → Control Register인 TC0_CMR 레지스터 주소를 추가한다.


 → #define TC0 12 // 타이머 카운터 0

 → #define CLKDIS 1 // 클록이 공급되지 않도록 금지한다.

 → #define TCCLKS 0 // Clock Selection - 분주비 선택(TIMER_CLOCK1(MCK/2)-분주비)

 → #define CPCTRG 14 // RC Compare Trigger Enable

⇒ timer.c

 

 → 전력 관리 제어기 (PMC)에서 클록을 공급하도록 설정

 → 타이머 카운터를 초기화하기 전에 실행되면 안되므로   TC0_IDR = 0xFFFFFFFF; // 인터럽트 금지를 위해 모든 비트를 1로 둔다.

 → 상태 레지스터를 읽기만 한다.(레지스터 이름을 적어놓기만 하면 읽어온다.)

 → AIC_IDCR = (1<<TC0); // 인터럽트 금지 명령 레지스터 - irq용 벡터 테이블

 → AIC_SVR[TC0] = (unsigned int)myCounter; // 소스 벡터 레지스터 -함수 호출 조건

 → 소스 모드 레지스터 - high level sensitive

 → 대응하는 인터럽트의 에지 검출기를 클리어한다. (혹시나 중간에 인터럽트가 들어왔을 경우를 위해 클리어해 둔다.)

 →  채널 모드 레지스터,  RC Compare Trigger Enable

WINAPI

- WM_COMMAND

⇒ 프로그램 실행중에 사용자가 메뉴 항목을 선택하면 WM_COMMAND 메시지가 발생한다.

⇒ 이 때 어떤 메뉴 항목이 선택되었는가는 wParam의 하위 워드로 전달되므로 LOWORD(wParam)을 읽어 판단할 수 있다. 그래서 Menu.cpp의 WndProc에서는 WM_COMMAND 메시지를 받을 경우 switch 문으로 다시 LOWORD(wParam)의 값에 따라 분기를 하여 각 메뉴 항목에 따른 처리를 발생한다.

⇒ ID_FILE_MENU1 메뉴 항목(Menu1)이 선택되었을 경우 메시지 박스를 열어 메뉴 항목이 선택되었음을 알려주고 ID_FILE_EXIT메뉴 항목(Exit)이 선택되었을 경우 프로그램을 종료한다.

⇒ WM_COMMAND 메시지는 메뉴 항목을 선택할 뿐만 아니라 액셀러레이터를 누를 때도 발생하며 도한 버튼, 에디트 박스 등의 컨트롤이 부모 윈도우로 통지 메시지를 보낼 때도 발생한다. 이 메시지의 추가 정보는 다음과 같은 구조를 가진다. 


설명

lParam

LOWORD(wParam)

HIWORD(wParam)

 

통지 메시지를 발생시킨 컨트롤의 윈도우 핸들

메뉴나 액셀러레이터, 컨트롤의 ID

컨트롤이 보내는 통지 메시지, 메뉴가 선택된 경우는 0이 되며 액셀러레이터가 선택된 경우는 1이 된다.

 

⇒ WM_COMMAND 메시지가 워낙 여려가지 명령을 받아들이는 메시지이다 보니 추가 정보도 복잡하다. 여기서 우리가 사용한 값은 메뉴 ID가 전달되는 LOWORD(wParam)뿐이다. 기억할 것은 메뉴 선택시 WM_COMMAND 메시지가 전달되며 LOWORD(wParam)을 읽어 어떤 메뉴 항목이 선택되었는지를 판단할 수 있다는 것.


- 메뉴 편집기

⇒ 메뉴 편집기는 사용자가 편집한 메뉴를 텍스트 형태로 리소스 파일에 기록한다.


- 새 메뉴의 작성

⇒ 새로운 메뉴를 작성할 때는 리소스 뷰의 팝업 메뉴에서 리소스 추가(또는 Insert) 항목을 선택한다.

 

⇒ 위와 같이 자동으로 IDR_MENU2가 생성되었다.(위에 IDR_NENU1 이 이미 만들어져 있으므로 IDR_MENU2가 되었다.)

- 메뉴 항목의 추가

⇒ 빈칸에 새로운 메뉴를 추가하려면 곧바로 캡션을 입력하거나 빈칸을 더블클릭하여 속성 편집기를 열고 캡션과 기타 속성들을 입력한다. 좌상단의 빈칸을 더블 클릭하여 File이라는 캡션을 주면 다음과 같이 된다.

 

⇒ 오른쪽과 아래쪽에 각각 빈칸이 나타나는데 이 빈칸들에 또 메뉴 항목을 만들 수 있으며 아래와 같은 식으로 메뉴 생성이 가능하다.

 

- 메뉴 항목의 수정

⇒ 기존에 만들어져 있는 메뉴의 이름이나 속성을 변경하려면 속성 편집기에서 원하는 속성을 다시 입력하면 된다.


- 메뉴 항목의 삽입

⇒ 기존에 작성되어 있는 메뉴 리스트에서 삽입할 위치에 커서를 위치한 후 키보드에서 Insert 키를 누르면 커서 위치에 빈칸이 새로 생성되며 이 빈칸에 원하는 항목을 입력한다.


- 메뉴 항목의 삭제

⇒ 삭제하고자 하는 메뉴 항목에 커서를 위치한 후 Delete 키를 누른다. 단, 메뉴 리스트의 메뉴 항목은 그냥 삭제되지만 하위 메뉴를 거느린 풀다운 메뉴를 삭제할 때는 바로 삭제하지 않고 경고 메시지 창이 출력된다.


- 메뉴의 이동

⇒ 이동하고자 하는 메뉴를 마우스로 드래그하여 원하는 위치로 이동할 수 있다. 이 기능을 이용해 메뉴 바에 있는 메뉴를 하위 메뉴로 만들 수 있다.

⇒ 예로 Edit 메뉴를 File 메뉴의 Save와 Print 사이에 끼워 넣으면 다음과 같이 Edit 메뉴 전체가 File 메뉴의 하위 메뉴가 된다.

 

- 복사 및 붙여넣기

⇒ 메뉴의 복사, 붙여넣기는 워드 프로세서에서 클립보드를 사용하여 문서의 일부분을 복사하는 것과 개념적으로 동일하다.


기타 리소스

- 아이콘, 커서

⇒ 아이콘이나 커서도 리소스의 일종이며 각각의 편집기를 사용하여 제작할 수 있다.

⇒ 메뉴의 Insert → resource 대화상자에서 ICON을 선택하여 새로운 아이콘을 만든다.

 

⇒ 다음으로 Insert → resource 대화상자에서 CURSOR을 선택하여 새로운 커서를 만든다.

 

⇒ 커서를 만든 후 커서 편집기를 닫고 이번에는 만들어 놓은 커서와 아이콘을 사용하도록 코드를 수정한다.

WndClass.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR1));
WndClass.hIcon 
= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));


⇒ 아래와 같이 아이콘과 커서가 생성된 것을 확인 할 수 있다.

 


- 액셀러레이터

⇒ 액셀러레이터(Accelerator)는 쉽게 말해 단축키이다. Ctrl+C는 Copy, Ctrl+V는 Paste 등이 있다.

⇒ 단, 윈도우wm에서 단축키와 Accelerator를 구별하는 이유는 윈도우즈에서 단축키(ShortCut)가 다른 의미로 사용되고 있기 때문이다. 메뉴 이름에 &를 넣어 Alt키와 함께 사용하는 키를 단축키라고 하며 액셀러레이터와는 의미가 조금 다르다.

⇒ 단축키는 반드시 Alt키와 함께 사용해야 하며 메뉴에 있는 항목을 키보드로 선택하는 빠른 방법이지만 액셀러레이터는 메뉴와 상관없이 언제든지 사용이 가능하다.


- 실습

⇒ 리소스 뷰에서 IDR_MENU1을 더블클릭하면 메뉴 편집기가 열린다.

⇒ File 팝업 메뉴의 속성 윈도우에서 Caption을 &file로 바꾼다.

 

⇒ File 메뉴 아래 세 개의 메뉴 항목에서 각 항목의 캡션을 다음과 같이 수정한다. 

수정 전

수정 후

Menu1

Menu&1\tCtrl+A

Menu2

Menu&1\tCtrl+B

Exit

&Exit\tCtrl+C



 

⇒ 아래는 수정중인 화면이다.

 

⇒ 메뉴를 만들 때와 같은 방법으로 리소스 추가 대화상자에서 Accelerator를 선택한다. 다음과 같은 액셀러레이터 편집기가 열린다. 각 란에 다음과 같이 입력한다.

 

 

⇒ 다음은 리소스를 코드에서 사용하도록 소스를 수정한다. WinMain의 선두에 hAccel 변수를 선언하고 메시지 루프만 다음과 같이 수정한다.

HACCEL hAccel;



hAccel 
= LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
while(GetMessage(&Message, NULL, 00))
{
  
if(!TranslateAccelerator(hWnd, hAccel, &Message))
  {
    TranslateMessage(
&Message);
    DispatchMessage(
&Message);
  }
}

 

⇒ Accel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));

 → 이 함수는 리소스로부터 액셀러레이터 테이블을 읽어들인다. 두 번째 인수 lpTableName은 액셀러레이터 테이블의 이름 문자열 포인터이되 우리가 작성한 액셀러레이터 테이블 IDR_ACCELERATOR1은 정수값이므로 MAKEINTRESOURCE 매크로를 사용해야 한다.

 → 이 함수는 리소스에서 액셀러레이터 테이블을 읽은 후 그 핸들을 리턴한다. 이 핸들값을 hAccel이라는 변수에 대입해 두면 다음부터 hAccel을 통해 액셀러레이터 테이블을 읽을 수 있다.

⇒ int TranslateAccelerator(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg);

 → 이 함수는 키보드 메시지를 WM_COMMAND 메시지로 변경하여 액셀러레이터가 동작할 수 있도록 한다. 액셀러레이터 Ctrl+A가 입력되었다고 해 보자. Ctrl+A는 액셀러레이터이기 이전에 키보드로부터의 입력이므로 먼저 WM_KEYDOWN 메시지가 발생할 것이고 그대로 내버려 주면 WndProc의 WM_KEYDOWN 메시지 처리 루틴에서 먼저 이 키값을 처리해 버릴 것이다.

 → TranslateAccelerator 함수는 lpMsg의 키보드 입력값을 읽어 이 키값이 hAccTable에 있는지 먼저 살펴보고 있을 경우 그 키에 해당하는 WM_COMMAND 메시지를 hWnd 윈도우로 전달하고 TRUE를 리턴해 버린다.

 → 그래서 액셀러레이터가 입력되었을 경우 TranslateMessage, DispatchMessage 함수가 실행되지 못하게 막아 버리며 다음 번의 WM_COMMAND 메시지가 처리되도록 한다.

 → WM_KEYDOWN 메시지는 중간에 다른 메시지로 변형되거나(WM_COMMAND) 추가로 메시지를 발생(WM_CHAR)시키는 경우가 빈번하다.

728x90