TA的每日心情 | 开心 2019-11-19 15:19 |
---|
签到天数: 1 天 [LV.1]初来乍到
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本帖最后由 Allevi 于 2018-11-26 09:42 编辑
4 p: A* t1 y+ Y) E/ Y9 P0 i5 I
! d( U; I3 b k1 W0 _6 V基于FPGA的LCD1602动态显示---Verilog实现
7 K1 w7 ]1 Z# `4 N1 C$ t一.LCD1602简要介绍- W5 X$ P/ J) o/ L- u N) G/ b
. e; \! c* V4 ^* _ j4 d0 _LCD1602,根据名称可以知道,就是能显示2行,每行16个字符的液晶,只能显示字母,数字和符号等字符,不能显示汉字,图片。如下图:
2 b" s+ e4 j A8 }
4 F1 I( h7 s0 z' h# t
2 y0 n3 D+ B& a" }. G9 N
市面上卖的的LCD1602操作基本上都是相同的,只是带不带背光之分。其控制芯片都是HD44780及其兼容芯片,所以控制接口都是一样,控制时序可以说是68并口时序。1LCD602控制线主要有4根:
& l2 R4 y2 p' J( w" E+ M4 `4 e( g: J0 U0 [; K( E
(1)RS:数据/指令选择端,当RS = 0,写指令;当RS = 1,写数据。
" {: K# w4 t5 \/ D1 {
! g0 I' y: d, @+ S9 ~(2)RW:读/写选择端,当RW = 0,写指令/数据;当RW = 1,读状态/数据。
2 G* V( J5 f8 ? ]* x+ L/ U
* T ~3 J, N+ B+ E6 ^9 f(3)EN:使能端,下降沿使指令/数据生效。7 O; r& P' \" N6 W% c
\5 j& E5 ?. p1 z: p P. D" d
(4)Data[7:0]:8根并行数据口。
$ y" X- O. [" j8 W T
2 }" y f8 {0 n' @
8 T! W+ r n9 Q
: v9 Q: d) K% g
9 P& z0 a8 U/ W3 z+ H4 g指令方面只讲解一下显示模式设置指令0x38,0x31的区别。其实模式设置指令就是上图中的指令6:0x38:设置8位格式,2行,5*7;0x31:设置8位格式,2行,5*7。为什么要介绍0x31呢,一般单片机驱动LCD1602都是0x38的?: {* q% [/ f# ?0 Z" z7 P# s9 J
5 K+ A0 N% Y0 T
由于一般的LCD1602都是VDD = 5V驱动的,而有些FPGA开发板上的LCD1602接口是由3.3V供电的。也就是VDD = 3.3V,这样就会引起供电不足的问题,所以经过试验得到,当VDD = 3.3V时,显示模式设置指令写入0x38时,LCD1602显示很暗,看不到;进而改为0x31时,只显示1行,LCD1602就正常显示了。这个要引起注意,下面我的代码就是只显示1行的。% h0 T9 a8 W4 D: x2 b1 M2 A1 X
其他指令详解请查看数据手册。& H* _; ]3 `$ M
1 X7 m# m$ w3 l
4 v8 D/ ^* o- u$ `7 t4 k) N8 l
二.FPGA驱动LCD1602思路
( X# @& ]! ?* `" @& [5 {, r
# t0 r' P0 H) j2 g5 d' @2 kFPGA驱动LCD1602,其实就是通过同步状态机模拟单片机驱动LCD1602,由并行模拟单步执行,状态过程就是先初始化LCD1602,然后写地址,最后写入显示数据。* C4 I" l; U0 J% w2 v( e
' }. Y9 z3 `. W" X- V1.首先,我们要明白LCD1602是慢速器件。如果直接用FPGA 外接的几十兆时钟直接驱动肯定是不行的,所以要对FPGA时钟进行分频驱动,或者计数延时使能驱动。6 N6 u+ M$ i9 K: }9 J D$ S, h& \
8 p* u& R2 V! v0 x
这里我采用的计数延时使能驱动,代码中通过计数器定时得出lcd_clk_en信号线驱动。要注意的是不同厂家生产的LCD1602的时序延时都不同,但大多数都是纳秒级的,这里我采用的是间隔500ns使能驱动,最好延时长一些比较可靠,这个可以自己尝试修正。
& j2 X0 p; e1 h& r, w
5 e; o& @2 J/ w1 ~8 Z4 M" y9 Y2.LCD1602的初始化过程需要明白。大家估计都用单片机驱动过LCD1602,这里FPGA驱动LCD1602的初始化过程也是一样的。主要是以下4条指令的配置:; |! p7 i+ L/ G* U2 q8 g* z' f
% n3 ?6 f7 X* R I* ^1 ~8 N
(1)显示模式设置Mode_Set:8’h38 # i2 I' f t3 Z
6 Z! f8 w8 B1 M, ^6 H
(2)显示开/关及光标设置Cursor_Set:8’h0c. z* T+ | L1 }+ `) l+ t. I; x
$ Y, P! r5 u9 \9 y& d
(3)显示地址设置Address_Set:8’h067 T+ h9 E5 u2 }0 D
1 _% S8 Y a0 J: v0 k6 S+ Z(4)清屏设置Clear_Set:8'h01
1 E4 E! P6 V. D# C. Y" X7 O
0 x3 E% @4 d$ k" `. j% X 这里需要注意是写指令,所以RS = 0,并且写完指令后,EN下降沿使能。
+ r+ g, V( D c& V v6 Z" X; V% h, c# I
3.初始化完成后,还需要写入地址,第一行初始地址:8’h80;第二行初始地址:8’h80 + 8”h40 = 8’hc0。这里RS = 0,并且写完地址后,EN下降沿使能。
2 Z6 U8 x& _4 g5 p+ t$ C6 ?' a3 [! @, L, `: Q
4.写入地址后,就可以显示字符啦。但需要注意LCD1602写入设置地址指令8’h06后,地址是随每写入一个数据后,默认自加一的。这个一定要明白,不然作动态显示时,就会出现问题。一定要把握我们的数据是要显示在哪个位置,而LCD1602写入地址是会默认地址指针加一的。这里RS = 1,并且写完数据后,EN下降沿使能。
6 `2 ^ F D- v% T2 I6 }3 z* d$ Q$ Z5 `/ M
5.由于我们要动态显示,所以数据要刷新。这里由于我们采用的是同步状态机模拟LCD1602的控制时序,所以在显示完最后的数据后,状态要跳回写入地址状态,以便进行动态刷新。这个很重要,不只是保证刷新,更是保证地址没有偏移。
5 k; {' C3 b4 L
* [1 R1 K1 x; f1 L2 O0 D; s8 ~以上就是大致的思路步骤了,大家可以结合下面的代码进行分析消化,只有你完全弄清LCD1602的控制时序,指令要点,才能完全把LCD1602玩弄于手掌之中,不然似懂非懂,终究会有无法理解的问题出现。! \3 }( B+ u3 a: O# G2 @4 T, A
1 v( I' X! V4 k" a2 u0 j8 U; J5 `& w$ X: p7 x
三.Verilog 代码
& E# ^; z+ M B& R( A: b4 \
! y" Q% d- F. X1 Z7 e3 i本来想把LCD1602_Driver封装成个模块的,然后直接向其写入地址,数据即可显示的,后来由于能力问题,发现不怎么好写,就没有封装成模块了。不过下面动态显示的代码还是可以给大家一个参考的,虽然代码时序不是很严谨。9 T% s0 N, L* D1 K# v& J* Q
* Q* {9 z0 x7 c; l! J
下面代码功能主要是完成一个0-99s的计数器,动态刷新。主要是在LCD1602上动态显示:“Cnt:00”。5 f. A0 y4 L0 S
/***********************************************************************
$ Q9 v' M. m0 }& \$ v0 i( W************************* name:LCD1602_Driver *************************& b4 W# G& K2 G4 ?5 e7 x' G
***********************************************************************/
* Q& v" `" p$ g- [3 h( p7 B; Pmodule lcd1602_driver(input clk, //50M0 p) M, q5 [9 U
input rst_n,
# y/ i# I0 f" j output lcd_p, //Backlight Source +
* k3 @- T/ u+ ^' ]! m$ \ output lcd_n, //Backlight Source -, B7 m/ ^: p& {2 k8 b; [
output reg lcd_rs, //0:write order; 1:write data % @2 {2 L9 [& q/ [! A- H4 H) W" d
output lcd_rw, //0:write data; 1:read data
2 D3 P) g. H' M% U7 W. b output reg lcd_en, //negedge
9 m6 {; b1 m3 E: H( ~" W output reg [7:0] lcd_data);
' k/ `/ a) i7 Y! z0 B+ ]4 j! E
% W# I2 d) e- [# \//--------------------lcd1602 order----------------------------
1 T, b4 W9 Q/ C* mparameter Mode_Set = 8'h31,
. v9 H0 ~" A% P. j9 t- ~) A# n Cursor_Set = 8'h0c,
7 {8 Q+ t# S- q& w' k" R; Y, p Address_Set = 8'h06,/ S2 e, k* l2 x
Clear_Set = 8'h01;
8 A( f0 O: V) Y7 Z2 L' u( a0 z! D4 n1 p5 A" S, z0 c
/****************************LCD1602 Display Data****************************/ 3 F: K; t+ f8 }- l# J2 S
wire [7:0] data0,data1; //counter data
( c* U- \6 W4 W( G; Hwire [7:0] addr; //write address
0 O! S0 n9 q. d1 `5 I" @+ ?//---------------------------------1s counter-----------------------------------9 v, ^4 X L- M6 l$ {' b
reg [31:0] cnt1;
$ }) \6 w6 p5 V5 D- D+ areg [7:0] data_r0,data_r1;
, b. D6 H" h- R8 B" a' K5 X4 n {always@(posedge clk or negedge rst_n)
/ X7 X# m, y% I- J4 J2 Dbegin+ S* @9 R. Z0 D0 z2 u0 B
if(!rst_n)
3 `3 f7 i- k& V) j begin
8 ]6 ~0 \- n8 d cnt1 <= 1'b0;
/ U6 o P4 @ i; r# [ data_r0 <= 1'b0;* G' B* o4 J3 V5 U
data_r1 <= 1'b0;
- u, J5 m$ g3 M. Y% o/ Z end5 _$ x% s2 y5 V1 u; x: g/ r
else if(cnt1==32'd50000000)% d8 R) O/ o* c" C4 F% w- T
begin* T$ x2 t$ Z4 k3 l9 C1 v
if(data_r0==8'd9)6 Z1 D$ F# I9 K
begin4 y8 I% j0 n+ o
data_r0 <= 1'b0;% b5 O0 O! K( v$ X: Q% L
if(data_r1==8'd9)6 z& ~5 m* \6 c( ~% r; L
data_r1 <= 1'b0;
7 O! b. `' c F7 r4 i" w) | else8 w3 E! ]3 _) L: R; G2 Q
data_r1 <= data_r1 + 1'b1;! q% P$ p( Z7 S
end. ]0 p: ?/ N! W' M
else7 j5 S2 Z" p/ n/ B2 O, @
data_r0 <= data_r0 + 1'b1;
& ?/ D& U) \2 o9 x$ d7 ~& ` cnt1 <= 1'b0;
0 X0 [; z. l4 @! C" H+ m: d end
/ y" g3 [' R" y) g- ~& e! S else
: `% ]% w! K( V1 @: Z) d3 g cnt1 <= cnt1 + 1'b1;
( B3 z& C- U' W4 ~end
3 r: n4 z/ K4 s' h. V& y
. e7 m3 s" F# }. q8 Xassign data0 = 8'h30 + data_r0 ; $ ~$ `+ C) u: H8 R7 `" M. p: P
assign data1 = 8'h30 + data_r1 ;. B' ?7 O$ W9 b+ y& r6 l
+ t2 T+ z& l. S5 @+ r8 {* a U- t//-------------------address------------------1 e9 L4 ?0 g& k7 R( q D( U Y
assign addr = 8'h80; ~5 R, \+ N: q$ S5 ]
; O/ ]* \8 t4 _% }' M/****************************LCD1602 Driver****************************/
1 b, e; W0 ^4 H( ~7 D7 O% o//-----------------------lcd1602 clk_en---------------------
# [; }! J9 q i" Freg [31:0] cnt;) h, V; D& M, j8 J& s
reg lcd_clk_en;
2 i" ^5 c+ A, x: {* W1 Jalways @(posedge clk or negedge rst_n)
L/ G0 j. \7 ]+ s5 U2 u* ]& P! x2 |9 Kbegin 6 x4 I- s, v# A
if(!rst_n)9 f% ^9 h+ Z1 U4 y
begin
6 b) V+ B" H& N7 }+ z2 ? cnt <= 1'b0;8 U; q6 E0 \+ c6 d1 U7 [& m
lcd_clk_en <= 1'b0;
1 Y/ `, ~7 X. s3 n! \ end8 a# R* k3 B, K% D
else if(cnt == 32'h24999) //500us
. p3 q4 M: K% a begin$ p% f3 G5 |* z
lcd_clk_en <= 1'b1;% ]* F- ^5 e0 a2 m) g6 M3 j
cnt <= 1'b0;
& o! L; Y" A( @/ T g y A# ] end- s5 k9 D' q+ S' M. V X2 f* C
else
# b5 [: R6 P! y, s7 w; d( f, m begin& K( E! x; j; {8 K. }0 p/ b
cnt <= cnt + 1'b1;
: }; W8 d: [. X" [. u( _; s+ d lcd_clk_en <= 1'b0;' x4 R# ] \6 K5 ~. U- B
end- ]; p/ L) z6 v& u/ ^# G
end 0 o. A$ F8 M1 X6 V: n8 _% G% c
( S9 h. C$ U- p3 w( r//-----------------------lcd1602 display state-------------------------------------------
, ^# g, | S* z, Ireg [4:0] state;
, O& p/ b/ F% E+ q5 Q! ]" ]always@(posedge clk or negedge rst_n)
; L$ e3 Q0 |" E: B; Pbegin
B @9 X% W* ?% c if(!rst_n)
+ L& S9 J" V; D$ i9 M D+ T begin
& u* o+ Y8 V; a3 g, \. ], i5 Y state <= 1'b0;
! ~: E- }1 n$ y3 D lcd_rs <= 1'b0;
# a6 x: V/ B4 ]" l: ]" j1 S lcd_en <= 1'b0;/ U5 f. l( l! L g* p8 B: E' N
lcd_data <= 1'b0;
; @4 G9 x! }' E# F/ S* d6 w0 K7 r S end$ I, Y0 ~2 f8 u8 L; A
else if(lcd_clk_en) * R7 U/ y( r+ }4 { e, K
begin! [' v, }4 a% B& Y9 ~, E9 |# R
case(state)* O5 ^" J9 s R9 o
//-------------------init_state---------------------
3 D6 Y$ M3 S0 v3 _6 J 5'd0: begin + B, ~+ W$ F. Q% M6 L+ z- o/ P1 i3 B& Z
lcd_rs <= 1'b0;
9 c3 X! V5 n( s4 Y4 g$ l lcd_en <= 1'b1;* M1 ^+ A; Z; e& e& p6 [
lcd_data <= Mode_Set; n; S% Z; y# t( X5 `& X
state <= state + 1'd1;2 R& B; G' }8 Z# A" h
end4 a, x2 y) M' b+ k p7 z
5'd1: begin
2 B, q5 G- q. C1 M" B lcd_en <= 1'b0;
% b- e& G4 G+ ^, v+ e7 U U+ j+ _2 |2 T state <= state + 1'd1;/ U- Q" v ?; y& G& b" ^3 `, `% V
end7 \. j5 w& _' P: V5 M0 v
5'd2: begin6 t! P1 U, J& |, Q' n& ~ h8 P
lcd_rs <= 1'b0;
% {) v' X9 I. N7 @/ P* D1 h lcd_en <= 1'b1;
G ~6 `$ ^! O& Y lcd_data <= Cursor_Set;
2 v+ k# M$ z- Z# M. z2 C6 ]/ T state <= state + 1'd1;- @4 ^$ b, X! O" Z' N. R& t+ f# p$ I, Y
end+ J7 R2 r& `% Q+ ~) p! h: a5 L. x
5'd3: begin
8 U. h. @( M0 l0 r, y lcd_en <= 1'b0;/ l- q; x3 w5 P
state <= state + 1'd1;9 R3 |1 }$ X0 ^8 |: c
end& S8 z# Q! v& i( f9 a% B
5'd4: begin4 \# {9 K2 j/ Z7 ^
lcd_rs <= 1'b0;
0 z$ Q" A, h6 w) d% H3 H lcd_en <= 1'b1;
! ?! g5 ?( [9 Z8 m lcd_data <= Address_Set;
( C3 G! ^0 w9 u: L& w3 Q7 c state <= state + 1'd1;
8 L9 I2 o$ ?) ` |* @ end
! \1 l$ u- W S3 Q8 [ 5'd5: begin8 U3 T+ _. s5 Y4 h
lcd_en <= 1'b0;7 e: a7 r/ ?& y5 a6 {4 z6 ~
state <= state + 1'd1;
, N V- U3 u! b3 p8 k5 P; u end
3 I+ O* G7 W1 E \1 S) f 5'd6: begin% j! H) n3 j4 b: }4 ~. P" h
lcd_rs <= 1'b0;
0 l0 x% L. ^4 X, q lcd_en <= 1'b1;( U$ o x* w4 ~* H" p
lcd_data <= Clear_Set;
# y6 d d- A: u' G, K& W: F9 X state <= state + 1'd1;
/ R7 M" i! y; h end
) e6 y( |9 O. f 5'd7: begin% u2 P" b, w9 {2 F/ }
lcd_en <= 1'b0;
- h8 f3 _, \, K' T" l) B state <= state + 1'd1;5 s) q' f: }; o3 E3 y% M8 T Y
end# S) j% z% {. B/ `
' b% X$ b2 v5 w" B
//--------------------work state--------------------! Y& V; r; G# A3 x
5'd8: begin 5 U7 z) S1 v2 |* ~
lcd_rs <= 1'b0;; E8 g8 b! Y2 X4 K: f! O! V
lcd_en <= 1'b1;
9 z" k6 Q- z7 C6 G& H2 g lcd_data <= addr; //write addr7 @1 H, m: g; J" H) T8 e! L4 k
state <= state + 1'd1;3 b9 K6 R$ G. R O# p0 p( o: ^
end: E$ K' p( _7 O5 f3 _
5'd9: begin" { I* d; c9 l0 I# R- F* I
lcd_en <= 1'b0;2 b6 L: ~. g5 _4 ^+ z' I
state <= state + 1'd1;
1 p6 }* h+ p0 X+ f9 x9 ~% u end
6 y+ b/ C, U4 w8 n% M- J0 c 5'd10: begin
" a s/ x/ @4 H- P0 S% ^ [ lcd_rs <= 1'b1;% D* }3 l7 h" q: y, X
lcd_en <= 1'b1;2 b/ S$ e/ S. j$ T: `; B4 t, A
lcd_data <= "C"; //write data
* {; W9 J; ?4 l' Q9 s/ C8 F! h state <= state + 1'd1;
" \7 }; v% t' r) B end
# S, o- g' u# h# k. V 5'd11: begin- R' u8 \5 g* D" h( e/ M3 x% M
lcd_en <= 1'b0;3 Z+ u; H8 D$ K: S- M6 Y
state <= state + 1'd1;
: g2 C b9 S2 ?: g: R end
2 G% F0 r }4 x4 ^( e 5'd12: begin
Q) p& n' y8 D# n" n lcd_rs <= 1'b1;
+ I* p# `7 I! W5 ? q+ b& ` lcd_en <= 1'b1;
; V- F( d) u N* _ lcd_data <= "n"; //write data
) S# I7 F" T6 g; I' k state <= state + 1'd1;
' ?/ t/ ?) H+ s9 ?$ L7 \7 [ end
$ r3 z, @- k/ |; u; O2 q 5'd13: begin% H5 Y& Y9 v' W/ T1 t! b9 E; m- V
lcd_en <= 1'b0;
/ s& c: p' ?, w5 h) x2 ` state <= state + 1'd1;4 R6 l9 g3 H. L5 f: A' e
end( {4 r( R5 V* h! t) Z
5'd14: begin" ~6 ?3 T3 D8 f/ e1 C* t" i: c
lcd_rs <= 1'b1;
; S( H7 F* i1 E- \: P) l- ]( I lcd_en <= 1'b1;2 `6 ~" {) w0 W B- l7 T" k
lcd_data <= "t"; //write data. u) [0 t# d- ]* {) [& v/ f3 n
state <= state + 1'd1;
4 i" B7 |( n4 @: E0 F- Q2 Z1 N end
* f/ I: {) d$ { 5'd15: begin
6 p) ^% g8 @1 E6 |' \( a3 \ lcd_en <= 1'b0;; g. e" l; T: c! T( }$ e5 h6 d
state <= state + 1'd1;
9 G* J* i. V: i9 b* P k0 B end
# Q/ }& ~2 P+ M1 [ 5'd16: begin
% L6 `0 I K( K4 J7 q! b! T% W lcd_rs <= 1'b1;9 d- |- b4 v( H, C+ @6 g
lcd_en <= 1'b1;
5 I- j9 H. Y9 _# a+ P, ] lcd_data <= ":"; //write data( K! F1 f/ ]0 M* F7 f/ D7 z2 w
state <= state + 1'd1;
0 i% y) Z$ v& `# U% ?5 q9 ?4 h2 l end- U$ y4 _; R9 t! M3 Y; Y" @
5'd17: begin
' V. q6 b$ ~$ J. e; B lcd_en <= 1'b0;: ?! R+ K% T5 |: w% f+ A0 n
state <= state + 1'd1;
8 \. f! C) c) _0 i end
$ m8 O0 i# B6 ?7 g: q 5'd18: begin
( o5 `) i* H) T U' A2 z lcd_rs <= 1'b1;
/ B6 L7 o# I6 F; u! Q+ T" V7 l lcd_en <= 1'b1;& s7 p1 A$ h# s% W+ z1 Y0 P0 W4 w1 L
lcd_data <= data1; //write data: tens digit) P+ X" [. h$ l. D( L9 E
state <= state + 1'd1;
/ U& O2 T- b. ^; m end$ }8 ^* K- h; v( E; A' }5 Q. l) W
5'd19: begin
9 E8 g( ^5 ~! N1 U7 \: \ lcd_en <= 1'b0;
0 k5 B+ ~' ~4 @' a& A state <= state + 1'd1;/ t. T, R$ k2 \7 N
end" w% O6 {$ p' b0 a# o
5'd20: begin& n% r3 t9 [* J; o5 s& {
lcd_rs <= 1'b1;9 ^5 B: Q/ D) Q8 \% ]2 L
lcd_en <= 1'b1;. P4 x& _7 m3 h) }0 P! c
lcd_data <= data0; //write data: single digit" S1 I' N% Q5 f* g( l
state <= state + 1'd1;6 W. P. i$ P: @- x4 ?$ @% D
end+ G; V4 Y0 Z J
5'd21: begin
% q# D( P2 {* O/ q, x: g: F lcd_en <= 1'b0;9 J0 x2 ^6 b7 _. i5 W8 j4 c
state <= 5'd8;
) d/ _' m/ k" w# k end
7 E4 b2 _2 Y u default: state <= 5'bxxxxx;# b2 z% X* y, J) c9 x! O
endcase2 ~2 a6 p" _! m; M, F
end- G# U. _( x- o |% a7 r; x' E3 ~
end( m" G) [4 ]$ Y9 }( v
5 P5 i' E( c" |' ?* r& p
assign lcd_rw = 1'b0; //only write
) [8 }/ t' k& [) Z) d0 u7 z$ ~0 z7 S( x1 v( O5 d7 O* n
//------------------backlight driver----------------
& |0 A- @, o, x9 ?7 n" }assign lcd_n = 1'b0;! {. q" o) g+ Q
assign lcd_p = 1'b1;, q9 h% ^0 l4 E* }# C; x; S+ z6 b4 C7 T
2 E' T" k. f7 _! v a' h8 k6 _9 Uendmodule( Q+ ?$ p1 j/ N' g4 q1 e
|
- z" O$ E# Z4 `7 x; d |
|