Atmega128을 이용하여 CLCD를 구동해보자. 꼭 mega128을 사용하지 않아도 된다. 있는게 128이라서.... 나중에 핀 할당만 다시해주면 된다. 나는 CLCD모델 LMC1623A를 가지고 설명하겠다. 모델마다 데이터시트가 다르니 여기 있는글과 똑같이하면 안될수도 있다. 하지만 다른제품도 거의 비슷하게 되어있다. 그리고 8bit 기준으로 설명하겠다. 갑자기 8bit라니 무슨 말인지 모르겠지... 데이터핀을 8개 쓰니까 8bit다. 핀 아낄려면 핀 4개만 연결해주면 된다. 그러면 4bit가 되는것이다.
먼저 CLCD가 atmega128에 어떻게 연결되어있는지 회로도를 보자.
위(15, 16번 핀),아래(1,2,3번 핀)에 있는 가변저항은 백라이트와 글자농도를 조정해준다.
Data PIN에는 일반포트 8개 전부 순서대로(LCD pin14:7 -> PORTx7:x0) 물리면 되고 Control PIN도 일반 핀
3개를 연결시켜주면 회로구성은 끝이다.
이제 데이터시트를 보자. 데이터시트는 사용법과 같은 놈이다. 대부분 회사마다 제품에대한 데이터시트를 제공한다.
데이터시트에서 핀 설명부분을 캡쳐해보았다.
대충 각 핀이 뭐하는 놈인지 설명해준다. LCD 4,5,6번 핀의 이름은 각각 RS, R/W, E이다. 잘 기억 해놓자. 핵심이다. 이제 동작에 대해 알아보자. 타이밍도 라는것이 나오는데 LCD를 사용하기 위해서는 데이터시트에서 제공해주는 타이밍도를 잘 보고 코드를 작성해야한다.
보자마자 머리가 아프다.저게 뭔가 싶고....하지만 걱정하지 마라. 의외로 간단하다. Control PIN(RS, R/W, E)을 위와 동일하게 맞춰주면 된다. 나는 RS, R/W, E를 각각 PE7, PE5, PE3으로 연결해주고 데이터핀은 PORTA에 연결했다고 가정하면 다음과같이 소스를 작성해주면 된다.
void LCD_data(unsigned char Data)
{
_delay_ms(1);
PORTE = 0b10000000; //RS set. RW clear. E clear.
_delay_us(0.05); //RW & RS Setup time is 40ns min.
PORTE = 0b10001000; // E set.
_delay_us(0.1); //Data Setup time is 80ns min.
PORTA = Data; // Data input.
_delay_us(0.5); // valid data min is 130ns.
PORTE = 0b00100000; // RS clear. RW set. E clear.
}
하지만 이게 끝이 아니다. 이렇게 쓰기 쉬웠다면 블로그에 자료정리 하지도 않았다. 설정같은걸 해줘야 한다.
LCD에 글자를 뿌릴때 어느 위치에서 시작할지, 커서는 표시할건지 말건지, 커서가 켜진다면 깜빡이게 할건지 말건지 등등... 설정해줄게 좀 있다. 자세한 내용은 아래 데이터시트를 참고하자.
설정을 해줄때는 RS핀이 0(LOW 상태)이라는 것을 알아두자. 설정을 위한 함수를 LCD_data함수처럼 만들어보자.
void LCD_controller(unsigned char control)
{
_delay_ms(30);
PORTE = 0x00; //RW clear.
_delay_us(0.05); //RW & RS Setup time is 40ns min.
PORTE = 0b00001000; // E set.
_delay_us(0.1); //Data Setup time is 80ns min.
PORTA = control; // Data input.
_delay_us(0.3); // valid data is 130ns min.
PORTE = 0b10100000; // RS set. RW set. E clear.
}
이해가 되지않으면 이해 될 때까지 반복학습을 하면 된다. 확실하다. 반복학습이 좀 짱인듯?
LCD를 사용하기 전에는 항상 초기화라는 것을 해주는것이 좋다. 초기화 과정은 아래와 같다.
초기화 하는것도 함수로 만들어 버리자.
void LCD_initialize(void)
{
/* 8bit interface mode */
_delay_ms(50);
LCD_controller(0x3c); // Function set. Use 2-line, display on.
_delay_us(40); // wait for more than 39us.
LCD_controller(0x0f); // Display ON/OFF Control. display,cursor,blink on
_delay_us(40); // wait for more than 39us.
LCD_controller(0x01); // Display Clear.
_delay_ms(1.53); // wait for more than 1.53ms.
LCD_controller(0x06); // Entry Mode Set. I/D increment mode, entire shift off
}
입력할 데이터는 한글자씩 LCD에 뿌려줘야 하니까 LCD_string도 만들어주자.
void LCD_string(unsigned char address, unsigned char *Str)
{
int i=0;
LCD_controller(address); // LCD display start position
while(*Str != '\0')
{
if(address+i == 0x90)
LCD_controller(0xc0); // second line display
LCD_data(*Str);
i++;
Str++;
}
}
인자값으로 2개가 들어가는데 address는 글자를 찍어줄 위치다. LCD 맨처음 위치는 0x80이고 1씩 증가하면서 다음칸
으로 이동한다. 16X2칸을 가지는 LCD의 주소는 다음과 같다.
0x80 |
0x81 |
0x82 |
0x83 |
0x84 |
0x85 |
0x86 |
0x87 |
0x88 |
0x89 |
0x8A |
0x8B |
0x8C |
0x8D |
0x8E |
0x8F |
0xC0 |
0xC1 |
0xC2 |
0xC3 |
0xC4 |
0xC5 |
0xC6 |
0xC7 |
0xC8 |
0xC9 |
0xCA |
0xCB |
0xCC |
0xCD |
0xCE |
0xCF |
즉 0,0인 지점이 0x80이 되는 것이다.
두 번째 인자값으로 포인터가 나온다 ㅎㄷㄷ... 그냥 시작주소를 알려주기 위함이니 어려워할 필요는 없다.
문자열이니까 끝에 NULL을 만날때까지 while문을 돌면서 LCD_data()함수에 주소값을 넣어준다.
그리고 한줄에 16글자가 들어갈 수 있으니까 첫번째 줄에서 위치 0x8F를 넘어가는 경우 0xC0로 넘긴다.
모든 준비가 끝났다. 위에서 만든 함수를 이용해서 what the hell..o world를 띄어보자.
#include "avr/io.h"
#include "avr/iom128.h"
#include "util/delay.h"
void LCD_controller(unsigned char control)
{
_delay_ms(30);
PORTE = 0x00; //RW clear.
_delay_us(0.05); //RW & RS Setup time is 40ns min.
PORTE = 0b00001000; // E set.
_delay_us(0.1); //Data Setup time is 80ns min.
PORTA = control; // Data input.
_delay_us(0.3); // valid data is 130ns min.
PORTE = 0b10100000; // RS set. RW set. E clear.
}
void LCD_data(unsigned char Data)
{
_delay_ms(1);
PORTE = 0b10000000; //RS set. RW clear. E clear.
_delay_us(0.05); //RW & RS Setup time is 40ns min.
PORTE = 0b10001000; // E set.
_delay_us(0.1); //Data Setup time is 80ns min.
PORTA = Data; // Data input.
_delay_us(0.5); // valid data min is 130ns.
PORTE = 0b00100000; // RS clear. RW set. E clear.
}
void LCD_string(unsigned char address, unsigned char *Str)
{
int i=0;
LCD_controller(address); // LCD display start position
while(*Str != '\0')
{
if(address+i == 0x90)
LCD_controller(0xc0); // second line display
LCD_data(*Str);
i++;
Str++;
}
}
void LCD_initialize(void)
{
/* 8bit interface mode */
_delay_ms(50);
LCD_controller(0x3c); // Function set. Use 2-line, display on.
_delay_us(40); // wait for more than 39us.
LCD_controller(0x0f); // Display ON/OFF Control. display,cursor,blink on
_delay_us(40); // wait for more than 39us.
LCD_controller(0x01); // Display Clear.
_delay_ms(1.53); // wait for more than 1.53ms.
LCD_controller(0x06); // Entry Mode Set. I/D increment mode, entire shift off
}
int main()
{
DDRE = 0xff; // Control_bit
DDRA = 0xff; // Data_bit
LCD_initialize(); // 초기화 한번 때려주고
LCD_string(0x80, "what the hell..o world"); // Start address is 0x80(0,0)
return 0;
}
잘 나온다. 총 32글자가 넘어가면 짤린다는 것에 유의하자. 안짤리고 화면시프트 할 수도 있는데 그건 자기가 알아서
공부하자.
'Embedded System > AVR' 카테고리의 다른 글
[AVR] SPI 통신 (15) | 2017.04.02 |
---|---|
[AVR] 모터드라이버 변경!!(V6 엔진 장착) (2) | 2017.04.02 |
[AVR] 소형 모터드라이버 만들기 (4) | 2017.04.02 |
[AVR] ADC 사용하기(13.11.25 코드 수정) (29) | 2017.04.02 |
[AVR] USART 직렬통신 하기(시리얼통신) (17) | 2017.04.02 |