ON/OFF 제어는 조작량을 -100%와 +100%으로 하기 때문에
조작량의 변화가 너무 크고 목표값에 대해 지나치게 반복하여
목표값의 부근에서 큰 진동 모양으로 반복하는 제어 방식입니
다.

 

제어량이 목표값보다 크면 조작량을 -100%로

그 반대의 경우라면 조작량을 +100% 로 하면 됩니다.

 

   

 

 

 

 

수식

  

 

 

E: 편차(목표값- 제어량)

plus_minus(val1): val1 의 값이 양수이면 +1, 음수이면 -1

 

 

예를 들어 목표값이 200, 제어량이 220이라면 100% 로 냉각을 하게 됩니다.

조작량 = plus_minus(-20) *100 => -100

 

예를 들어 목표값이 200, 제어량이 199이라면 100% 로 가열을 하게 됩니다.

조작량 = plus_minus(1) *100 => +100

 

 

 

 

실험 동영상

 

 

'전자/일반' 카테고리의 다른 글

빵판에서 사용 가능한 푸쉬,리셋 스위치  (0) 2016.04.20
USB2.0 MINI 5p cable 미니5핀 케이블  (0) 2016.03.31
다양한 저항 종류 – 용량  (0) 2016.03.31
체리, ON/OFF 제어 방식  (2) 2012.11.28
PID 제어  (4) 2012.11.28
서보 모터 제어 방법  (1) 2012.11.15
Posted by WhiteAT

댓글을 달아 주세요

  1. 립쁜 2015.03.24 16:23  댓글주소  수정/삭제  댓글쓰기

    혹시 소스파일 제공가능하시나요?ㅜㅜㅜ

    semi1359@naver.com입니다

    • Favicon of https://avr128.com BlogIcon WhiteAT 2015.03.24 16:28 신고  댓글주소  수정/삭제

      실제 온도센서와 열전소자를 제어하는 키트와 연결하여
      실험할 수 있는 프로그램 입니다.

      자세한 내용은 http://whiteat.com/pWAT_CHERRY 를 참조하세요

PID 제어

전자/일반 2012. 11. 28. 12:16

 

자동제어 방식 중에 PID 제어가 있습니다. 

 

 

PID 제어란?


P: proportional(비례) 
I: Integral(적분) 
D: Differential(미분) 
의 3가지 조합으로 제어하는 방식으로 유연한 제어가 가능해 집니다.

 

 

 

ON/OFF 제어, P제어, PI 제어, PID 제어를 비교해 보겠습니다.

 

 

 

 

ON/OFF 제어



단순 ON/OFF 제어는 조작량을 -100%와 +100%으로 하기 때문에
조작량의 변화가 너무 크고 목표값에 대해 지나치게 반복하여
목표값의 부근에서 큰 진동 모양으로 반복하는 제어 방식입니다.

 

 

주변 온도가 15도이며 20도로 설정된 상태입니다.

처음 20도로 온도가 상승한 후 20도를 기준으로 진동을 하게 되는데 주변 온도가 15도라서 평균적으로 약 19도 정도를 유지하게 됩니다.

만약 주변온도가 10도라면 평균온도는 그 이하가 될 것입니다.

 

이 방식은 주변온도에 따라 평균 온도가 달라지며 순간순간의 조작량이 많아 효율이 좋지 않습니다.

 

 

 

 

P 제어



조작량을 목표값과 현재 값과의 차에 비례하게 하여 서서히 조절하는 제어 방법을 비례 제어라고 합니다.


이렇게 하면 목표값에 접근하면 좀더 세밀하게 제어를 가할 수 있기 때문에
ON/OFF 제어보다 세밀하게 목표값에 접근할 수 있습니다.

 

 

얼핏보면 ON/OFF 제어와 비슷해 보이지만 조작량의 최대값을 조절하여 진동폭을 줄일 수 있습니다. 진동폭이 작아져도 여전히 진동하는 문제가 있습니다.

 

 

 

 

PI 제어

 

P 제어 식에 에러의 누적 값을 더해 주면 좀더 안정적인 제어를 할 수 있습니다.

 

 

PI 제어는 빠르게 목표값에 도달한 듯 보이지만 마지막에 약간의 진동이 있습니다.

 

 

PID 제어

 


비례 제어만으로 제어가 잘 될 것이라 생각되겠지만 실제로는 제어량이 목표값에 접근하면 문제가 발생합니다. 조작량이 너무 작아지고, 그 이상 미세하게 제어할 수 없는 상태가 그러합니다.

결과는 목표값에 아주 가까운 제어량의 상태에서 안정한 상태로 될 수 있는데 비례제어만 사용하게 되면 목표값에 가까워지더라도 제어량과 완전히 일치하지 않는 상태로 되고 맙니다.


이 미소한 오차를 "잔류편차"라고 하는데 이 잔류편차를 없애기 위해 사용되는 것이 적분 제어입니다.
즉, 미소한 잔류편차를 시간적으로 누적하여, 그 누적값을 조작량에 증가하여 편차를 없애는 식으로 동작시킬수 있습니다.

이와 같이, 비례 동작에 적분 동작을 추가한 제어를 "PID 제어"라 합니다.

 

 

 

 

PID 제어로 빠르고 작은 진동으로 목표 값에 도달합니다.






Kd 을 0.01 로 했을 때







Kd 을 0.005 로 했을 때






PID 실험 키트


 

PID,CHERRY,실험,ON/OFF/P,PI,PID,제어,자동제어








출처: http://whiteat.com/1798


 

 

'전자/일반' 카테고리의 다른 글

빵판에서 사용 가능한 푸쉬,리셋 스위치  (0) 2016.04.20
USB2.0 MINI 5p cable 미니5핀 케이블  (0) 2016.03.31
다양한 저항 종류 – 용량  (0) 2016.03.31
체리, ON/OFF 제어 방식  (2) 2012.11.28
PID 제어  (4) 2012.11.28
서보 모터 제어 방법  (1) 2012.11.15
Posted by WhiteAT

댓글을 달아 주세요

  1. 한승묵 2013.05.08 19:52  댓글주소  수정/삭제  댓글쓰기

    잘보고 갑니다. 좋은 정보입니다.

  2. 2013.05.20 18:00  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

    • Favicon of https://avr128.com BlogIcon WhiteAT 2013.05.26 14:42 신고  댓글주소  수정/삭제

      http://whiteat.com/WhiteAT_Cherry 에서 프로그램(실행파일) 제공하며 시뮬레이션 프로그램이 아닙니다.

      WAT-CHERRY 라는 보드와 연결하여 실제로 PID 제어를 실험할수 있는 프로그램입니다.

  3. 빵쿠 2015.12.02 18:48  댓글주소  수정/삭제  댓글쓰기

    감사합니다!!
    실질적으로 p i d 에 각각 어느정도 값을 넣는지 찾고 있었어요 ㅎㅎㅎ

 

 

16x2 라인의 캐릭터 LCD 를 제어해 보겠습니다.

 

 

< ATMEGA128 과 캐릭터 LCD 연결 회로도 일부 >

 

 

 

 

 

 

 

LCD 의 데이터 선은 ATMEGA128의 PORTB 에 연결하고, 컨트롤 선은 PORTC를 사용합니다.

VR1의 5K 가변 저항은 캐릭터 LCD의 백라이트 밝기를 조절할 수 있습니다.

 

 

캐릭터 LCD 우측 그림처럼 출력하는 예제입니다.

abcdefghijklmnop

0123456789ABCDEF

 

 

 

 

 

 

 

 

원문은 http://whiteat.com 에 있습니다.

 

 

 

 

주요 코드

 

main.c 일부

/*

    EX_02_01.c

 

    필요한보드

    1. WAT-AVR128 (모듈)

    2. WAT-AVR128 EXT (확장보드)

    3. WAT-CLCD (캐릭터그래픽LCD)

 

    Character LCD에영문/숫자출력

    AVRStudio 4.18

    2011-10-04

 

    홈페이지: http://whiteat.com

    MCU자료실: http://avr128.com

    쇼핑몰: http://kit128.com

 

*/

 

#include <avr/io.h>

#include "WAT128.h"

 

int main()

{

 

    CLCD_Init();        // LCD 초기화

 

    CLCD_PutChar('a');

    CLCD_PutString(1,0,"bcdefghijklmnop");

    CLCD_PutString(0,1,"0123456789ABCDEF");

 

    while(1)

    {

    }

}

 

 

 

 

 

 

 

전체 소스 ( AVRStudio용)

EX_02_01.ZIP

 

 

Posted by WhiteAT

댓글을 달아 주세요

 

 

컴파일하여 생성된 결과 파일(헥사파일)을 다음과 같은 방법으로 라이팅 할 수 있습니다.

- Ponyprog 프로그램과 프린터 포트를 이용








 

< PONYPROG 실행 화면 >

 

 

 

 


http://www.lancos.com                  <= 여기에서 다운로드할 수 있다.

http://www.lancos.com/ppwin95.html     <= 조금더 자세한 주소

 



< PONYPROG 프로그램 기본적인 사용 방법 >
먼저 사용하는 Device Family 를 선택한다.

 

 

 

 

 

다음으로 사용하는 Device Type 를 선택한다.

 

 

 

 

 

다음으로 프로그램을 라이팅에 사용할 포트을 선정한다.
아래는 병렬 포트(LPT1)으로 셋팅하는 예이다.

 

 < PONYPROG 프로그램 FUSE 셋팅 >

 

 

 

 


하드웨어에 맞게 비트를 설정해 주어야 한다.

아래 메뉴를 선택하여 Configuration Bilts 창을 연다.

 

 

 

 

 

 

아래 예는 8Mhz 로 외부 XTAL 를 사용하는 설정이다.

 

 

 

 

 

 

< PONYPROG 프로그램 라이팅 >
기본적인 세팅은 끝났으며 이제 헥사파일을 라이팅 하면 된다.
메뉴를 선택한 후

 

 

 

 

 

라이팅할 헥사 파일을 열고,

 

 

 

 

메뉴를 선택하여 라이팅하면 라이팅이 진행됩니다.

 

     

 



=======================================================================================
Writing 속도 빠르게 하는 방법

PonyProg(Parallel Port) ISP가 느려서 사용하지 않는 분들은
한번, 하기 사항을 참고해 보시기 바랍니다.

1. 사용프로그램: PonyProg v2.06f
2. ISP형식: Parallel Port
3. 사용MCU: ATmega128
4. 사용환경: WindowsXP
-> PonyProg2000디렉토리에 들어 있는
     PONYPROG2000.INI 파일 설정중에서
     SPIBusSpeed=NORMAL을 SPIBusSpeed=FAST로 변경하니
     ISP Writing속도가 2배 정도 향상 되었습니다.







http://kit128.com/goods/view.php?seq=9 에서
케이블을 포함하여 6,600원에 저렴하게 판매하고 있습니다.







Posted by WhiteAT

댓글을 달아 주세요




컴파일하여 생성된 결과 파일(헥사파일)을 다음과 같은 방법으로 라이팅 할 수 있습니다.

- Ponyprog 프로그램과 프린터 포트를 이용

- AVRStudio 프로그램과 WAT-AVR ISP ( USB 용 AVR ISP)를 이용

 



 



 

하드웨어 연결

 

 

 

그림처럼 AVR 모듈과 USB ISP 케이블을 연결하고 USB ISP 케이블을 PC의 USB 포트에 연결합니다.




 

 

 

 

 

이 내용에 대한

원본은 http://WhiteAT.com 에서 제공하는 WAT-AVR128 모듈 매뉴얼에 있습니다.

저작권은 http://WhiteAT.com 에 있습니다.

 

 



PL2303 드라이버(XP, 윈도우7 공용) 

    PL2303_Prolific_DriverInstaller_v1.5.0.zip
드라이버 제작사인 http://www.prolific.com.tw/eng/downloads.asp?ID=31 에서도 다운로드 가능합니다.





 

 

프로그램 연결

 

 

 

AVRStudio STK500 도구바에서 ‘Display the Connect Dialog' 버튼을 클릭하면 ISP 연결 설정에 관한 다이어로그 박스가 나타납니다.

 



 

 

  

 

Platform에서 AVRISP 를 선택하고 Port에서 연결된 포트 번호를 선택한 후 [Connect]를 클릭합니다. 연결을 성공하면 프로그램라이팅에 관련된 다이어로그박스가 뜨게 되고 연결이 실패하면 다시 선택하라고 같은 창이 뜹니다.

지금까지는 ISP 케이블에 AVR 모듈을 연결하지 않아도 상관없습니다.

 





 

 

 

 

 

 

 

 

디바이스 설정

 

 

[Device and Signature Bytes]에서 사용할 디바이스명을 선택하고 [Settings]에서 적당한 라이팅 속도를 결정합니다.

 

 

 

 

 

 

 

 

 

 

 

프로그램 라이팅

 

 

 

[...]으로 헥사파일을 선택한 후 [Program]으로 라이팅을 할 수 있습니다.


 








 

 

 

 

FUSE( 퓨즈) 설정

 

 


 

아래와 같이 설정할 수 있습니다. 가장 많이 사용되는 설정이며 필요에 따라 변경할 수 있습니다.

 

 

 

 

 

 

 

 

 

 

 

 

에러 발생시

 

 

만약 다음과 같은 에러가 발생한다면 AVR 모듈이 연결되었는지 확인하고 연결되어 있다면 SCK 속도를 낮춰가며 적당한 라이팅 속도를 찾아야 합니다.

 

 









 

 

현재 AVRStudio 에서는 총 6가지의 ISP 라이팅 속도를 제공합니다.

 

 

 




 




 

이 제품은 http://kit128.com/goods/view.php?seq=4&main=true&mainType=1 에서 구매하실 수 있습니다.



 

Posted by WhiteAT

댓글을 달아 주세요

 

 

ATMEGA128 컨트롤러의 컴파일툴은 AVRStudio, Codevision, IAR 등이 있습니다. 이러한 컴파일툴의 대부분 유료이며 잘 알려진 무료 컴파일툴은 AVR Studio입니다. Codevision 은 유료이나 코드위저드가 있어 초기에 코드 생성할 때 편리합니다. IAR 은 주로 업체에서 사용되는 컴파일툴입니다.

 

 

소스 컴파일툴

 

 

AVRStudio 와 WinAVR 로 컴파일 할 수 있습니다. AVRStudio 는 코딩하는데 편리한 환경을 제공하고 WinAVR 은 컴파일러를 제공합니다.

 

 

프로그램 다운로드

http://www.atmel.com 에 가입 후 AVRStudio 프로그램을 다운받을 수 있습니다.

http://winavr.sourceforge.net/ 에서 가입 없이 WinAVR을 다운받을 수 있습니다.

 

 

 

프로그램 설치

먼저 WinAVR을 설치한 후 AVRStudio를 설치합니다.

 

AVRStudio 는 컴파일을 쉽게 도와주는 툴을 제공하고

WinAVR 은 여러 헤더파일과 라이브러리와 컴파일러(AVR-gcc)를 제공합니다.

 

 

 

 

 

 

먼저 새로운 프로젝트를 생성한다.

 

 

 

 

 

 

다음으로 프로젝트명을 결정 한다

 

 

 

 

 

 

 

 

Finish를 눌러 종료하면, 이제 소스를 편집할 수 있는 창이 열린다.

이제 코딩하면 된다.

 

 

 

 

 

 

간단하게 소스를 편집하고,

#include <avr/io.h>

 

int main(){

DDRB = 0xFF; // output

PORTB = 0xFF; // LED ON

return 0;

 

}

 

 

 

 

 

 

Build and Run 를 실행하여 test1.hex 파일이 생성되었는지 확인합니다.

라이팅 하는 방법은 http://whiteat.com/56165 에 있습니다.

 

출처: http://whiteat.com/260 

 

 

 

Posted by WhiteAT

댓글을 달아 주세요

 

PORTA의 0 ~ 7 포트에 LED 8개가 연결되어 있고 LED에 불이 들어오게 하려면 해당되는 포트에 '0'을 출력하면 됩니다. 딥스위치 1번을 ON 하면 D0(PORTA.0에 연결된 LED)부터 D7까지 차례대로 ON되고 딥스위치 1번을 OFF 하면 마지막 켜진 LED부터 OFF 되는 예제입니다.

 

 

DIP SWITCH 1번 ON

D0: ●○○○○○○○

D1: ●●○○○○○○

D2: ●●●○○○○○

D3: ●●●●○○○○

D4: ●●●●●○○○

D5: ●●●●●●○○

DIP SWITCH 1번 OFF

D4: ●●●●●○○○

D3: ●●●●○○○○

D2: ●●●○○○○○

D1: ●●○○○○○○

D0: ●○○○○○○○

PORTA 에 LED, PORTE에는 딥스위치가 연결되며, 실험에 사용할 회로와 WAT보드의 연결 방법은 아래와 같습니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

원문은 http://avr128.com 에 있습니다.

 






 

 

 

 

 

주요 코드

 

main.c 일부

/*

    EX_01_03.c

 

    PORTA의0 ~ 7 포트에LED 8개가연결되어있고

    LED에불이들어오게하려면해당되는포트에

    ''을출력하면됩니다.

    

    딥스위치1번을ON 하면

    D0(PORTA.0에연결된LED)부터D7까지차례대로ON되고

    딥스위치1번을OFF 하면마지막켜진LED부터OFF 되는

    예제입니다.

 

    LED: PORTA 에연결

    DIP SWITCH: PORTE 에연결

         

 

    AVRStudio 4.18

    2011-08-25

 

    최신코드와다른예제는홈페이지에있습니다.

    http://avr128.com

 

*/

 

#include <avr/io.h>

 

// 일정시간딜레이

void Delay()

{

    register unsigned long i;

    for(i = 0; i < 300000; i++)

    {

        asm volatile(" PUSH R0 ");

        asm volatile(" POP R0 ");

        asm volatile(" PUSH R0 ");

        asm volatile(" POP R0 ");

        asm volatile(" PUSH R0 ");

        asm volatile(" POP R0 ");

        asm volatile(" PUSH R0 ");

        asm volatile(" POP R0 ");

        asm volatile(" PUSH R0 ");

        asm volatile(" POP R0 ");    

    }

}

 

int main()

{

    DDRA = 0xFF;     // PORTA OUTPUT

    PORTA = 0xFF;    //    ALL LED OFF

 

    DDRE = 0x00;        // DIP SWITCH 용으로입력

 

    while(1)

    {

 

        Delay();

 

        if((PINE & 0x01) == 0x00)

        {

 

            // DIP 1 이ON 이면

            PORTA <<= 1;

            PORTA |= 0;        // 마지막LED 는ON 되게

        

        }

        else

        {

 

            //     DIP 1이OFF 이면

            PORTA >>=1;

            PORTA |=0x80;    // 처음LED 는OFF 되게

 

        }    

    }

}

 

 

 

 

 

 

전체 소스 ( AVRStudio 컴파일용)

 

 

 




Posted by WhiteAT

댓글을 달아 주세요

 

그래픽 LCD 에 영문, 원, 사각형 선(라인)을 출력 하는 예제입니다.

 

 

 

 

 

 

원문은 http://avr128.com 에 있습니다.

 

 

 

 

주요 코드

 

main.c 일부

/*

    

필요한보드

    1. WAT-AVR128 (모듈)

    2. WAT-AVR128 EXT (확장보드)

    3. WAT-GLCD (모노그래픽LCD)

 

기능

    그래픽LCD 에사각형, 원, 라인을그린다.

 

 

    http://avr128.com

 

    

    2011-08-10 : 사각형, 원, 라인그리기기능추가

 

*/

 

 

#include <avr/io.h>

#include "WAT128.h"

 

 

#ifdef _USE_GLCD_

#include "gfont.h"

#endif

 

 

int main(){

 

    int i=0;

 

 

//    OpenSCI0(57600); // 디버깅포트

 

    GLCD_Init();

    GLCD_String(0,0," AVR128.com");

 

 

    // 외각선(사각형) 그리기

    GLCD_DrawRect(0,0,127,63);

 

    // 대각선그리기

    GLCD_DOT_Line(0,0,127,63);

    GLCD_DOT_Line(0,63,127,0);

 

    // 원그리기

    GLCD_DOT_DrawCircle(64,32,10);

    GLCD_DOT_DrawCircle(32,32,14);

    GLCD_DOT_DrawCircle(96,32,14);

 

    while(1)

    {

 

    }

}

 

 

 

 

 

 

wat128.h 일부

// 점찍기

void GLCD_SetPixel(int x1,int y1,BOOL _b);

 

// 라인그리기

void GLCD_DOT_Line(int x1,int y1,int x2,int y2);

 

// 원그리기

void GLCD_DOT_DrawCircle(int x1,int y2,int _size);//

 

// 사각형그리기

void GLCD_DrawRect(int x1,int y1,int x2,int y2);

 

 

 

 

 

wat128.c 일부

 

void GLCD_SetPixel(int x1,int y1,BOOL _b)

{

    BYTE byteCS = 0;

    BYTE byteData;

 

    if(x1>=128 || y1>=64)

        return;

 

    if(x1<64 )

    {

        byteCS = 0x01;    

    }

    else

    {

        x1 = x1%64;

        byteCS = 0x02;

    }

 

 

    GLCD_Command(byteCS,0x40 + x1);    // x 좌표지정

    GLCD_Command(0x00,0xB8 + y1/8);    // y 좌표지정

 

 

    GLCD_ReadData(byteCS); //read 하면처음에이상한값이나온다;; 그냥버림

    

 

    byteData = GLCD_ReadData(byteCS);

 

    if(_b==1)

        byteData |= 1<<(y1%8);

    else

        byteData &= ~(1<<(y1%8));

 

    GLCD_Command(byteCS,0x40 + x1);    // x 좌표지정

    GLCD_Command(0x00,0xB8 + y1/8);    // y 좌표지정

 

    GLCD_WriteData(byteCS, byteData,0);

 

}

 

 

void GLCD_DOT_Line(int x1,int y1,int x2,int y2)

{

    int i;

    int y=y1;

    for(i=x1;i<=x2;i++)

    {

        if(y1 <y2)

            y = y1+(i-x1)*(y2-y1)/(x2-x1);

        else

            y = y1-(i-x1)*(y1-y2)/(x2-x1);

        GLCD_SetPixel(i,y,1);

    }

 

}

 

void GLCD_DOT_DrawCircle(int x1,int y1,int _size)

{

    int i;

    int j;

    int y=0;

    int Lasty=0;// dot 간의간격이클경우임의의선을그려준다.

 

    for(i=x1-_size;i<=x1+_size;i++)

    {

        y= round(sqrt((_size*_size )-(i-x1)*(i-x1)));

 

        GLCD_SetPixel(i,y1+y,1);

        GLCD_SetPixel(i,y1-y,1);

 

        if(Lasty !=0)

        {

            // 좌측처리

            if(Lasty +1< y1+y)

            {

                // dot 사이의간격이너무벌어진것이다.

                for(j=1;j<(y1+y)-Lasty;j++)

                {

 

                    GLCD_SetPixel(i-1,y1-y+j,1);    // 좌측상단

                    GLCD_SetPixel(i-1,y1+y-j,1);// 좌측하단에끊어진부분

 

                    //sprintf(g_temp,"\r\nLasty:%dm j:%d",Lasty,j);

                    //PutString0(g_temp);

 

                }

 

            }

            // 우측처리

             else if(Lasty -1 > y1+y)

            {

                // dot 사이의간격이너무벌어진것이다.

                for(j=1;j<Lasty - (y1+y);j++)

                {

                    sprintf(g_temp,"\r\nLasty:%dm i:%d, j:%d, y1+y-j:%d",Lasty,i,j,y1+y-j);

                    PutString0(g_temp);

 

                     GLCD_SetPixel(i,y1-y-j,1);// 우측상단

                     GLCD_SetPixel(i,y1+y+j,1);// 우측하단에끊어진부분

 

 

                }

 

            }

 

        }

 

        Lasty = y1+y;

    }

}

 

void GLCD_DrawRect(int x1,int y1,int x2,int y2)

{

 

    int i=0;

    for(i=x1;i<=x2;i++)

    {

        GLCD_SetPixel(i,y1,1);

        GLCD_SetPixel(i,y2,1);

 

    }

    for(i=y1+1;i<=y2-1;i++)

    {

        GLCD_SetPixel(x1,i,1);

        GLCD_SetPixel(x2,i,1);

 

    }

 

 

 

}

 

 

 

 

 

전체 소스

 



Posted by WhiteAT

댓글을 달아 주세요

 

 

 

그래픽 LCD 에 커서 있는 영문을 출력 하는 예제입니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

원문은 http://avr128.com 에 있습니다.

 

 

 







주요 코드

 

wat128.h 일부

 

 

#define GLCD_CS1 0    // 좌측LCD 선택

#define GLCD_CS2 1    // 우측LCD 선택

#define GLCD_RST 2    // RESET

#define GLCD_RW 3    // Read/Write

#define GLCD_RS 4    // Command/Data

#define GLCD_EA 5    // Enable

 

 

 

 

 

#define SET_EA    SetBit(GLCD_CONTROL_PORT,GLCD_EA)

#define CLR_EA    ClearBit(GLCD_CONTROL_PORT,GLCD_EA)

 

#define SET_CS1    SetBit(GLCD_CONTROL_PORT,GLCD_CS1);

#define CLR_CS1    ClearBit(GLCD_CONTROL_PORT,GLCD_CS1);

#define SET_CS2    SetBit(GLCD_CONTROL_PORT,GLCD_CS2);

#define CLR_CS2    ClearBit(GLCD_CONTROL_PORT,GLCD_CS2);

 

#define SET_RS    SetBit(GLCD_CONTROL_PORT,GLCD_RS);

#define CLR_RS    ClearBit(GLCD_CONTROL_PORT,GLCD_RS);

 

 

#define GLCD_DATA_PORT    PORTA        // DATA 레지스터

#define GLCD_DATA_PORT_DIR    DDRA    // DATA 방향레지스터

#define GLCD_DATA_INPUT    PINA        // DATA 입력레지스터

 

 

#define GLCD_CONTROL_PORT    PORTB    // CONTROL 레지스터

#define GLCD_CONTROL_PORT_DIR    DDRB    // CONTROL 방향레지스터

 

 

struct _POSITION_

{

    UINT8 x;    // X 좌표

    UINT8 y;    // Y 좌표

};

 

// GLCD 관련구조체

struct _GLCD_INFO_

{

    struct _POSITION_ pos;            // 현재출력중인좌표

    struct _POSITION_ posCursor;    // 커서위치

    UINT8 ShowCursor;                // 커서를보여줄것인지/아닌지

};

 

 

 

struct _GLCD_INFO_ g_GLCD;    // GLCD 구조체

 

 

 

void GLCD_Init();            // GLCD 초기화

void GLCD_Clear();            // GLCD 화면초기화

void GLCD_Command(BYTE byteSignal,BYTE byteCommand);    // COMMAND

void GLCD_SetXY(BYTE x, BYTE y);        // 좌표이동

void GLCD_SetXY_ROW(struct _POSITION_ pos,BYTE row);    // DATA 관련좌표이동

 

void GLCD_WriteData(BYTE byteSignal,BYTE byteChar,BYTE bBlock);    // 데이터쓰기

BYTE GLCD_ReadData(BYTE byteSignal);                            // 데이터읽기

void GLCD_English(BYTE Ecode,BYTE bBlock);                        // 영문출력

void GLCD_Korean(UINT16 Kcode,BYTE byteBlock)    ;                // 한글출력

void GLCD_String(BYTE x,BYTE y,BYTE const *string);                // 문자열출력

void GLCD_ShowCursor(UINT8 _show);                            // 커서를show/hide 한다.

void GLCD_RemoveCursor();                                    // 현재커서를안보이게한다.(제거한다)

 

 

 

 

 

wat128.c 일부

 

 

extern prog_uchar E_font[128][16];

 

extern prog_uint16_t KSTable[2350] ;

 

extern prog_uchar table_cho[21];

extern prog_uchar table_joong[30];

extern prog_uchar table_jong[30];

 

extern prog_uchar bul_cho1[22];

extern prog_uchar bul_cho2[22];

extern prog_uchar bul_jong[22];

 

extern prog_uchar K_font[360][32] ;

 

 

void GLCD_Init()

{

 

    SetBit(GLCD_CONTROL_PORT_DIR,GLCD_CS1);

    SetBit(GLCD_CONTROL_PORT_DIR,GLCD_CS2);

    SetBit(GLCD_CONTROL_PORT_DIR,GLCD_RST);

    SetBit(GLCD_CONTROL_PORT_DIR,GLCD_RW);

    SetBit(GLCD_CONTROL_PORT_DIR,GLCD_RS);

    SetBit(GLCD_CONTROL_PORT_DIR,GLCD_EA);

 

 

    GLCD_DATA_PORT_DIR = 0xFF;

 

    ClearBit(GLCD_CONTROL_PORT,GLCD_RST);

    DelayUS(10);

 

    SetBit(GLCD_CONTROL_PORT,GLCD_RST);

 

    ClearBit(GLCD_CONTROL_PORT,GLCD_RW);

 

 

    g_GLCD.pos.x = 0;

    g_GLCD.pos.y = 0;

 

 

    g_GLCD.ShowCursor = 0;

    

    g_GLCD.posCursor.x = 0;

    g_GLCD.posCursor.y = 0;

 

    CLR_EA;

    CLR_CS1;

    CLR_CS2;

    CLR_RS;

 

    GLCD_Command(0x00,0x3F);    // CS1, CS2 display ON

    GLCD_Command(0x00,0xC0);    // CS1, CS2 display position

 

 

    DelayMS(1);

 

    GLCD_String(0,0," ");

    GLCD_String(1,0," ");

    GLCD_String(2,0," ");

    GLCD_String(3,0," ");

 

}

 

 

void GLCD_Command(BYTE byteSignal,BYTE byteCommand){

 

    // E=0, DI = 0;

    CLR_EA;

    CLR_RS;

 

 

    if(0x02 == (byteSignal&0x02))

    {

        SET_CS1;

    }

    else

    {

        CLR_CS1;

    }

    if(0x01 == (byteSignal&0x01))

    {

        SET_CS2;

    }

    else

    {

        CLR_CS2;

    }

 

 

    DelayUS(1);

    GLCD_DATA_PORT = byteCommand;

 

 

    SET_EA;

    CLR_EA;

 

 

 

    SET_CS1;

    SET_CS2;

    DelayUS(1);

 

 

}

 

// x,y 좌표를사용자가변경할수있다.

void GLCD_SetXY(BYTE x, BYTE y)

{

    g_GLCD.pos.x = x;

    g_GLCD.pos.y = y;

 

}

 

// 문자의세로길이는16bit 라서위/아래를나누어출력해야한다.

// 문자출력시위/아래

// x : x position

// y : y position

// row 0: upper

//        1: lower

void GLCD_SetXY_ROW(struct _POSITION_ pos,BYTE upperrow)

{

    if(upperrow == 0)                    // 출력한문자의데이터가위쪽이면

        GLCD_Command(0x00,0xB8 + pos.x*2);

    else                                // 출력한문자의데이터가아래쪽이면

        GLCD_Command(0x00,0xB8 + pos.x*2 + 1);

 

    if(pos.y <= 7)                    // 좌측LCD 이면

        GLCD_Command(0x01,0x40 + pos.y*8);

    else                            // 우측LCD 이면

        GLCD_Command(0x02,0x40 + (pos.y-8)*8);

}

 

 

void GLCD_WriteData(BYTE byteSignal,BYTE byteChar,BYTE bBlock){

 

    if(1 == bBlock)

    {

        byteChar = ~byteChar;

    }

 

    CLR_EA;

    SET_RS;

 

 

    if(0x02 == (byteSignal&0x02))

    {

        SET_CS1;

    }

    else

    {

        CLR_CS1;

    }

    if(0x01 == (byteSignal&0x01))

    {

        SET_CS2;

    }

    else

    {

        CLR_CS2;

    }

 

 

    DelayUS(1);

 

    GLCD_DATA_PORT = byteChar;                

 

    SET_EA;

    CLR_EA;

 

    SET_CS1;

    SET_CS2;

 

    DelayUS(1);

}

 

BYTE GLCD_ReadData(BYTE byteSignal)

{

    BYTE byteChar;

    CLR_EA;

    SET_RS;

 

    SetBit(GLCD_CONTROL_PORT,GLCD_RW);

    GLCD_DATA_PORT_DIR = 0x00;

 

    if(0x02 == (byteSignal&0x02))

    {

        SET_CS1;

    }

    else

    {

        CLR_CS1;

    }

    if(0x01 == (byteSignal&0x01))

    {

        SET_CS2;

    }

    else

    {

        CLR_CS2;

    }

 

    DelayUS(1);

 

 

    SET_EA;

    CLR_EA;

    byteChar = GLCD_DATA_INPUT;

    GLCD_DATA_PORT_DIR = 0xFF;

 

    ClearBit(GLCD_CONTROL_PORT,GLCD_RW);

 

 

    SET_CS1;

    SET_CS2;

 

    return byteChar;

}

 

// 8x16 크기의영문출력

void GLCD_English(BYTE Ecode,BYTE bBlock)    

{

    BYTE i, byteCS;

 

    if(g_GLCD.pos.y <= 7)        // 좌측LCD 선택    

        byteCS = 0x01;

    else                        // 우측LCD 선택    

        byteCS = 0x02;

 

    if(g_GLCD.ShowCursor==1)

    {

        GLCD_RemoveCursor();

    }

 

    // 먼저세로의크기16중상단8개만출력

    GLCD_SetXY_ROW(g_GLCD.pos,0);        

 

 

 

    for(i = 0; i <= 7; i++)

    {

        GLCD_WriteData(byteCS, pgm_read_byte(&E_font[Ecode][i]),bBlock);

    }

 

 

 

    // 세로의크기16중하단8개만출력

    GLCD_SetXY_ROW(g_GLCD.pos,1);    

 

    for(i = 8; i <= 15; i++)

    {

        if((g_GLCD.ShowCursor == 1))

        {

            // 커서를출력한다면

            g_GLCD.posCursor = g_GLCD.pos;

            GLCD_WriteData(byteCS,pgm_read_byte(&E_font[Ecode][i]) | 0x80,bBlock);

        }

        else

            GLCD_WriteData(byteCS,pgm_read_byte(&E_font[Ecode][i]),bBlock);

    }

 

 

    g_GLCD.pos.y++;

    if(g_GLCD.pos.y == 16)

    {

        g_GLCD.pos.y = 0;

        if(++g_GLCD.pos.x >=4) g_GLCD.pos.x=0;

    }

}

 

// 16x16 크기의한글출력

void GLCD_Korean(UINT16 Kcode,BYTE byteBlock)

{

    BYTE i, byteCS;

    BYTE cho_5bit, joong_5bit, jong_5bit;

    BYTE cho_bul, joong_bul, jong_bul=0, jong_flag;

    unsigned int character;

    BYTE Korean_buffer[32];    // 임시버퍼

 

    if(g_GLCD.pos.y == 15)                // 마지막1칸이라면공백을출력하고다음으로.

        GLCD_English(0x20,byteBlock);

 

 

    if(g_GLCD.pos.y <= 7)        // 좌측LCD 선택    

        byteCS = 0x01;

    else                        // 우측LCD 선택    

        byteCS = 0x02;

 

 

 

    // 일단초성/중성/종성을얻고

    cho_5bit = table_cho[(Kcode >> 10) & 0x001F];

    joong_5bit = table_joong[(Kcode >> 5) & 0x001F];

    jong_5bit = table_jong[Kcode & 0x001F];

 

    if(jong_5bit == 0)                // 종성이없을경우

    {

        jong_flag = 0;

        cho_bul = bul_cho1[joong_5bit];

        if((cho_5bit == 1) || (cho_5bit == 16)) joong_bul = 0;

        else joong_bul = 1;

    }

    else                        // 종성이있다면

    {

        jong_flag = 1;

        cho_bul = bul_cho2[joong_5bit];

        if((cho_5bit == 1) || (cho_5bit == 16)) joong_bul = 2;

        else joong_bul = 3;

        jong_bul = bul_jong[joong_5bit];

    }

 

 

    // 초성데이터값가져오기

    character = (UINT16)cho_bul*20 + (UINT16)cho_5bit;        

    for(i = 0; i <= 31; i++)

        Korean_buffer[i] = pgm_read_byte(&K_font[character][i]);

 

 

    // 중성데이터가져와서합치기

    character = (UINT16)8*20 + (UINT16)joong_bul*22 + (UINT16)joong_5bit;

    for(i = 0; i <= 31; i++)

        Korean_buffer[i] |= pgm_read_byte(&K_font[character][i]);

 

    // 종성이있을경우합치기

    if(jong_flag == 1)        

    {

        character = (UINT16)8*20 + (UINT16)4*22 +(UINT16)jong_bul*28 + (UINT16)jong_5bit;

        for(i = 0; i <= 31; i++)

            Korean_buffer[i] |= pgm_read_byte(&K_font[character][i]);

    }

 

 

 

    // 반전추가예정

    //     if(TRUE == byteBlock){

    //         for(i = 0; i <= 31; i++)

    //             Korean_buffer[i] = ~Korean_buffer[i];

    //     }

 

    // 16 x16 크기에서좌측상단출력

    GLCD_SetXY_ROW(g_GLCD.pos,0);        // 상단8 출력

    for(i = 0; i <= 7; i++)

        GLCD_WriteData(byteCS,Korean_buffer[i],byteBlock);

 

    // 16 x16 크기에서좌측하단출력

    GLCD_SetXY_ROW(g_GLCD.pos,1);        

    for(i = 16; i <= 23; i++)

    {

        if(g_GLCD.ShowCursor == 1)

            GLCD_WriteData(byteCS,Korean_buffer[i] | 0x80,byteBlock);

        else

            GLCD_WriteData(byteCS,Korean_buffer[i],byteBlock);

    }

 

 

 

 

 

 

    g_GLCD.pos.y++;

 

    // 16 x16 크기에서우측상단출력

    GLCD_SetXY_ROW(g_GLCD.pos,0);        // display upper right row

    for(i = 8; i <= 15; i++)

        GLCD_WriteData(byteCS,Korean_buffer[i],byteBlock);

 

 

    // 16 x16 크기에서우측하단출력

    GLCD_SetXY_ROW(g_GLCD.pos,1);        

    for(i = 24; i <= 31; i++)

    {

        if(g_GLCD.ShowCursor == 1)

            GLCD_WriteData(byteCS,Korean_buffer[i] | 0x80,byteBlock);

        else

            GLCD_WriteData(byteCS,Korean_buffer[i],byteBlock);

    }

 

    g_GLCD.pos.y++;

    if(g_GLCD.pos.y == 16)

    {

        g_GLCD.pos.y = 0;

        g_GLCD.pos.x++;

    }

}

 

 

 

 

void GLCD_String(BYTE x,BYTE y,BYTE const *string)    

{

    BYTE character1;

    unsigned int character2;

 

 

    g_GLCD.pos.x = x;

    g_GLCD.pos.y = y;    

 

 

    while(*string != '\0')

    {

        character1 = *string;

        string++;

        if(character1 < 0x80)

            GLCD_English(character1,FALSE);        

        else

        {

            character2 = 256*character1 + (*string & 0xFF);

            string++;

            GLCD_Korean(character2,0);    

        }

    }

}

 

 

void GLCD_ShowCursor(UINT8 _show)

{

    g_GLCD.ShowCursor = _show;

}

 

 

void GLCD_RemoveCursor()

{

    BYTE byteData[8];

    BYTE byteCS=0;

 

    if(g_GLCD.ShowCursor == 0)

        return;

 

    GLCD_SetXY_ROW(g_GLCD.posCursor,1);

 

    if(g_GLCD.posCursor.y <= 7)    // 좌측화면이면

        byteCS = 0x01;

    else                    

        byteCS = 0x02;

 

 

 

    GLCD_ReadData(byteCS);

    byteData[0] = GLCD_ReadData(byteCS);

    if(byteData[0] & 0x80 )

    {

        // 커서가black 이면

        byteData[0] &= 0x7F;

        byteData[1] = GLCD_ReadData(byteCS) & 0x7F;

        byteData[2] = GLCD_ReadData(byteCS) & 0x7F;

        byteData[3] = GLCD_ReadData(byteCS) & 0x7F;

        byteData[4] = GLCD_ReadData(byteCS) & 0x7F;

        byteData[5] = GLCD_ReadData(byteCS) & 0x7F;

        byteData[6] = GLCD_ReadData(byteCS) & 0x7F;

        byteData[7] = GLCD_ReadData(byteCS) & 0x7F;    }

    else

    {

        // 커거서white이면(주로문자의블럭지정에서사용)

        byteData[0] |= 0x80;

        byteData[1] = GLCD_ReadData(byteCS) | 0x80;

        byteData[2] = GLCD_ReadData(byteCS) | 0x80;;

        byteData[3] = GLCD_ReadData(byteCS) | 0x80;

        byteData[4] = GLCD_ReadData(byteCS) | 0x80;

        byteData[5] = GLCD_ReadData(byteCS) | 0x80;;

        byteData[6] = GLCD_ReadData(byteCS) | 0x80;

        byteData[7] = GLCD_ReadData(byteCS) | 0x80;

    }

      

 

 

 

    GLCD_SetXY_ROW(g_GLCD.posCursor,1);

    GLCD_WriteData(byteCS,byteData[0],0);

    GLCD_WriteData(byteCS,byteData[1],0);

    GLCD_WriteData(byteCS,byteData[2],0);

    GLCD_WriteData(byteCS,byteData[3],0);

    GLCD_WriteData(byteCS,byteData[4],0);

    GLCD_WriteData(byteCS,byteData[5],0);

    GLCD_WriteData(byteCS,byteData[6],0);

    GLCD_WriteData(byteCS,byteData[7],0);

 

}

 

 

 

main.c

/*

    

필요한보드

    1. WAT-AVR128 (모듈)

    2. WAT-AVR128 EXT (확장보드)

    3. WAT-GLCD (모노그래픽LCD)

 

기능

    그래픽LCD 에커서있는영문을표시한다.

 

 

    http://avr128.com

 

    

    2011-08-08 : 주석추가

 

*/

 

 

#include <avr/io.h>

#include "WAT128.h"

 

 

#ifdef _USE_GLCD_

#include "gfont.h"

#endif

 

 

int main(){

 

    int i=0;

 

 

    GLCD_Init();

    GLCD_ShowCursor(1); // 커서를 보이게 하자.

 

    GLCD_SetXY(0,0);

    GLCD_String(0,0,"AVR128.com ");

 

    while(1)

    {

        // 약200ms 마다커서가있는'E' 출력

         GLCD_English('E',0);

        DelayMS(200);

    }

}

 

Posted by WhiteAT

댓글을 달아 주세요

 

 

WAT-KEY 4x4 예제

 

WAT-KEY 4x4 배열을 PC 에서 실시간으로 모니터링 하는 예제

http://avr128.com/27

 

 

 

 

WAT-IO&ADC 예제

 

로터리 스위치의 값을 FND 4자리 중 제일 앞자리에 표시하는 예제

http://avr128.com/25

 

가변 저항의 값에 따라 LED 를 켜는 예제

http://avr128.com/24

 

 

 

Posted by WhiteAT

댓글을 달아 주세요