TA的每日心情 | 开心 2019-11-19 15:19 |
---|
签到天数: 1 天 [LV.1]初来乍到
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本帖最后由 Allevi 于 2018-11-26 09:42 编辑
/ F7 u) ^4 Z, ~6 m' G& [( S9 d- A% U5 D, d
基于FPGA的LCD1602动态显示---Verilog实现 3 ?" E! |. j3 W2 x) f
一.LCD1602简要介绍
6 p' i! \6 S: d! @
. N( F% Z5 j/ N% yLCD1602,根据名称可以知道,就是能显示2行,每行16个字符的液晶,只能显示字母,数字和符号等字符,不能显示汉字,图片。如下图:! d; T" c8 S) e9 R
2 ?! m1 U; C \. V: ]
1 p) ~7 h5 V6 \0 ?- n
市面上卖的的LCD1602操作基本上都是相同的,只是带不带背光之分。其控制芯片都是HD44780及其兼容芯片,所以控制接口都是一样,控制时序可以说是68并口时序。1LCD602控制线主要有4根:
7 G3 ]& @* L5 A% J; Q6 I* j8 g" o4 E3 D4 M( Q/ ?
(1)RS:数据/指令选择端,当RS = 0,写指令;当RS = 1,写数据。
& X" P8 s. t! g: H0 P
D4 j! q0 p7 ]; }9 O4 C(2)RW:读/写选择端,当RW = 0,写指令/数据;当RW = 1,读状态/数据。/ v8 v( V$ [: @0 `4 C
4 u) M) e+ ?* Z; W(3)EN:使能端,下降沿使指令/数据生效。- e; s- a, A. b! E7 z( U; C1 P4 j
$ s$ m. }8 }. e(4)Data[7:0]:8根并行数据口。
. }6 o9 a9 C0 k; l
, q3 Y/ m) {0 X1 ^8 w
$ Y4 k; ^# ?( o- L% m; U- X
1 N5 y. u5 ]/ v
! o6 N0 h6 `( Q1 B: A) b
指令方面只讲解一下显示模式设置指令0x38,0x31的区别。其实模式设置指令就是上图中的指令6:0x38:设置8位格式,2行,5*7;0x31:设置8位格式,2行,5*7。为什么要介绍0x31呢,一般单片机驱动LCD1602都是0x38的?8 l5 N' d% \2 @6 l0 f# M1 S+ a
8 g5 B0 a7 ?# }3 E
由于一般的LCD1602都是VDD = 5V驱动的,而有些FPGA开发板上的LCD1602接口是由3.3V供电的。也就是VDD = 3.3V,这样就会引起供电不足的问题,所以经过试验得到,当VDD = 3.3V时,显示模式设置指令写入0x38时,LCD1602显示很暗,看不到;进而改为0x31时,只显示1行,LCD1602就正常显示了。这个要引起注意,下面我的代码就是只显示1行的。
8 t0 c* |, W% M其他指令详解请查看数据手册。
9 W9 d2 _7 E1 o) q, ]) r; M7 A! ]% n5 d5 n# _" I
+ N2 ^$ q8 `' [$ N& h/ q二.FPGA驱动LCD1602思路6 a7 w4 k% M" s4 v
; T6 Z6 g4 A7 j/ N: x- h
FPGA驱动LCD1602,其实就是通过同步状态机模拟单片机驱动LCD1602,由并行模拟单步执行,状态过程就是先初始化LCD1602,然后写地址,最后写入显示数据。+ S P8 n8 V2 z K
A* ? {3 w( W# k" k6 `$ r! b& p1 q
1.首先,我们要明白LCD1602是慢速器件。如果直接用FPGA 外接的几十兆时钟直接驱动肯定是不行的,所以要对FPGA时钟进行分频驱动,或者计数延时使能驱动。
* }, W- l$ v; C6 x0 s: ?6 l P3 h* z) _. m" f1 i. r* t
这里我采用的计数延时使能驱动,代码中通过计数器定时得出lcd_clk_en信号线驱动。要注意的是不同厂家生产的LCD1602的时序延时都不同,但大多数都是纳秒级的,这里我采用的是间隔500ns使能驱动,最好延时长一些比较可靠,这个可以自己尝试修正。+ I0 u. R8 w1 R; `+ A( Z
: f1 j& J* a$ I# c) Y
2.LCD1602的初始化过程需要明白。大家估计都用单片机驱动过LCD1602,这里FPGA驱动LCD1602的初始化过程也是一样的。主要是以下4条指令的配置:
2 t1 [* y% C' R4 e- w% {* Z
' T, i) D) p% H6 |( x5 a) Q. a% B(1)显示模式设置Mode_Set:8’h38
. k) e, u9 j5 B! ?" a5 V0 e
+ v5 R/ M+ w3 L2 e(2)显示开/关及光标设置Cursor_Set:8’h0c
; U+ k; O( s8 W5 f, W5 B) E! E9 t- Q( P6 c6 y! H% v& i J
(3)显示地址设置Address_Set:8’h06
& D+ j) c8 q& W; W( b7 {
( k& h/ T0 o u) c(4)清屏设置Clear_Set:8'h015 R$ F3 L8 `8 f: A
, z9 d, O* S& {3 F) e
这里需要注意是写指令,所以RS = 0,并且写完指令后,EN下降沿使能。
. l6 m$ o8 b1 q3 Q6 Y3 m! W) P( Z# v- m# T9 N7 p$ i9 r; z/ ~
3.初始化完成后,还需要写入地址,第一行初始地址:8’h80;第二行初始地址:8’h80 + 8”h40 = 8’hc0。这里RS = 0,并且写完地址后,EN下降沿使能。
0 s5 {+ Y* W$ N# A. G/ a. x- Z! l7 v! q$ `' D5 ?+ a" K4 w, W! e; V/ \
4.写入地址后,就可以显示字符啦。但需要注意LCD1602写入设置地址指令8’h06后,地址是随每写入一个数据后,默认自加一的。这个一定要明白,不然作动态显示时,就会出现问题。一定要把握我们的数据是要显示在哪个位置,而LCD1602写入地址是会默认地址指针加一的。这里RS = 1,并且写完数据后,EN下降沿使能。1 g* y4 h' |* v9 h5 A% F
/ z. y6 _! t0 f
5.由于我们要动态显示,所以数据要刷新。这里由于我们采用的是同步状态机模拟LCD1602的控制时序,所以在显示完最后的数据后,状态要跳回写入地址状态,以便进行动态刷新。这个很重要,不只是保证刷新,更是保证地址没有偏移。
" `3 L$ f) W* P: J! B
' R P# y0 y _以上就是大致的思路步骤了,大家可以结合下面的代码进行分析消化,只有你完全弄清LCD1602的控制时序,指令要点,才能完全把LCD1602玩弄于手掌之中,不然似懂非懂,终究会有无法理解的问题出现。# N4 L k; J: z4 k$ v2 ~; |' y
' H% h. p% f7 q1 B, P" T6 s: O" V8 @7 M
三.Verilog 代码2 h" \7 O6 j5 S" t
( e G7 F7 n3 j; p5 v! M) a
本来想把LCD1602_Driver封装成个模块的,然后直接向其写入地址,数据即可显示的,后来由于能力问题,发现不怎么好写,就没有封装成模块了。不过下面动态显示的代码还是可以给大家一个参考的,虽然代码时序不是很严谨。
Q1 F5 Z$ ~8 Z+ E
# v) [, v( m# ^8 |下面代码功能主要是完成一个0-99s的计数器,动态刷新。主要是在LCD1602上动态显示:“Cnt:00”。, ?" G- L: j; t# ~1 t. c# Y& k: }3 S
/***********************************************************************
, c% Q# E# N' i5 Q7 {; o************************* name:LCD1602_Driver *************************$ K9 L( C# k n9 n! p9 [
***********************************************************************/
9 f6 p0 e6 R8 K" J2 a+ o$ b4 [$ F( omodule lcd1602_driver(input clk, //50M
0 ^1 j( e; ]# N' E% m4 a( u# t input rst_n,
9 o" Q# W, t1 U# M9 T% B output lcd_p, //Backlight Source +
* I2 j0 x6 A' X) H output lcd_n, //Backlight Source -
& W# s6 m" Z9 _' t! K) Q6 O$ S r output reg lcd_rs, //0:write order; 1:write data
" v+ h1 y. q5 h' Y8 L& F output lcd_rw, //0:write data; 1:read data* W4 J$ w; O( S# C4 I" S
output reg lcd_en, //negedge
9 N; e3 T [0 Z* `$ z output reg [7:0] lcd_data);, c: ^- p, i4 t6 r% Z
3 f1 l1 t7 _5 [' e" U; v% ^( k6 e
//--------------------lcd1602 order----------------------------' d* T) D/ N) I4 x; U+ ?7 y
parameter Mode_Set = 8'h31,
$ G) u1 o! d$ O! v* z0 ? Cursor_Set = 8'h0c,
. I; A/ G% |3 E% u2 Q Address_Set = 8'h06, A6 \5 K9 U7 ?) T1 s* {+ j! Z9 W
Clear_Set = 8'h01;
7 W3 f* S" B: Y& w
& C; c& Y6 t. }: [/****************************LCD1602 Display Data****************************/ % X' @4 o y5 s( J7 W. A9 t; w( x' A
wire [7:0] data0,data1; //counter data
) t% U. @- z* t! n$ k) Rwire [7:0] addr; //write address8 ~2 w+ V8 s/ G, U& n. U" k) R
//---------------------------------1s counter-----------------------------------
" N1 X7 U' B3 Y& v: Ireg [31:0] cnt1;
* Y" Q# b" t: a* R" `+ Hreg [7:0] data_r0,data_r1;
6 V) ?/ Q, ~6 ]2 m$ [always@(posedge clk or negedge rst_n)
u: X. G5 d. nbegin1 w7 Q! q Z9 P( t6 t
if(!rst_n)$ }' [( q: S0 K) ^) e
begin0 e4 y- O% d2 Y
cnt1 <= 1'b0;1 ~$ y4 ~# i1 s' \1 G
data_r0 <= 1'b0;
$ U# B( r- a7 M: C! S: i data_r1 <= 1'b0;
! `7 C( G4 w2 M# L1 F' ~ end
' ^( t( T; g% a( K" X* X) G% e& ~ else if(cnt1==32'd50000000)
8 Z1 v6 B& l- d) Z begin
! V+ j% z, b8 |, W5 g0 c if(data_r0==8'd9)
, C, i+ h% A4 `" k9 b" i. `$ P begin3 Q' s. Z: T. z9 M E7 Q5 Z
data_r0 <= 1'b0;
% n8 y. |8 |8 [6 I if(data_r1==8'd9)0 L0 [* R+ f" e
data_r1 <= 1'b0;+ E( x& i! b2 p) {
else
# e) V$ x2 ~0 d; S, |9 N data_r1 <= data_r1 + 1'b1;1 E3 w. ~& ?% [( \3 Z r
end
, F( _4 [3 b5 @* H$ E' J4 Y0 O: _ else
! n) R5 z% L* q( {% } data_r0 <= data_r0 + 1'b1;
) K) J z9 F# t/ a! ` cnt1 <= 1'b0;
0 [ n0 z( y5 Q- T( u end' z6 d, h1 \" d% F1 |
else9 c/ U0 V4 ^1 C/ s
cnt1 <= cnt1 + 1'b1;
9 X* a- M4 ^% w% }8 q9 } O7 N8 Nend! n+ R- D# m) N$ U2 P
4 ^9 D; V5 O. ?1 P9 X7 tassign data0 = 8'h30 + data_r0 ;
5 F" ~" }2 v8 Uassign data1 = 8'h30 + data_r1 ;$ G) |- Y, ]% S( S
( u* u5 n. e7 X/ O0 r
//-------------------address------------------% F Z2 c' ]& d; p7 ^; B, v
assign addr = 8'h80;) o. S# g3 C/ f* c% _
+ i1 H( n {5 `/****************************LCD1602 Driver****************************/
( i. Y. u' y% i- @# w8 P x//-----------------------lcd1602 clk_en---------------------
% N% L- x$ P0 J2 areg [31:0] cnt;
1 z7 N7 ]$ Q3 ]( O Lreg lcd_clk_en;& R$ M3 y# c4 B" Z% S! S% T/ ~$ p
always @(posedge clk or negedge rst_n)
- T# n. B" x+ m8 s. ubegin " I+ a/ k8 U. S, R B( m) a
if(!rst_n)4 j+ m9 X+ u' P( ?: ?
begin9 {" Q/ o# M# W# @
cnt <= 1'b0;
' z9 V# U F* T' ~2 e lcd_clk_en <= 1'b0;0 e7 m* \5 A7 `6 p; j
end$ d( J8 ]) R; {1 u- V
else if(cnt == 32'h24999) //500us
9 f* x% @; o' k. n8 g$ N begin/ [ P7 e! e" q
lcd_clk_en <= 1'b1;" v' c4 T' Q% q, Z( W, {8 t
cnt <= 1'b0;
) b# Z+ y5 P; t# R3 t8 ]% Z' ?& V& x end% A8 G9 X+ C7 d7 u# \1 P; _
else
0 j9 J+ S+ ~& D# c begin" J+ B1 R3 W3 O; s5 k9 F: Q
cnt <= cnt + 1'b1;
* ^" r. V- C& U5 c# ], p2 ^ lcd_clk_en <= 1'b0;
2 k2 I" S. B4 F end
; S. Z1 c" N) x7 Nend . t' o, O- @1 \
; P( {+ }+ Z, Y% w1 V8 _! h( I
//-----------------------lcd1602 display state-------------------------------------------% l2 ?3 M) B- M" P: q( x
reg [4:0] state;/ R: t/ y, T+ m [8 L
always@(posedge clk or negedge rst_n)5 [. W3 }9 ^4 _+ x
begin
4 X7 {' N; M t3 H# K1 e if(!rst_n)" |% N8 ~) h, _& b8 P F( ^
begin
0 Q6 p# P$ Q; g state <= 1'b0;: M" b9 e( I" j
lcd_rs <= 1'b0;7 k$ j5 n) o/ \+ v4 j; N
lcd_en <= 1'b0;6 R8 k6 @' q3 G# N
lcd_data <= 1'b0;
( i+ A4 d" N9 W3 C4 z% f end" B0 \2 h+ W y* D0 Z: J
else if(lcd_clk_en)
/ S# L" K4 N' g" Y7 @ begin
6 v. }! G5 w/ L3 B$ u case(state)' [7 u; ]# S9 m/ v( Z4 l- m
//-------------------init_state---------------------
$ a; S/ I; S5 p6 N" n% ?% ?( C6 A, e 5'd0: begin 2 j( q5 _: d+ P! I* v
lcd_rs <= 1'b0;
" h; V) M' T! N$ ?9 y; f! C8 A lcd_en <= 1'b1;
) x: U6 x0 R& ] lcd_data <= Mode_Set;
- w% R# f, h! x. k3 k6 Y1 b b% N! a" | state <= state + 1'd1;
2 X7 H+ o! ]; l. V9 D" ]+ B* i* F$ ` end( O N" v+ i6 O5 _
5'd1: begin" l0 Y3 l- p5 P0 U+ j5 U6 E2 R
lcd_en <= 1'b0;
- s* ?) }* q! W2 {2 F" k state <= state + 1'd1;
2 d& [1 V: F+ R+ M, p8 A1 M end
9 ]8 V0 a) I# a4 k9 S 5'd2: begin
+ K) W0 ]5 H9 D; {. N8 l7 ~ lcd_rs <= 1'b0;
' m9 P1 U9 s- s lcd_en <= 1'b1;
7 T/ E' o& w3 B ?2 S1 U lcd_data <= Cursor_Set;! @8 B' p5 \5 n3 j) H
state <= state + 1'd1;4 T9 I) H- F/ u% C5 T
end
$ K, W, T, X, _2 K8 s& F: T' T N 5'd3: begin+ \: t9 [$ t+ [8 d. \ r
lcd_en <= 1'b0;* k4 Q; W4 [/ S/ v% b; s
state <= state + 1'd1;0 J9 F$ F% b. y: `! h: L- p; j
end7 A( B! P- t+ a/ d
5'd4: begin( Q% K7 o; q3 L6 n1 |7 p
lcd_rs <= 1'b0;' k5 V1 } b1 } n: [; |- ?
lcd_en <= 1'b1;5 ]! u+ ~" ?, l1 @& B7 e
lcd_data <= Address_Set;
( G1 l3 p! Y G7 ? state <= state + 1'd1;5 Y( U; }. h1 p# s9 D5 o
end
, V+ I' U2 r- {9 K/ h+ _7 f 5'd5: begin) }& G7 A+ r# s) w* q
lcd_en <= 1'b0;4 @ ?" i; b% S- ]- x
state <= state + 1'd1;
7 W' d' K, h; Y3 G, _5 m; `( g! i end. V5 U' z! O$ n! c9 B! E/ z3 c% c
5'd6: begin, v4 U4 D# ?5 h5 S0 j& ~3 B
lcd_rs <= 1'b0;
+ l) |4 K0 p' e) y5 d lcd_en <= 1'b1;, Y3 T% H* T1 J4 |, w3 K: M
lcd_data <= Clear_Set;
6 W: P8 k5 C, C7 {# \; B state <= state + 1'd1;3 S$ F/ J# @$ c, t: F: c
end1 B' @& m/ X* @% V1 Q# Y
5'd7: begin6 ~0 E$ f4 J6 D; A2 b. L
lcd_en <= 1'b0;
/ D9 w+ Y( H7 S state <= state + 1'd1;9 {* M3 R- G) |8 @
end$ M- W) E x5 F! z- B
& t( L" Z' k6 m7 I( ~2 b- m
//--------------------work state--------------------! E U; Y7 S+ _8 G: T9 z
5'd8: begin 0 t9 t9 f6 A( k5 B. _6 I( N
lcd_rs <= 1'b0;& P3 P3 O7 H' X0 N0 \+ I$ B$ u
lcd_en <= 1'b1;( p2 S% m$ k- p/ a1 H
lcd_data <= addr; //write addr
4 E* |8 H$ ^2 Q& m! J state <= state + 1'd1;
, ^. ~; n' ~; t0 q end, ~) ~$ s4 b" N2 F9 b" p A$ ?, D
5'd9: begin$ S8 A" p7 G% f6 H
lcd_en <= 1'b0;+ p+ G* M3 S7 p+ V$ y9 v) Y
state <= state + 1'd1;1 G( t- x( u1 z6 T/ d! S2 j& A# @- L+ P
end
. J0 I, \+ Z/ l4 A0 b 5'd10: begin
0 x9 B; y$ |/ y h lcd_rs <= 1'b1;. |- X7 A, f6 [9 g9 B: z
lcd_en <= 1'b1;
, x& j1 {/ j& q4 |" t& i& h! s lcd_data <= "C"; //write data
3 [' l" {4 _1 h6 C- C G state <= state + 1'd1;) z. V- s% e% B9 P- V# L" L
end( p1 M3 D1 }4 q6 X
5'd11: begin
6 \' y6 [7 O% n* ^ lcd_en <= 1'b0;
0 |* W: d9 p4 F8 i6 s K state <= state + 1'd1;& b/ `, P" N' G, v) H a q5 d
end1 l* }$ G. P' p( e
5'd12: begin( I) Y! p3 `1 X0 a% p" E
lcd_rs <= 1'b1;' W* m% a9 s2 t' t
lcd_en <= 1'b1;$ E1 g8 ^$ ?7 p; d- [ c" g: l
lcd_data <= "n"; //write data b! ^8 K. w6 {* k
state <= state + 1'd1;3 A' h6 W$ X1 @ [4 v3 Y
end+ r& l4 C p7 V, [5 m3 A4 C
5'd13: begin
3 U W+ w6 F. C* F, M$ N5 p& o lcd_en <= 1'b0;
8 t; n% v0 P; N state <= state + 1'd1;& E" c7 y! z& G1 ^* f
end1 P( z! u3 J1 _% v" r
5'd14: begin
, b6 c3 F. `/ [) U/ Y# b1 W ^ lcd_rs <= 1'b1;& S. a2 H' e, }$ A& A7 Q9 ^
lcd_en <= 1'b1;
6 k7 M" i. x& a7 k7 }$ u4 Y1 a lcd_data <= "t"; //write data
& c v& r8 _6 u state <= state + 1'd1;
$ |' i( h S3 S1 q7 @ end" z! z5 A: b' V
5'd15: begin4 S' q/ d" P6 |) o5 d3 ?7 z x
lcd_en <= 1'b0;
& g, l; g2 m3 O. l) y9 a2 G$ @ state <= state + 1'd1;) C: l- }9 j1 J0 ^5 j( C
end
& z! w1 {& r( g6 f 5'd16: begin$ ]! x% J( z# _) D
lcd_rs <= 1'b1;
& R5 D: N! t9 } lcd_en <= 1'b1;
% Y) p' K% c7 P( \; {/ X3 Z; `6 r lcd_data <= ":"; //write data
" O# E4 \4 N3 j& H state <= state + 1'd1;, e B, |) o+ z9 ~4 i+ N
end/ X; `8 L8 J* ~
5'd17: begin O) N+ L) K# K$ N3 G/ g
lcd_en <= 1'b0;( A0 l/ O& v8 X1 r
state <= state + 1'd1;
" ^+ j0 X0 M' F end ! ?( s! B9 a/ H; J5 }7 v
5'd18: begin
- X1 o0 U; v/ p. x/ M lcd_rs <= 1'b1;( X- y9 K, j. g( F5 g
lcd_en <= 1'b1;# o. k- N- L. c/ s. C A# `
lcd_data <= data1; //write data: tens digit
. p( D" E' t$ z$ W( U( D state <= state + 1'd1;
2 q5 |! _% ]4 \9 ? end& y# m( x+ n( n/ G* E
5'd19: begin% ^( m4 g; h/ G. q: D
lcd_en <= 1'b0;
" ]. u$ }+ \$ N- o' x: O, T state <= state + 1'd1;: M& [4 R; e9 t- F4 l& @8 e$ f
end, P8 _" S7 S: C/ r$ G+ P
5'd20: begin
9 L* R8 ^+ M1 d lcd_rs <= 1'b1;# B% D& H9 y) O
lcd_en <= 1'b1;0 v* V F6 g% e, P0 c4 ]7 R" K
lcd_data <= data0; //write data: single digit+ `5 Y* }% N2 |, l. U1 d) c& e
state <= state + 1'd1;* q) ^( J' ~& W) r6 E
end" i3 J+ Q0 J! U# `
5'd21: begin
! f- v# ]! y& `( t lcd_en <= 1'b0;
& g. |4 l% m4 I4 Y" G state <= 5'd8;8 O( R2 }+ A3 u2 j; I1 V' A* n* y
end5 _; |" {7 l0 y9 D8 @: \$ |1 p- ]
default: state <= 5'bxxxxx;8 ^$ U& k$ N( U- Q
endcase( \: c! B$ F3 d3 |! h
end
4 H. A. d+ R& `% m4 e" r8 m# l9 Mend- J" z# ~( B+ m4 ~, n+ ~3 i1 t; n* ]
5 y' ~1 V/ ` J# X2 g8 F& Zassign lcd_rw = 1'b0; //only write) T I/ d/ Y" q8 M( f c' z
0 p% `/ A# T+ h$ O! t+ t//------------------backlight driver----------------# z. m6 A/ M1 e; C7 A
assign lcd_n = 1'b0;
9 B1 b+ G3 @9 h9 Z; bassign lcd_p = 1'b1;
4 [; D5 f/ E2 \3 m* ~! X+ f2 x3 a7 c5 u8 R' q
endmodule
% U9 p5 C4 N% m; Z |
9 S( W- I0 K" C |
|