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

[내장형]윤병도_2011년 8월 26일_일일보고서

by 알 수 없는 사용자 2011. 8. 26.
728x90
반응형


*코드 최적화
Timing Diagram을 보면 여러 주변기기마다 데이터를 처리하는 속도등이 다르다
특히 lcd모듈은 동작시간이 다소 느리므로 타이밍도를 잘 보고 delay시간을 적절히 조절하여 주어야 한다
다음은 lcd모듈의 Timing Diagram이다



 


위에서 보면 최소한 기다려줘야 하는 시간이 MIn에서 nano second단위로 표시되고 있다
그 시간을 delay시키기 위해서 코드내에 delay 매크로 함수를 만들어서 시간을 대입하고 있다
그 시간을 Timing Diagram에 맞게 최적화 시켰을 때 가장 효율적인 프로그램이 될 것이다
그럼 코드상의 delay 매크로 함수를 최적화 시키기 위해서 먼저 Timing Diagram을 보자
위에서 E cycle Time은  enable이 최소 한 사이클 동안 지연시켜야 할 시간이다
enable을 최초 up시킨후에 다시 up시킬때까지의 최소 한 사이클은 500nano second가 되어야 한다
다음은  E pulse width인데  E pulse는 up된 상태에서 최소 230nano second가 되어야 한다
그 다음 R/W and RS Setup Time은 RS와 R/W신호를 준후 E신호를 up시키기 전까지 최소 기다려 줘야 하는 시간이다
R/W and RS Hold Time은 E 신호가 하강한후 다시 R/W and RS 를 Setup시키기 전에 기다려 줘야 하는 최소한의 시간이다
아래의 Data SetupTime과 Data Hold Time은 E 신호의 하강 edge를 기준점으로 그 전 그리고 그 후에 반드시 기다려주어야 데이터가 정상적으로 읽힘을  알 수 있다 
아래의 Data SetupTime과 Data Hold Time를 코드상에서 구현해 보자

 CLCD_DELAY(5000);
 PIOA_SODR = Uiinst; //데이터를 넣음  
CLCD_DELAY(3000);   //Delay for  Data SetupTime
 PIOA_CODR= CLCD_EN;  //enable low( lcd non -choice)
 CLCD_DELAY(1000);  // Delay for  Data Hold Time
그 외에도 에지(신호의 상승또는 하강점)를 기준점으로 잡고 그 전후로  적절한 수준의 delay를 주어서 최적화시킨다
 *사용자 정의문자 출력
텍스트형 LCD 모듈에서 글자를 찍을 때 우리는 거의 CG ROM에 저장된 기본 문자 폰트를 이용하여 문자의 코드를 DD RAM에 써주기만 하면 자동으로 CG ROM에서 찾아 화면에 디스플레이 시켜주었다. (CG ROM의 문자코드는 문자의 아스키코드값과 일치)
그러나 기본적인 문자폰트가 아닌 자신의 문자를 만들기 위해서는CGRAM을 이용해야 한다 

CG RAM
    - 사용자 정의 문자를 지정하는데 사용하는 메모리
    - 5x7 도트를 사용하는 경우 초대 8문자까지 정의 가능
    - 사용자 정의 문자는 0x00~0x0F 영역에 할당되어 있는데 1문자가 2개의 코드 영역을 차지하기 때문에
       실제 코드 값은 0x00~0x07(또는 0x08~0x0F)로 사용
다음은 사용자 정의 문자를 사용하여 자신의 이름을 출력하는 프로그램이다
//cgram.c

접기

#define PIOA_PER    (*(volatile unsigned int *)0xFFFFF400)
#define PIOA_OER  (*(volatile unsigned int *)0xFFFFF410)
#define PIOA_PPUDR  (*(volatile unsigned int *)0xFFFFF460)
#define PIOA_CODR  (*(volatile unsigned int *)0xFFFFF434)
#define PIOA_SODR  (*(volatile unsigned int *)0xFFFFF430)

#define  CLCD_RS    (0X01<<8)
#define  CLCD_RW    (0X01<<9)
#define  CLCD_EN    (0X01<<10)
#define  CLCD_BS    (0XFF<<16)
//start of command  function
#define   CLCD_INST_CD    (0X01<<16)          //clear display
#define   CLCD_INST_FS     (0X38<<16)         //function set( 8bit(1),  2line(1),  5*8(0))
#define   CLCD_INST_EM     (0X06<<16)         //Entry mode(right direction(1),shift screen(0))
#define   CLCD_INST_DO    (0X0E<<16)          //display on
#define   CLCD_INST_CS    (0X14<<16)          //cursor shift
#define   CLCD_INST_RH    (0X02<<16)          //return home
#define   CLCD_INST_DD1   (0X80<<16)         //ddram  address setting (first line)
#define   CLCD_INST_DD2   (0XC0<<16)         //ddram  address setting (second line)
#define   CLCD_INST_CG   (0X40<<16)         //cgram  address setting 
#define   CLCD_DELAY(Z)       for(iCount =0;iCount <(Z);++iCount) //delay

void LCD_INST(unsigned int );
void LCD_DATA(unsigned int);

void LCD_INIT(void)
{
  // Configure the pin in output
  PIOA_OER  = CLCD_RS|CLCD_RW|CLCD_EN|CLCD_BS;
  // Set the PIO controller in PIO mode instead of peripheral mode
  PIOA_PER  = CLCD_RS|CLCD_RW|CLCD_EN|CLCD_BS;
  // Disable pull-up
  PIOA_PPUDR  =  CLCD_RS|CLCD_RW|CLCD_EN|CLCD_BS;
  PIOA_CODR  =0XFF<<16);   //pin input clear
}

int main(void)
{
  volatile unsigned int iCnt = 0;

   unsigned int pName[] = {
    0x040x0A, 0x110x110x110x0A, 0x040x00,    // 'ㅇ'  0x00
    0x110x110x110x1F, 0x110x110x1F, 0x00,    // 'ㅂ' 0x01
    0x010x010x0F, 0x010x0F, 0x010x010x00,    // 'ㅕ' 0x02
    0x000x1F,0x100x100x100x100x1F,  0x00,    // 'ㄷ' 0x03

    0x1F, 0x0A, 0x0A, 0x100x100x100x1F, 0x00,    // 'ㅠㄴ' 0x04
    0x040x0A, 0x110x110x110x0A, 0x040x00,    // 'ㅇ'  0x05
    0x000x000x000x040x040x040x1F, 0x00,    // 'ㅗ' 0x06

}; 

  

  LCD_INIT();

  LCD_INST(CLCD_INST_FS);
  LCD_INST(CLCD_INST_EM);
  LCD_INST(CLCD_INST_CS);
  LCD_INST(CLCD_INST_DO);
  LCD_INST(CLCD_INST_CD);
  LCD_INST(CLCD_INST_RH);


  LCD_INST(CLCD_INST_CG);
  for(iCnt=0; iCnt<56; ++iCnt){
    LCD_DATA(pName[iCnt]);
  }
  
  LCD_INST(CLCD_INST_DD1);  // DD RAM Address (첫라인 첫위치)
   LCD_DATA(0x00);      // 'ㅇ'  0x00

  LCD_INST(0x82<<16);  
   LCD_DATA(0x01);      //  'ㅂ' 0x01
   LCD_DATA(0x02);      //  'ㅕ' 0x02

 LCD_INST(0x85<<16);
   LCD_DATA(0x03);      //'ㄷ' 0x03




  LCD_INST(0xC0<<16);  // DD RAM Address (두번째 라인 첫위치)
  LCD_DATA(0x04);      // 'ㅠㄴ' 0x04

  LCD_INST(0xC3<<16);
  LCD_DATA(0x05);      // 'ㅇ'  0x05

  LCD_INST(0xC5<<16);
  LCD_DATA(0x06);      // 'ㅗ' 0x06




  
  while(1);
  return 0;
}

 void LCD_INST(unsigned int Uiinst)
{
  static volatile unsigned int iCount = 0//unsigned is faster than signed
  PIOA_CODR= CLCD_EN;  //enable low( lcd non -choice)
  PIOA_CODR = CLCD_RS; //instruction register을 선택
  PIOA_CODR  = CLCD_RW; // write 옵션 선택

  CLCD_DELAY(1000);


  PIOA_SODR= CLCD_EN;  //enable high(lcd choice)
  CLCD_DELAY(5000);
  PIOA_SODR = Uiinst; //인자로 들어온 명령실행
    CLCD_DELAY(3000);
  PIOA_CODR= CLCD_EN;  //enable low( lcd non -choice)
    CLCD_DELAY(1000);
  PIOA_CODR  =0XFF<<16);      //pin input clear
}
  void LCD_DATA(unsigned int Uiinst)
{
  static volatile unsigned int iCount = 0//unsigned is faster than signed
  PIOA_CODR= CLCD_EN;  //enable low( lcd non -choice)
  PIOA_SODR = CLCD_RS; //data register을 선택
  PIOA_CODR  = CLCD_RW; // write 옵션 선택
  CLCD_DELAY(1000);


  PIOA_SODR= CLCD_EN;  //enable high(lcd choice)
  CLCD_DELAY(5000);
  PIOA_SODR = (Uiinst<<16); //인자로 들어온 데이터 출력
  CLCD_DELAY(3000);
  PIOA_CODR= CLCD_EN;  //enable low( lcd non -choice)
  CLCD_DELAY(1000);
  PIOA_CODR  =0XFF<<16);  //pin input clear
}



*WINCHAR 메시지
윈도우즈 환경은  입력을 받는 함수가 블로킹상태에서 기다릴수 없는 메시지 처리방식이므로 입력 문자가 들어오면 운영체제는 포커스를 가진 컨트롤에 키보드 메시지를 보내는 방식으로 프로그램이 실행된다
여기서 포커스(Focus)를 가진 콘트롤이란 활성화되어 있는 윈도우(프로그램)에서 메시지를 받아들일 수 있는 컨트롤을 말한다.
아무리 여러개의 프로그램이 동시에 실행되는 멀티 태스킹 환경이라 하더라도 활성화될 수 있는 프로그램은 오직 하나밖에 없으며 활성화된 프로그램에서 단 하나의 콘트롤만 포커스를 가지고 키보드 입력을 받아들일 수 있다.


 

위에서 각각 프로세스의 메시지큐에서 GetMessage가 메시지를 꺼내어 보고  메시지가 WM_KEYDOWN인 경우 그 키 입력이 보통의 문자(화살키 등의 특수키 제외)인 경우 TranslateMessage가 WM_CHAR로 변경하여  DispatchMessageWndProc으로 보낸다
WM_CHAR 메시지는 입력된 문자의 아스키 코드를 wParam으로 전달하도록 되어 있으며 우리는 wParam의 값을 읽어 사용자가 어떤 키를 눌렀는지를 알아내게 된다. 예를 들어 사용자가 'S'키를 눌렀으면 wParam은 S의 아스키 코드값인 53h가 전달되며 이 값을 그대로 화면으로 출력하면 문자 S가 출력될 것이다. lParam에는 비트별로 다음과 같은 복잡한 정보가 전달된다.


이 정보 중 필요한 정보가 있으면 lParam을 참조하여 사용하면 되고 필요없으면 wParam만 사용한다
 WM_CHAR 메시지에서 lParam의 정보들을 사용해야 할 경우는 드물다. 메시지 별로 필요한 추가정보는 메시지와 함께 전달되는 wParam, lParam을 통해 넘어오는데 메시지별로 wParam과 lParam을 사용하는 방법은 다 다르다
*무효영역
WM_PAINT 메시지는 윈도우가 다시 그려져야 할 필요가 있을 때마다 호출되는데 다시 그려져야 할 필요가 있다는 말은 무효 영역(Invalid Region)이 있다는 뜻이다
무효하다는 말은 원래 그려져야 할 모습과는 다른 모습을 가지고 있다는 뜻이며 곧 다시 그려져야 할 필요가 있다는 의미이다. 윈도우즈는 어떤 윈도우가 무효 영역을 가지고 있으면 WM_PAINT 메시지를 보내주어 윈도우를 다시 그리도록 한다
 윈도우의 일부분이 가려졌다 나타나거나 최소화되었다가 복구되면 무효 영역이 발생하고 그때 마다 WM_PAINT 메시지를 받게 된다.
이런 식으로 윈도우즈는 윈도우의 일부가 지워졌을 때 지워진 작업 영역을 무효로 만들어 윈도우가 다시 그려지도록 해 준다. 마찬가지로 프로그램의 내부에서 윈도우의 모습을 변경시켰을 때(값의 변화 등)는 운영체제가 작업영역을 무효화하지 않고 프로그램 스스로 변경된 부분이 다시 그려질 수 있도록 강제로 무효화시켜 주어야 하며 이때 사용되는 함수가 바로 InvalidateRect이다.

BOOL InvlidateRect(HWND hWnd, CONST RECT *lpRect, BOOL bErase);

이 함수는 윈도우의 작업 영역을 무효화시켜 윈도우즈로 하여금 WM_PAINT 메시지를 해당 윈도우로 보내도록 한다. 첫번째 인수 hWnd는 무효화의 대상이 되는 윈도우, 즉 다시 그려져야 할 윈도우의 핸들이다. 이 값은 WndProc이 호출될 때 전달되는 첫번째 인수 hWnd를 그대로 써 주면 된다.
두번째 인수 lpRect는 무효화의 대상이 되는 사각 영역을 써 주되 이 값이 NULL이면 윈도우의 전 영역이 무효화된다. 전 영역을 무효화하면 윈도우가 완전히 다시 그려진다
세번째 인수 bErase는 무효화되기 전에 배경을 모두 지운 후 다시 그릴 것인지 아니면 배경을 지우지 않고 그릴 것인지를 지정한다. 이 값이 TRUE이면 배경을 지운 후 다시 그리고 FALSE이면 배경을 지우지 않은채로 다시 그린다.
Key 예제의 경우 문자열이 계속 늘어만 나며 지워져야할 문자가 없기 때문에 이 인수를 FALSE로 지정하였지만 지워져야할 부분이 있다면 이 인수는 TRUE가 되어야 한다. 예제를 다음과 같이 변경해 보자.

	case WM_CHAR:
		if ((TCHAR)wParam == 32) {
			str[0]=0;
		}
		else {
			len = strlen(str);
			str[len]=(TCHAR)wParam;
			str[len+1]=0;
		}
		InvalidateRect(hWnd,NULL,TRUE);
		return 0;

스페이스 키가 입력되었을 경우 문자열을 지우도록 하였다. 이렇게 되면 기존에 출력되어 있던 문자들이 지워져야 하므로 InvalidateRect의 세번째 인수는 TRUE가 되어야 한다

728x90