|
LCD 모듈의 내부블럭도 |
||||||||||||||||||||||||||||||||||||||||
일반적인 LCD 모듈에서 사용하는 LCD 콘트롤러의 내부 구조는 아래 그림과 같이 구성되어 있으며, 사용자에게 필요한 부분만 간단히 살펴보기로 한다. |
||||||||||||||||||||||||||||||||||||||||
LCD 내부 레지스터 |
||||||||||||||||||||||||||||||||||||||||
·
IR(Instruction
Register) 레지스터 ·
DR(Data
Register) 레지스터 |
||||||||||||||||||||||||||||||||||||||||
LCD 핀 사양 및 기능 선택 |
||||||||||||||||||||||||||||||||||||||||
|
|
|
|
3. 소스코드
module CLCD_test(
clk20m,
reset,
lcd_en,
lcd_rs,
lcd_rw,
lcd_data
);
input clk20m;
input reset;
output lcd_en;
output lcd_rs;
output lcd_rw;
output [7:0] lcd_data;
reg clk_1khz;
reg [17:0] cnt_1khz;
reg [3:0] dit0;
reg [3:0] dit1;
reg [3:0] dit2;
reg [3:0] dit3;
always @(posedge reset or posedge clk20m)
begin
if(reset == 1'b1)
cnt_1khz <= 0;
else if(cnt_1khz == 9999) begin // --(1)
cnt_1khz <= 0;
clk_1khz <= !clk_1khz;
end else begin
cnt_1khz <= cnt_1khz + 1;
end
end
character_lcd character_lcd
(
.clk_1khz_bufg (clk_1khz),
.reset (reset),
.lcd_en (lcd_en),
.lcd_rs (lcd_rs),
.lcd_rw (lcd_rw),
.lcd_data (lcd_data)
);
endmodule
module character_lcd(
clk_1khz_bufg,
reset,
lcd_en,
lcd_rs,
lcd_rw,
lcd_data
);
input clk_1khz_bufg;
input reset;
output lcd_en;
output lcd_rs;
output lcd_rw;
output [7:0] lcd_data;
reg [8:0] lcd_cnt;
wire [7:0] lcd_state;
reg [7:0] lcd_db;
parameter [7:0] LCD_BLANK = 8'b00100000;
parameter [7:0] LCD_DASH = 8'b00101101;
parameter [7:0] LCD_COLON = 8'b00111010;
parameter [7:0] LCD_PERIODE = 8'b00101110;
parameter [7:0] LCD_EQUAL = 8'b00111101;
parameter [7:0] LCD_0 = 8'b00110000;
parameter [7:0] LCD_1 = 8'b00110001;
parameter [7:0] LCD_2 = 8'b00110010;
parameter [7:0] LCD_3 = 8'b00110011;
parameter [7:0] LCD_4 = 8'b00110100;
parameter [7:0] LCD_5 = 8'b00110101;
parameter [7:0] LCD_6 = 8'b00110110;
parameter [7:0] LCD_7 = 8'b00110111;
parameter [7:0] LCD_8 = 8'b00111000;
parameter [7:0] LCD_9 = 8'b00111001;
parameter [7:0] LCD_A = 8'b01000001;
parameter [7:0] LCD_B = 8'b01000010;
parameter [7:0] LCD_C = 8'b01000011;
parameter [7:0] LCD_D = 8'b01000100;
parameter [7:0] LCD_E = 8'b01000101;
parameter [7:0] LCD_F = 8'b01000110;
parameter [7:0] LCD_G = 8'b01000111;
parameter [7:0] LCD_H = 8'b01001000;
parameter [7:0] LCD_I = 8'b01001001;
parameter [7:0] LCD_J = 8'b01001010;
parameter [7:0] LCD_K = 8'b01001011;
parameter [7:0] LCD_L = 8'b01001100;
parameter [7:0] LCD_M = 8'b01001101;
parameter [7:0] LCD_N = 8'b01001110;
parameter [7:0] LCD_O = 8'b01001111;
parameter [7:0] LCD_P = 8'b01010000;
parameter [7:0] LCD_Q = 8'b01010001;
parameter [7:0] LCD_R = 8'b01010010;
parameter [7:0] LCD_S = 8'b01010011;
parameter [7:0] LCD_T = 8'b01010100;
parameter [7:0] LCD_U = 8'b01010101;
parameter [7:0] LCD_V = 8'b01010110;
parameter [7:0] LCD_W = 8'b01010111;
parameter [7:0] LCD_X = 8'b01011000;
parameter [7:0] LCD_Y = 8'b01011001;
parameter [7:0] LCD_Z = 8'b01011010;
parameter [7:0] LCD_UNDER = 8'b01011111;
parameter [7:0] LCD_S_a = 8'b01100001;
parameter [7:0] LCD_S_b = 8'b01100010;
parameter [7:0] LCD_S_c = 8'b01100011;
parameter [7:0] LCD_S_d = 8'b01100100;
parameter [7:0] LCD_S_e = 8'b01100101;
parameter [7:0] LCD_S_f = 8'b01100110;
parameter [7:0] LCD_S_g = 8'b01100111;
parameter [7:0] LCD_S_h = 8'b01101000;
parameter [7:0] LCD_S_i = 8'b01101001;
parameter [7:0] LCD_S_j = 8'b01101010;
parameter [7:0] LCD_S_k = 8'b01101011;
parameter [7:0] LCD_S_l = 8'b01101100;
parameter [7:0] LCD_S_m = 8'b01101101;
parameter [7:0] LCD_S_n = 8'b01101110;
parameter [7:0] LCD_S_o = 8'b01101111;
parameter [7:0] LCD_S_p = 8'b01110000;
parameter [7:0] LCD_S_q = 8'b01110001;
parameter [7:0] LCD_S_r = 8'b01110010;
parameter [7:0] LCD_S_s = 8'b01110011;
parameter [7:0] LCD_S_t = 8'b01110100;
parameter [7:0] LCD_S_u = 8'b01110101;
parameter [7:0] LCD_S_v = 8'b01110110;
parameter [7:0] LCD_S_w = 8'b01110111;
parameter [7:0] LCD_S_x = 8'b01111000;
parameter [7:0] LCD_S_y = 8'b01111001;
parameter [7:0] LCD_S_z = 8'b01111010;
always @(posedge clk_1khz_bufg or posedge reset)
begin
if(reset == 1'b1)
lcd_cnt <= 0;
else if(lcd_cnt == 9'b001111000) //=> 8'b001111010 = 3C // --(2)
lcd_cnt <= 9'b000110100; // => 8'b00011010 = 1A
else
lcd_cnt <= lcd_cnt + 1;
end
assign lcd_state = lcd_cnt[8:1]; // --(3)
always @*
begin
case (lcd_state) // --(4)
// rw=0, rs=0
8'h00 : lcd_db = 8'b00111000; // function set(8bit interface, 5*7 dot) -15ms delay
8'h0A : lcd_db = 8'b00111000; // function set(8bit interface, 5*7 dot) -4.1ms delay
8'h12 : lcd_db = 8'b00111000; // function set(8bit interface, 5*7 dot) -100us delay
8'h16 : lcd_db = 8'b00111000; // function set(8bit interface, 5*7 dot)
8'h17 : lcd_db = 8'b00001100; // display on
8'h18 : lcd_db = 8'b00000001; // clear display
8'h19 : lcd_db = 8'b00000110; // entry mode set(increment address, no shift)
// rw=0, rs=0
8'h1A : lcd_db = 8'b10000000;
// rw=0, rs=1
8'h1B : lcd_db = LCD_BLANK;
8'h1C : lcd_db = LCD_BLANK;
8'h1D : lcd_db = LCD_BLANK;
8'h1E : lcd_db = 8'h5B; // [
8'h1F : lcd_db = LCD_X;
8'h20 : lcd_db = LCD_F;
8'h21 : lcd_db = LCD_C;
8'h22 : lcd_db = LCD_DASH;
8'h23 : lcd_db = LCD_X;
8'h24 : lcd_db = LCD_C;
8'h25 : lcd_db = LCD_1;
8'h26 : lcd_db = LCD_4;
8'h27 : lcd_db = LCD_4;
8'h28 : lcd_db = 8'h5D; // ]
8'h29 : lcd_db = LCD_BLANK;
8'h2A : lcd_db = LCD_BLANK;
// rw=0, rs=0
8'h2B : lcd_db = 8'b11000000;
// rw=0, rs=1
8'h2C : lcd_db = LCD_C;
8'h2D : lcd_db = LCD_O;
8'h2E : lcd_db = LCD_U;
8'h2F : lcd_db = LCD_N;
8'h30 : lcd_db = LCD_T;
8'h31 : lcd_db = LCD_U;
8'h32 : lcd_db = LCD_P;
8'h33 : lcd_db = 8'h26; //&
8'h34 : lcd_db = LCD_D;
8'h35 : lcd_db = LCD_W;
8'h36 : lcd_db = LCD_EQUAL;
8'h37 : lcd_db = LCD_0;
8'h38 : lcd_db = LCD_0;
8'h39 : lcd_db = LCD_0;
8'h3A : lcd_db = LCD_0;
8'h3B : lcd_db = LCD_BLANK;
default : lcd_db = 0;
endcase
end
assign lcd_rw = 0; // --(5)
assign lcd_rs = ((lcd_state >= 8'h00 & lcd_state < 8'h1B) | lcd_state == 8'h2B) ? 0 : 1; // --(6)
assign lcd_en = !lcd_cnt[0]; // --(7)
assign lcd_data = lcd_db;
endmodule
=====================================================================================================
(1) : 1KHz 생성 합니다 즉 Character LCD 운용 클럭으로 1KHz를 사용합니다
(2) : lcd_cnt 의 값을 "001110010"까지 증가합니다 왜???
(3) : lcd_state에 lcd_cnt(8 downto 1)의 값을 입력합니다
(4) : lcd_state의 값에 따라 Character LCD 초기화 및 표시할 데이터 값을 기록합니다
(5) : Character LCD의 rw값은 항상 '0'을 출력 합니다 즉 busy 체크를 하지 아니하고 적절한 Delay를
사용함으로서 타이밍을 설정합니다
(6) : Character LCD의 rs값은 lcd_state의 값에 따라 Data/Instruction Register로 구분됩니다
찬찬히 소스코드에 있는 주석과 비교해 보세요
(7) : Character LCD의 en값은 lcd_cnt(0)의 값에 부정을 한 값입니다
위 타이밍 챠트를 참고하세요
4. 동작
아래와 같이 동작 수행을 완료 하였습니다 여러분은 다른 캐릭터를 기록해 보세요
손쉽게 성공하시리라 생각됩니다
=====================================================================================================
|
첫댓글 ERROR:Cpld:1244 - Unexpected Exception 오류가 발생하네요.
이상한 건 Error는 0으로 나옵니다.
bin파일은 만들어 지네요.
Xilinx에 문의해야 할 Error 메세지인 것 같습니다. 내부 로직 문제보다 SW툴의 오류 이유를 알아야 할듯 합니다.
ucf파일과 테스트벤치는 수정안되었고 character_LCD.v파일 중에 조합회로 합성을 순차회로 합성으로 변경하였습니다.
네~ 한번 카페지기님 코드 확인해 볼께요~ 감사합니다.
죄송하지만, 아래 vhdl 코드를
process(reset,clk_1khz,new_value)
begin
if(reset = '0') then
start_stop <= '0';
elsif rising_edge(clk_1khz) then
old_value <= new_value;
if(old_value = '1') and (new_value = '0') then
start_stop <= not start_stop;
end if;
end if;
end process;
=====아래처럼 바꾸면 되나요?
always @(*)
begin
if(reset == 0)
start_stop <= 0;
else begin old_value <= new_value;
if ((old_value == 1) & (new_value == 0)) begin
start_stop <= !start_stop;
end
end
end
위의 코드는 순차회로고 님이 만든코드는 조합회로라 다른회로입니다 process문과 always문은 유사하지만 블럭과 이벤트 목록에 따라 회로합성이다릅니다~
아 그렇군요~~~^^;
다름이 아니라.. 주신 것으로 실행했는데, lcd와 7세그먼트는 들어오는데.. 시간 카운터가 안되어서요~ 그래서.. 위 코드 변경에 문제가 있는것 같아서 문의 드렸었네요~~
암튼 감사합니다~^^
제가 reset 핀을 모두 negedge로 해놓았는데.. 파일비교 (오른쪽으로 변경)한것과 같이.. 하나만 posedge로 되어 있어서 변경했더니, 잘 되네요~~ 감사합니다.^^
화면에 안보이네요~~^^; 즉,
==============================================================
always @(posedge reset or posedge clk_100hz)
begin
if(reset == 1'b1) begin
==================================================== 을..
always @(negedge reset or posedge clk_100hz)
begin
if(reset == 1'b0) begin
============================================================= 이렇게 변경했습니다.
reset신호를 모서리이벤트를 일치시켜야지요 한곳은 1로하고 다른곳은0으로 하면 계속 리셋조건에 걸립니다
네 맞아요~~ 제가 이부분을 잘못했어요~^^;;
조언해주셔서 감사합니다~^^
무지 재미난 코딩스탈입니다
^.~
ㅎㅎㅎ 다음번엔... uart 해볼려고하는데.. 막히면 또.. 여쭙겠습니다~~^^;
리셋이1일때 동작하면 잡음에 의해 리셋걸릴 수 있습니다~
네네 주의할께요~~^^
유용한 자료네요. 감사^^
위의 레지스터 표그리기는 어떤 소프트웨어를 이용한 건가요. 워드 혹은 아래한글
MS Word 입니다~~
글쿤요~~~ 워드 쓴지가 오래되어서 ㅋㅋㅋㅋㅋ
start_stop을 순차회로로 만드건 sw2신호의 bouncing신호를 무시하기위함입니다
네네 푸쉬버튼시에 디바운스 위한 것은 알겠어요~~