- 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에 컴파일 옵션을 추가한다.
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)); |
⇒ 아래와 같이 아이콘과 커서가 생성된 것을 확인 할 수 있다.
- 액셀러레이터
⇒ 액셀러레이터(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 = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
while(GetMessage(&Message, NULL, 0, 0))
{
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)시키는 경우가 빈번하다.
'코스웨어 > 11년 내장형하드웨어' 카테고리의 다른 글
[내장형]황세선 2011년 9월 14일 (24) | 2011.09.15 |
---|---|
[내장형]정선주 2011년 9월 9일 (10) | 2011.09.10 |
[내장형]심재원_2011년09월08일 (10) | 2011.09.08 |
[내장형]이수란_2011년9월7일 (9) | 2011.09.07 |
[내장형]최남식-2011년9월5일 일일보고서 (11) | 2011.09.06 |
[내장형]윤민석-2011년 9월 2일 일일보고서 (10) | 2011.09.02 |
AT91SAM7S의 USART(DBGU) (0) | 2011.09.02 |
[내장형]이성재 2011년 9월1일 일일보고서 (15) | 2011.09.01 |