Character LCD 실습
Download
Report
Transcript Character LCD 실습
마이크로콘트롤러응용설계 - 2
character LCD
시스템및센서네트워크연구실
1
ATmega128
시스템및센서네트워크연구실
2
LED sink / switch pullup 회로
470
5V
PC0
+5V
PC1
…..
10K
PC7
PD2
104 (0.1uF)
시스템및센서네트워크연구실
3
시스템및센서네트워크연구실
4
16*2 character LCD
16*2 character LCD
5V 단일전원으로 구동
5*7 또는 5*10 도트의 폰트로 문자를 표시
인터페이스가 표준화되어 있기 때문에 uC에 쉽게 연결 가능
8비트 또는 4비트 데이터 버스 방식으로 구동
CGRAM (Character Generator RAM), CGROM (Character Generator ROM),
DDRAM (Data Display RAM)을 내장하고 있음
시스템및센서네트워크연구실
5
핀 정의
#1
+5V
VDD
#2
LCD 밝기 조절
V0
RS
R/W
E
PC0
PC1
PC2
DB4
DB5
DB6
DB7
PC4
PC5
PC6
PC7
VSS
#3
시스템및센서네트워크연구실
+5V
LEDA
LEDK
6
LCD 기본 동작
레지스터
LCD에는 8비트의 인스트럭션 레지스터(IR)과 데이터 레지스터(DR)이
있음
IR : DDRAM과 CGRAM에 대한 어드레스 설정, 메모리 클리어, display
on/off, 커서 이동 등에 대한 명령어 코드를 가짐
DR : DDRAM과 CGRAM에 써넣은 데이터나 읽은 데이터를 일시적으로
저장하는 역할
RS와 R/W에 의하여 제어됨
RS R/W
0
0
IR 쓰기 동작
0
1
busy flag와 address counter (AC) 읽기
1
0
DR 쓰기 동작 : DR -> DDRAM, CGRAM
1
1
DR 읽기 동작 : DR <- DDRAM, CGRAM
시스템및센서네트워크연구실
7
Busy Flag (BF)
LCD 모듈이 다음 명령을 받을 수 있는 지를 나타냄
• BF = 1 : LCD는 내부 동작 수행 중이므로 다음 명령 받을 수 없음
• BF = 0 : 다음 명령을 받을 수 있음
Address Counter (AC)
DDRAM이나 CGRAM의 어드레스를 지정할 때 사용
IR에 어드레스 셋 명령어를 쓰면 IR에서 AC로 어드레스 정보가 전송됨
DDRAM과 CGRAM은 명령어에 의하여 선택
DDRAM이나 CGRAM에 디스플레이 데이터를 쓰면 AC는 자동으로 +1
또는 -1이 됨
시스템및센서네트워크연구실
8
DDRAM (Display Data RAM)
LCD 화면(16*2)에 출력되는 문자를 저장하는 RAM
8비트 문자 데이터를 각 행별로 40문자씩 저장
1행은 0x00 – 0x27, 2행은 0x40 – 0x67의 어드레스를 가짐
각 행은 40문자씩 저장하지만, LCD에는 16문자씩 동시에 출력 가능
따라서, 쉬프트 동작을 이용하여 DDRAM의 해당 어드레스를 LCD에 출
력해야 함
• 초기 상태
0x00 – 0x0F
0x40 – 0x4F
• 0x21 출력하려면, 전체 행을 왼쪽 2문자 쉬프트
0x02-0x0F, 0x20, 0x21
0x42-0x4F, 0x50, 0x51
시스템및센서네트워크연구실
9
CGROM (Character Generator ROM)
LCD에 사전에 정의되어 있는 8비트 문자 코드
ASCII 코드로 정의되어 있음
• 예) a : 01100001, A : 01000001
• 프로그램에서는 문자를 그대로 이용할 수 있
음
LCD에 표시할 문자의 코드값만 DDRAM에 써주
면, LCD는 문자코드에 해당하는 문자 패턴을 출
력
CGRAM (Character Generator RAM)
사용자가 정의하는 문자의 패턴을 저장하기 위한
RAM
시스템및센서네트워크연구실
10
LCD 명령어
LCD 제어 명령어
시스템및센서네트워크연구실
11
Clear display
LCD 화면 clear 후
커서 home(1행 1열)으로 이동, DDRAM의 AC (address counter) 0으로 셋
Return home
커서 home으로 이동, DDRAM의 AC 0으로 셋
Entry mode set
커서의 움직이는 방향 설정 및 디스플레이의 쉬프트 가능하게 함
커서 이동
• I/D=1 & S=0 : 커서 우측 이동 방향 설정
• I/D=0 & S=0 : 커서 좌측 이동 방향 설정
디스플레이 쉬프트
• I/D=1 & S=1 : display 좌 쉬프트 가능 설정
• I/D=0 & S=1 : display 우 쉬프트 가능 설정
• S=0 : display 쉬프트 불가
시스템및센서네트워크연구실
12
Display On/Off control
Display(D), cursor(C), blinking of cursor(B) 설정
D=1 : LCD 전체가 on되어 글자 표시
C=1 : 커서가 나타남
B=1 : 커서의 깜박임 동작
Cursor or display shift
커서 이동 및 display 쉬프트 조정
S/C R/L
0 0 : cursor 위치 좌로 이동, AC는 -1
0 1 : cursor 위치 우로 이동, AC는 +1
1 0 : display와 cursor 좌로 이동
1 1 : display와 cursor 우로 이동
시스템및센서네트워크연구실
13
Function set
DL : interface data length 설정
• DL=1 – 8비트, DL=0 – 4비트
• DL=0일 때 DB7-DB4가 사용되며, 상위 4비트, 하위 4비트 순서로 전
송
N : display line 수 설정
• N=0 – 1라인 표시, N=1 – 2라인 표시
F : display font type 설정
• F=0 – 5*10 도트 (N=1일 때만 사용 가능), F=1 – 5*8 도트
Set CGRAM address
CGRAM의 address 설정
Address 설정 후 CGRAM의 데이터 읽고 쓸 수 있음
시스템및센서네트워크연구실
14
Set DDRAM address
DDRAM의 어드레스 설정
Address 설정 후 DDRAM의 데이터 읽고 쓸 수 있음
Read busy flag and address counter
BF : 내부 동작 상태를 알 수 있는 비지 플래그
• BF = 1 : 내부 동작이 진행 중이라 명령을 받아들일 수 없음
• BF = 0 : 명령을 받아들일 수 있음
AC : address counter의 값을 읽을 수 있음
Write data to RAM
DDRAM 또는 CGRAM에 데이터를 쓸 수 있음
Read data from RAM
DDRAM 또는 CGRAM으로부터 데이터를 읽을 수 있음
시스템및센서네트워크연구실
15
LCD 프로그램
LCD 함수 정의
void LCD_init(void) : LCD 초기화 함수
• 사양에서 정의된 시간만큼 안정화 동작을 가짐
• 초기화 명령어 세팅
void Command(unsigned char) : instruction 쓰기 함수
• RS=0 -> RW=0 -> delay -> E(enable signal)=1 -> delay -> E=0
• 상위 4비트, 하위 4비트 순으로 수행
void Data(unsigned char) : 데이터 쓰기 함수
• RS=1 -> RW=0 -> delay -> E=1 -> delay -> E=0
• 상위 4비트, 하위 4비트 순으로 수행
void Busy(void) : Busy Flag Check
• BF를 체크하지 않고 일정 시간 지연
void LCD_String(char flash *) : 문자열 출력 함수
시스템및센서네트워크연구실
16
// LCD 초기화 함수
void LCD_init(void)
{
DDRC = 0xFF;
PORTC &= 0xFB;
// 포트 C 출력 설정
//E = 0;
// 인스트럭션 쓰기 함수
void Command(unsigned char byte)
{
Busy();
// 인스트럭션 상위 바이트
PORTC = (byte & 0xF0);
PORTC &= 0xFE;
PORTC &= 0xFD;
delay_us(1);
PORTC |= 0x04;
delay_us(1);
PORTC &= 0xFB;
// 충분한 지연시간을 통한 안정화 과정
delay_ms(15);
Command(0x20);
// D5=1
delay_ms(5);
Command(0x20);
// D5=1
delay_us(100);
Command(0x20);
// D5=1
// 초기화 과정
Command(0x28);
Command(0x06);
Command(0x01);
Command(0x0c);
// 인스트럭션 하위 바이트
PORTC = ((byte<<4) & 0xF0);
PORTC &= 0xFE;
PORTC &= 0xFD;
delay_us(1);
PORTC |= 0x04;
delay_us(1);
PORTC &= 0xFB;
// function set
// entry mode set
// all clear
// display on
}
// 데이터
// RS = 0;
// RW = 0;
// E = 1;
// E = 0;
// 데이터
// RS = 0;
// RW = 0;
// E = 1;
// E = 0;
}
시스템및센서네트워크연구실
17
// 문자열 출력 함수
//데이터 쓰기 함수
void Data(unsigned char byte)
{
Busy();
void LCD_String(char flash str[])
// 데이터 상위 바이트
PORTC = (byte & 0xF0);
PORTC |= 0x01;
PORTC &= 0xFD;
delay_us(1);
PORTC |= 0x04;
delay_us(1);
PORTC &= 0xFB;
{
char flash *pStr=0;
pStr = str;
while(*pStr) Data(*pStr++);
}
// 데이터 하위 바이트
PORTC = ((byte<<4) & 0xF0);
PORTC |= 0x01;
PORTC &= 0xFD;
delay_us(1);
PORTC |= 0x04;
delay_us(1);
PORTC &= 0xFB;
// char flash : pointer declaration for program memory
// char eeprom : pointer declaration for EEPROM
// 데이터
//RS = 1;
//RW = 0;
//E = 1;
//E = 0;
// 데이터
//RS = 1;
//RW = 0;
//E = 1;
//E = 0;
}
// Busy Flag Check -> 일반적인 BF를 체크하는 것이 아니라
// 일정한 시간 지연을 이용한다.
void Busy(void)
{
delay_ms(2);
시스템및센서네트워크연구실
}
18
실습 1
// Hello!!
// Atmel ATmega128 출력
#include <mega128.h>
#include <delay.h>
#define LINE2
#define HOME
0xC0
0x02
// 2nd Line Move
// Cursor Home
void LCD_init(void);
void LCD_String(char flash str[]);
void Busy(void);
void Command(unsigned char);
void Data(unsigned char);
void main(void)
{
LCD_init();
Command(HOME);
LCD_String("Hello!!");
Command(LINE2);
LCD_String("Atmel ATmega128");
// 첫번째 라인에 출력
// 두번째 라인에 출력
while(1);
}
// 앞에 5개 함수 원형 추가
시스템및센서네트워크연구실
19
실습 2
// 두 라인에 문자열 출력 -> 1초간 LCD on -> 1초간 LCD off -> 1초간 LCD on -> 1초 간격으로 16번 오른쪽으로 이동
#include <mega128.h>
#include <delay.h>
#define LINE2
#define HOME
#define RSHIFT
#define LSHIFT
#define DISPON
#define DISPOFF
0xC0
0x02
0x1C
0x18
0x0c
0x08
// 2nd Line Move
// Cursor Home
// Display Right Shift
// Display Left Shift
// Display On
// Display Off
while(1){
Command(HOME);
LCD_String("Hello!!");
Command(LINE2);
LCD_String("Atmel ATmega128");
void LCD_init(void);
void LCD_String(char flash str[]);
void Busy(void);
void Command(unsigned char);
void Data(unsigned char);
delay_ms(1000);
Command(DISPOFF);
delay_ms(1000);
Command(DISPON);
delay_ms(1000);
void main(void)
{
int i;
// 16번 오른쪽으로 쉬프트
for(i=0;i<16;i++) {
Command(RSHIFT);
delay_ms(1000);
}
LCD_init();
// 첫 번째 라인에 출력
// 두 번째 라인에 출력
// 1초 시간 지연
// Display Off
// 1초 시간 지연
// Display On
// 1초 시간 지연
}
}
시스템및센서네트워크연구실
20
실습 3
// 첫번째 라인에 문자열 표시한 후 좌측으로 계속 이동시키는 프로그램 작성
// include, define, function 원형 선언 공통
void main(void)
{
LCD_init();
// 첫 번째 라인에 출력
Command(HOME);
LCD_String("Hello!! -- Atmel ATmega128");
delay_ms(1000);
// 1초 시간 지연
while(1){
Command(LSHIFT);
delay_ms(500);
// Display Left Shift
// 0.5초 시간 지연
}
}
시스템및센서네트워크연구실
21
실습 4
// LCD의 첫번째 라인에 Value : XX 표시
// SW1을 누르면 1감소, SW2를 누르면 1 증가 (0-59까지 출력)
// 외부 인터럽트0 서비스 루틴
interrupt [EXT_INT0] void external_int0(void)
{
int num = 0;
num++;
if(num > 59) num = 0;
void main(void)
{
int N10=0, N1=0;
DDRD = 0b00000000;
EIMSK = 0b00000011;
EICRA = 0b00001010;
SREG = 0b10000000;
delay_ms(1);
}
// PD0, PD1 입력 설정 (SW1, SW2)
// 외부 인터럽트0, 1 인에이블
// 외부 인터럽트0, 1 하강 에지
// 전역 인터럽트 인에이블 비트 셋
// 외부 인터럽트1 서비스 루틴
interrupt [EXT_INT1] void external_int1(void)
{
num--;
if(num < 0) num = 59;
LCD_init();
delay_ms(1);
while(1){
// while(1) : 무한 루프
Command(HOME);
LCD_String(“Value : ”);
N10 = num / 10;
N1 = num % 10;
// 10자리 추출
// 1자리 추출
Data(0x30 + N10);
// 0x30 – ‘0’에 대한 ASCII 코드값
// 즉, 1을 출력하려면 0x31을 출력해야 함
}
Data(0x30 + N1);
}
} 시스템및센서네트워크연구실
22
실습 5
// 외부 인터럽트0 서비스 루틴
// SW1을 누르면, Computer의 랜덤 숫자 출력,
// SW2를 누르면 User의 랜덤 숫자 출력, 두 값을 비교하여 결과 출력
{
#include <stdlib.h>
interrupt [EXT_INT0] void external_int0(void)
Command(HOME);
num1 = (char) (rand() % 8);
LCD_String(“Com : ”);
Data(0x30 + num1);
// 선언부에 stdlib.h 함수 추가
int num1=0, num2=0;
delay_ms(1);
void main(void)
{
DDRD = 0b00000000;
EIMSK = 0b00000011;
EICRA = 0b00001010;
SREG = 0b10000000;
}
// PD0, PD1 입력 설정 (SW1, SW2)
// 외부 인터럽트0, 1 인에이블
// 외부 인터럽트0, 1 하강 에지
// 전역 인터럽트 인에이블 비트 셋
// 외부 인터럽트1 서비스 루틴
interrupt [EXT_INT1] void external_int1(void)
{
num2 = (char) (rand() % 8);
LCD_String(“ User : ”);
Data(0x30 + num2);
LCD_init();
while(1);
// while(1) : 무한 루프
}
Command(LINE2);
if(mum1 > num2)
LCD_String (“Com is win”);
if(mum2 >= num1)
LCD_String (“User is win”);
}
시스템및센서네트워크연구실
23
실습 6
Data(0x30 + min10);
Data(0x30 + min1);
LCD_String(“: ”);
Data(0x30 + sec10);
Data(0x30 + sec1);
// LCD를 이용한 간이시계 제작
int sec=0, minn=0, loc=0;
void main(void)
{
int i, min10, min1, sec10, sec1;
DDRD = 0b00000000; // PD0, PD1 입력 설정 (SW1, SW2)
EIMSK = 0b00000011; // 외부 인터럽트0, 1 인에이블
EICRA = 0b00001010; // 외부 인터럽트0, 1 하강 에지
SREG = 0b10000000; // 전역 인터럽트 인에이블 비트 셋
delay_ms(1000);
// 대략 1초를 기다림
}
}
// 외부 인터럽트0 서비스 루틴
interrupt [EXT_INT0] void external_int0(void)
{
if(loc == 0) sec++;
LCD_init();
if(loc == 1) sec += 10;
while(1){
// while(1) : 무한 루프
Command(HOME);
LCD_String(“Time : ”);
sec++;
if(sec >= 60) {
sec = 0;
minn++;
if(minn >= 60)
minn = 0;
}
min10 = minn / 10;
// 분의 10자리 추출
min1 = minn % 10;
// 분의 1자리 추출
sec10 = sec / 10;
// 초의 10자리 추출
시스템및센서네트워크연구실
sec1 = sec % 10;
// 초의 1자리 추출
if(loc == 2) minn++;
if(loc == 3) minn += 10;
if(sec > 59) sec -= 60;
if(minn > 59) minn -= 60;
}
// 외부 인터럽트1 서비스 루틴
interrupt [EXT_INT1] void external_int1(void)
{
loc = (loc + 1) % 4;
}
24