一天一个设计实例-​LCD1602的应用设计

LCD1602的应用设计

1.1.1LCD1602的简介

工业字符型液晶,能够同时显示16x02即32个字符。(16列2行)

图6‑16 LCD1602实物图

注:为了表示的方便 ,后文皆以1表示高电平,0表示低电平。

1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形(用自定义CGRAM,显示效果也不好)。

1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。

市面上字符液晶大多数是基于HD44780液晶芯片的,控制原理是完全相同的,因此基于HD44780写的控制程序可以很方便地应用于市面上大部分的字符型液晶。

HD44780内置了DDRAM、CGROM、CGRAM.其中要让lcd显示就需要将DDRAM的相应地址写入数据。

图6‑17 LCD1602内部框架图

图6‑18 通用5V LCD1602驱动电路原理图

图6‑19 DDRAM地址与显示位置的对应关系

在1602中,我们只要前面16行就行,其地址和屏幕的对应关系:

图6‑20 地址和屏幕的对应关系

上图可知DDRAM一共有40个地址,但是对应于1602显示,只能有32个地址有效。这是因为1602可以显示上下两行,每一行显示16符号,一共显示32个符号,每个显示对应于DDRAM一个地址。例如,我需要在1602的第一行最左边显示一个字母A。首先找到第一行最左边对应DDRAM的地址是什么,查看上图可知是:00H,然后大写字母A对应于ASCII中为41H,此时我们只需要给DDRAM的00H地址写个数据41H即可显示了。

问题2:为何写个41H,就可以显示为"A"呢?

对于这个问题,就需要理解CGROM和CGRAM的作用。在芯片HD44780中内置了192个常用字符的字模,存于CGROM(character generate ROM)中,还有8个允许用户自定义字符(也就是可以显示八个中文字)的RAM,也就是CGRAM。具体描述为下图:

图6‑21 CGROM和CGRAM的作用

可以从上图分析A在字模中代码:高4位为0100,低4位为0001.所以组成8位就变成了41H,这就说明了为何写入41H就可以显示“A”。

上图红框里面表示为CGRAM,字模代码为:00H-0FH;ASCII的字模代码为:20H-7FH;日文和希腊字符的字模代码为:A0H-FFH;10H-1FH和80H-9FH没有使用。

问题3:我要任意显示一个字母,数字怎么办?

这个问题是接着上面一个问题而言,具体就是:在1602中我要在某一行某个位置显示我想要的数字或是字母,我应该对应DDRAM地址写个什么样的八位数据?例如,我想显示“1”,那不是就写个01H呢?此时就需要一个思维转换,我们要显示的“1”不再是一个数据,而是需要转换为一个图案,可以看到上图有1的图案,该图案对应了31H,所以需要显示一个“1”,我们就需要给1602的数据总线(DB7--DB0)输入31H。以此类推,例如我们需要输入kb129 is a good man,于是就需要给1602顺序输入:6BH,62H,31H,32H,39H ,20H(空格),69H,73H,20H,61H,20H,67H,6FH,6FH,64H,20H,6DH,61H,6EH。

问题4:那显示汉字怎么办呢?

问题2中解决了显示任意一个字母和数字,但是汉字在图中找不到汉字,怎么办?这时候需要使用CGRAM了,先用字模软件,将对应汉字的变为二进制数。

图6‑22 取模软件的应用

例如我想要显示一个“电”字,由于1602中显示的图案为5*7或是5*10,所以在8*8中左边三列不能使用。得到8列八位数据:04, 1F, 15,1F, 15,1F, 04,07.

然后就需要将这8个8bit数据写入CGRAM中,写CGRAM需要使用指令:

图6‑23 写CGRAM需要使用指令

可以设置地址指针自加一模式,所以如果我们想把“电”这个字方在第1个CGRAM中,也就是对应DDRAM中的00H,就需要将地址写为DB7--DB0:0100_0000.然后将数据04, 1F, 15,1F, 15,1F, 04,07依次写进CGRAM中。这样在CGROM字符的字模中00H就代表了“电”。

最后就是显示,也就是如果需要将“电”显示在1602中,就将地址指针指向DDRAM,然后写数据为00H。

图6‑24 地址指针指向DDRAM

1.1.2关注时序

上面已经了解到要让1602显示就需要将特地的地址输入特地的值,如果你刚接触1602,此时一定特别想了解怎么将上面的思路转换为verilog代码。但是一定需要注意时序问题,1602的读写时序为:

图6‑25 1602的写时序

图6‑26 1602的读时序

表6‑11 写操作时序周期

E Cycle Time 是我们最关心的数据,表6‑11中给出了最小的值,为500ns,即2MHz为最高的频率,这在LCD1602的驱动设计时需要格外注意,否则由于FPGA的运行速度快,导致写入速度过快,会使LCD1602的驱动设计时需要格外注意,否则由于FPGA的运行速度快,导致写入速度过快,会使LCD1602无法响应。

此外,LCD1602的初始化由严格的顺序,要是处理不当,会导致显示不正常,甚至不能正常显示。LCD1602的初始化顺序也不是设计者想出来的,原厂规定必须这样去处理,否则达不到预期的效果。

LCD1602的驱动主要有8bit模式和4bit模式,8bit模式为最常用的模式,设计简单,操作方便,而4bit模式则略复杂一点,在I/O资源紧张的情况下可以选择使用4bit模式。本次设计主要使用8bit模式驱动。手册中关于LCD1602的8bit模式的初始化操作流程图如图6‑27所示。

由图6‑27可知,LCD1602从上电到稳定至少需要等待15ms,15ms内不能进行忙状态读取,等待15ms上电初始化稳定之后,开始进行LCD1602的配置与初始化,主要是时序图中初始化结束前的配置。没有经过正确的初始化,LCD1602不会按照预期的效果显示,因此模式初始化在LCD1602的驱动中尤为重要。为了明确了解LCD1602的模式配置初始化过程,在这里给出整个模式配置流程,以及相关的寄存器配置,包括以下内容。

(1)延时15ms,等待LCD1602上电稳定;

(2)功能配置。主要配置LCD1602为8bit还是4bit模式显示,显示的行数为2行或者1行,字符以5x11或者5x8显示。关于8/4bit功能配置的寄存器说明,如图6‑27所示。

DL、N、F分别为1、1、0,因此功能配置寄存器的值为38H。

(3)关闭LCD1602显示。

(4)为了显示模式的配置,需要先关闭1602,相关的寄存器如图6‑27所示。

图6‑27 LCD1602 8bit模式的初始化操作流程

这里特别注意了setup和 hold time,但是实际使用中由于1602显示不需要很高的时序,所以我们只需降低1602工作的时钟就可以很容易满足1602的时序要求。

1.1.3LCD1602指令功能

(1)Display Clear清屏指令设置

表6‑12 Display Clear清屏指令设置

指令功能

指令编码

执行时间/ms

RS

R/W

DB7

DB6

DB5

DB4

DB3

DB2

DB1

DB0

清屏

0

0

0

0

0

0

0

0

0

1

1.64

Function:

<1>cursor move to first digit

<2>地址计数器AC的值设置为0;

(2)Return Home光标归位

表6‑13 Return Home光标归位

指令功能

指令编码

执行时间/ms

RS

R/W

DB7

DB6

DB5

DB4

DB3

DB2

DB1

DB0

光标归为

0

0

0

0

0

0

0

0

1

X

1.64

Function:

<1>把光标撤回到显示器的左上方

<2>把地址计数器Ac设置为0;

<3>保持DDRAM的值不变

(3)Entry Mode set输入模式设置指令

表6‑14 Entry Mode set输入模式设置指令

指令功能

指令编码

执行时间/us

RS

R/W

DB7

DB6

DB5

DB4

DB3

DB2

DB1

DB0

进入模式设置

0

0

0

0

0

0

0

1

I/D

S

40

Function:

I/D   set cursor move direction H:increase L:decrease

写入数据之后的光标移动的方向H:右移L:左移

S    specifies shift of display H:display is shifted L:display is not shifted

写入一个数据之后显示屏移动或者不移动

(4)Display On/off显示开关控制指令

表6‑15 Display On/off显示开关控制指令

指令功能

指令编码

执行时间/us

RS

R/W

DB7

DB6

DB5

DB4

DB3

DB2

DB1

DB0

显示开关控制

0

0

0

0

0

0

1

D

C

B

40

D:H:显示开;L:显示关

C:H:光标开   L:光标关

B:H: 光标闪烁 L:光标不闪烁

(5)Shift 设置显示屏或者光标移动的方向

表6‑16 Shift 设置显示屏或者光标移动的方向

指令功能

指令编码

执行时间/us

RS

R/W

DB7

DB6

DB5

DB4

DB3

DB2

DB1

DB0

设定显示屏或光标移动方向

0

0

0

0

0

1

S/C

R/L

X

X

40

S/C:显示屏还是光标 H:显示屏移动L:光标移动

R/L:向左移动还是向右移动H:右移L;左移(光标右移:AC值加1;光标左移:AC值减1)

(6)Set Function

表6‑17 Set Function

指令功能

指令编码

执行时间/us

RS

R/W

DB7

DB6

DB5

DB4

DB3

DB2

DB1

DB0

功能设定

0

0

0

0

1

DL

N

F

X

X

40

DL:data length                            L:数据总线为4位    H:数据总线为8位

N  :number line                            L:1行 显示         H:2行显示

F :                               L:5×7点阵/每字符    H:5×10点阵/每字符

(7)Set CGRAM Address

表6‑18 Set CGRAM Address

指令功能

指令编码

执行时间/us

RS

R/W

DB7

DB6

DB5

DB4

DB3

DB2

DB1

DB0

设定CGRAM

0

0

0

1

CGRAM的地址(6位)

40

设置CGRAM的地址,我们将我们自定义的字模数据存入对应的地址,从0x40~0x7F,128字节,8个字符的字模数据可存入。

(8)Set  DDRAM Address

表6‑19 Set  DDRAM Address

指令功能

指令编码

执行时间/us

RS

R/W

DB7

DB6

DB5

DB4

DB3

DB2

DB1

DB0

设定DGRAM

0

0

1

DGRAM的地址(7位)

40

与CGRAM一样,在往DDRAM里面写入想要显示的字符的字符区位码的之前需要将存储字符区位码的地址首先写入。DDRAM的地址空间以上已述。(加地址的时候我们要加上0x80,因为写入地址的时候DB7必须为1)

(9)Read Busy Flag and the Address读取忙碌标志和地址计数器的值

表6‑20 Read Busy Flag and the Address读取忙碌标志和地址计数器的值

指令功能

指令编码

执行时间/us

RS

R/W

DB7

DB6

DB5

DB4

DB3

DB2

DB1

DB0

读取忙碌信号或AC地址

0

1

FB

AC内容(7位)

40

BF:H:忙碌,表示无法结束单片机送来的数据;L:准备就绪,可以接受数据

当内部操作正在进行的时候,读取BF的值

AC:读取地址计数器的值

1.数据写入CGRAM和DDRAM

2.从CGRAM和DDRAM读取数据

1.1.4显示字库中本来就有的字符和显示自定义的字符步骤

1.显示字库中本来就有的字符

步骤一:系统初始化和LCD初始化

步骤二:LCD液晶屏上面每个字符对应于DDRAM的地址,你想要把字符写进屏幕哪个位置,就往DDRAM写入该位置所对应的地址。(对应的地址在上述已说)

步骤三:字库中本来已经存在的字符各自有对应的字符区位码,其实就是每个字符对应的ASCII码(见字符表格)。你要显示哪个字符,只要将该字符对应的ASCII码写入DDRAM就搞定了,这个是很简单的。

2.显示自定义的字符

其实显示自定义的字符和字库字符差不多的,只需要将你自定义的字符用取模工具得到字模的数组数据之后。之后的步骤和显示字库字符是一样一样滴。

步骤一:系统初始化和LCD初始化

步骤二:搞清楚字符点阵的格式是5*8,通过取字模工具得出自定义字符的字模数据,再写入相应的CGRAM地址,一个地址写入一个一个字节数据(一个字节的8位,前3位为0,点阵的格式5*8)

步骤三:同显示字库中本来就有的字符一样的做法

1.1.5LCD1602的自带字库应用设计

图6‑28 LCD1602的自带字库应用设计建模

表6‑21 端口说明

端口名

位宽

输入/输出

说明

CLOCK

1

Input

时钟信号

RST_n

1

Input

复位信号,低电平有效

line_rom1

128

Input

第一行显示的字符缓冲寄存器

line_rom2

128

Input

第二行显示的字符缓存寄存器

1602_EN

1

Output

使能信号,高电平读取数据,下降沿执行命令

1602_RS

1

Output

高电平时选择数据,低电平时选择命令

1602_RW

1

Output

高电平时读取信号,低电平时写入信号

1602_DATA

8

Output

数据输出端口

图6‑29 液晶显示流程

代码6‑3 lcd1602_basemod代码

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-05-19 20:56:01

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-06-29 00:54:50

7.//# Description:

8.//# @Modification History: 2019-05-19 20:57:52

9.//# Date                By             Version             Change Description:

10.//# ========================================================================= #

11.//# 2019-05-19 20:57:52

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module lcd1602_basemod

17.(

18.    input CLOCK, RST_n,

19.     //lcd1602 interface

20.    output              LCD1602_RS,     //H: Data; L: Instruction code

21.    output              LCD1602_RW,     //H: Read; L: Write

22.    output              LCD1602_EN,     //LCD1602 Chip enable signal

23.    output      [7:0]   LCD1602_D       //LCD1602 Data interface

24.

25.    // input iCall,

26.     //output oDone,

27.     //input [5:0]iData

28.

29.);

30.

31.//****************************************************************************//

32.//   取模数据

33.//****************************************************************************//

34.//--------------------------------

35.//Driver of LCD1602

36.localparam  [127:0] line_rom1 = " Subscriptions: ";//"Hello World*^_^*";//第一行固定显示

37.wire    [127:0]  line_rom2; //= "OpenFPGA   *^_^*";//"I am OpenFPGA!";  //第二行滚动显示

38.

39.//***************************************************************************//

40.wire DoneU1;

41.//wire [7:0] oDATA;

42.

43.

44.     lcd1602_funcmod U1

45.     (

46.         .CLOCK( CLOCK ),

47.          .RST_n( RST_n ),

48.          .LCD1602_RS( LCD1602_RS ),   // > top

49.          .LCD1602_RW( LCD1602_RW ),         // > top

50.          .LCD1602_EN( LCD1602_EN ),         // <> top

51.          .LCD1602_D(LCD1602_D),

52.          .line_rom1( line_rom1 ),    // > top

53.          .line_rom2( line_rom2 ),  // > U2

54.          .iCall( 1'b1 ),            // < U1

55.          .oDone( DoneU1 )             // > U1

56.

57.

58.     );

59.

60.     reg [7:0]i;

61.//   reg [127:0]isLine_rom2;

62.    reg [23:0] Data;

63.     reg [7:0]isData;

64.     always @ ( posedge CLOCK or negedge RST_n )

65.         if( !RST_n )

66.              begin

67.                    i  <= 8'd0;

68.                    Data <= 24'd0;

69.                    isData <= 8'd0;

70.//                  isLine_rom2 <= {"Number:",Data};

71.                end

72.          else

73.              case( i )

74.//************************初始化操作*********************************//

75.                     0 :

76.

77.                     if( DoneU1 ) begin i <= i + 1'b1;end

78.

79.

80.                     1 :

81.                     if( DoneU1) begin  isData<= isData+1'b1;i <= i + 1'b1; end

82.//                   else begin isCall[1]<= 1'b1; end//Display off

83.

84.                     2 :

85.                     if( DoneU1 ) begin

86.

87.                            if(isData==16) begin isData<=8< span="">'d0;i <= i + 1'b1; end

88.                          else begin i <= i + 1'b1; end

89.

90.                     end//Clear the LCD

91.

92.                     3:

93.                      case (isData)

94.                       0:

95.                            begin Data = "0";i <=i+1'b1;  end

96.                        1:

97.                           begin Data = "1";i <=i+1'b1;  end

98.                       2:

99.                            begin Data = "2";i <=i+1'b1;  end

100.                        3:

101.                           begin Data = "3";i <=i+1'b1;  end

102.                       4:

103.                            begin Data = "4";i <=i+1'b1;  end

104.                        5:

105.                          begin Data = "5";i <=i+1'b1;  end

106.                       6:

107.                            begin Data = "6";i <=i+1'b1;  end

108.                        7:

109.                           begin Data = "7";i <=i+1'b1;  end

110.                       8:

111.                            begin Data = "8";i <=i+1'b1;  end

112.                        9:

113.                           begin Data = "9";i <=i+1'b1;  end

114.                       10:

115.                            begin Data = "10";i <=i+1'b1;  end

116.                        11:

117.                           begin Data = "11";i <=i+1'b1;  end

118.                        12:

119.                           begin Data = "12";i <=i+1'b1;  end

120.                       13:

121.                            begin Data = "13";i <=i+1'b1;  end

122.                        14:

123.                           begin Data = "14";i <=i+1'b1;  end

124.                       15:

125.                            begin Data = "15";i <=i+1'b1;  end

126.                        16:

127.                           begin Data = "16";i <=i+1'b1;  end

128.

129.                        default :begin Data = "000";i <=i+1'b1;  end

130.

131.                      endcase

132.

133.                     4:

134.                     i <= 8'd0;//8'd7

135.        endcase

136.

137.

138.      assign line_rom2 = {"Number:",Data};

139.//    assign oDATA = D1;

140.

141.

142.endmodule

代码6‑4 lcd1602_ctrlmod代码

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-05-19 20:55:44

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-06-28 23:43:55

7.//# Description:

8.//# @Modification History: 2019-05-19 20:58:05

9.//# Date                By             Version             Change Description:

10.//# ========================================================================= #

11.//# 2019-05-19 20:58:05

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module lcd1602_ctrlmod

17.(

18.    input CLOCK, RST_n,

19.     input iCall,

20.     output oDone,

21.    input       [127:0] line_rom1,  //LCD1602 1th row display

22.    input       [127:0] line_rom2,  //LCD1602 2th row display

23.     output [1:0]oCall,

24.     input iDone,

25.     output [7:0]oDATA

26.);

27.//LCD1602 init

28.localparam  DISP_SET    =   8'h38;  //Display mode: Set 16X2,5X8, 8 bits data

29.localparam  DISP_OFF    =   8'h08;  //Display off

30.localparam  CLR_SCR     =   8'h01;  //Clear the LCD

31.localparam  CURSOR_SET1 =   8'h06;  //Set Cursor

32.localparam  CURSOR_SET2 =   8'h0C;  //Display on

33.//Display 1th line

34.localparam  ROW1_ADDR   =   8'h05;  //Line1's first address

35.

36.//Display 2th line

37.localparam  ROW2_ADDR   =   8'h1C;  //Line2's first address

38.

39.

40.//---------------------------------------

41.

42.//   reg [63:0]iData;

43.     reg [7:0]D1;

44.     reg [7:0]i;

45.     reg [1:0]isCall;

46.     reg isDone;

47.     always @ ( posedge CLOCK or negedge RST_n )

48.         if( !RST_n )

49.              begin

50.                    D1 <= 8'd0;

51.                    i  <= 8'd0;

52.                    //iData <= 64'd0;

53.                    isCall[1:0] <= 2'b00;

54.                end

55.          else if ( iCall )

56.              case( i )

57.//************************初始化操作*********************************//

58.                     0 :

59.

60.                    if( iDone ) begin isCall[1]<= 1'b0;i <= i + 1'b1;end

61.                     else begin isCall[1] <= 1'b1; end//Display mode

62.

63.                     1 :

64.                     if( iDone ) begin isCall[1]<= 1'b0; i <= i + 1'b1; end

65.                     else begin isCall[1]<= 1'b1; end//Display off

66.

67.                     2 :

68.                     if( iDone ) begin isCall[1] <= 1'b0; i <= i + 1'b1; end

69.                     else begin isCall[1] <= 1'b1; end//Clear the LCD

70.

71.                    3 :

72.                     if( iDone ) begin isCall[1] <= 1'b0; i <= i + 1'b1;  end

73.                     else begin isCall[1] <= 1'b1; end//Set Cursor

74.

75.                     4 :

76.                     if( iDone ) begin isCall[1] <= 1'b0; i <= i + 1'b1;  end

77.                     else begin isCall[1] <= 1'b1; end//Display on

78.

79.                     5 :

80.                     begin isDone <= 1'b1; i <= i + 1'b1; end

81.                     6 :

82.                     begin isDone <= 1'b0; i <= i + 1'b1; end//初始化完成

83.                    //Display 1th line

84.

85.                    7 :

86.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = 8'h80; end

87.                     else begin isCall[0] <= 1'b1; end////Line1's first address

88.

89.                     8 :

90.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[127:120]; end

91.                     else begin isCall[0] <= 1'b1; end

92.

93.                     9 :

94.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[119:112]; end

95.                     else begin isCall[0] <= 1'b1; end

96.

97.                     10 :

98.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[111:104]; end

99.                     else begin isCall[0] <= 1'b1; end

100.

101.                     11 :

102.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[103: 96]; end

103.                     else begin isCall[0] <= 1'b1; end

104.

105.                     12 :

106.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 95: 88]; end

107.                     else begin isCall[0] <= 1'b1; end

108.

109.                     13 :

110.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 87: 80]; end

111.                     else begin isCall[0] <= 1'b1; end

112.

113.                     14 :

114.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 79: 72]; end

115.                     else begin isCall[0] <= 1'b1; end

116.

117.                     15 :

118.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 71: 64]; end

119.                     else begin isCall[0] <= 1'b1; end

120.

121.                     16 :

122.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 63: 56]; end

123.                     else begin isCall[0] <= 1'b1; end

124.

125.                     17 :

126.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 55: 48]; end

127.                     else begin isCall[0] <= 1'b1; end

128.

129.                     18 :

130.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 47: 40]; end

131.                     else begin isCall[0] <= 1'b1; end

132.

133.                     19 :

134.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 39: 32]; end

135.                     else begin isCall[0] <= 1'b1; end

136.

137.                     20 :

138.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 31: 24]; end

139.                     else begin isCall[0] <= 1'b1; end

140.

141.                     21 :

142.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 23: 16]; end

143.                     else begin isCall[0] <= 1'b1; end

144.

145.                     22 :

146.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 15:  8]; end

147.                     else begin isCall[0] <= 1'b1; end

148.

149.                     23 :

150.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[  7:  0]; end

151.                     else begin isCall[0] <= 1'b1; end//

152.        //Display 2th line

153.

154.                    24 :

155.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = 8'hC0; end

156.                     else begin isCall[0] <= 1'b1; end//Line2's first address

157.                     25 :

158.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[127:120]; end

159.                     else begin isCall[0] <= 1'b1; end

160.

161.                     26 :

162.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[119:112]; end

163.                     else begin isCall[0] <= 1'b1; end

164.

165.                     27 :

166.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[111:104]; end

167.                     else begin isCall[0] <= 1'b1; end

168.

169.                     28 :

170.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[103: 96]; end

171.                     else begin isCall[0] <= 1'b1; end

172.

173.                     29 :

174.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 95: 88]; end

175.                     else begin isCall[0] <= 1'b1; end

176.

177.                     30 :

178.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 87: 80]; end

179.                     else begin isCall[0] <= 1'b1; end

180.

181.                     31 :

182.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 79: 72]; end

183.                     else begin isCall[0] <= 1'b1; end

184.

185.                     32 :

186.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 71: 64]; end

187.                     else begin isCall[0] <= 1'b1; end

188.

189.                     33 :

190.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 63: 56]; end

191.                     else begin isCall[0] <= 1'b1; end

192.

193.                     34 :

194.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 55: 48]; end

195.                     else begin isCall[0] <= 1'b1; end

196.

197.                     35 :

198.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 47: 40]; end

199.                     else begin isCall[0] <= 1'b1; end

200.

201.                     36 :

202.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 39: 32]; end

203.                     else begin isCall[0] <= 1'b1; end

204.

205.                     37 :

206.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 31: 24]; end

207.                     else begin isCall[0] <= 1'b1; end

208.

209.                     38 :

210.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 23: 16]; end

211.                     else begin isCall[0] <= 1'b1; end

212.

213.                     39 :

214.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 15:  8]; end

215.                     else begin isCall[0] <= 1'b1; end

216.

217.                     40 :

218.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[  7:  0]; end

219.                     else begin isCall[0] <= 1'b1; end//

220.

221.

222.                     41:

223.                     i <= 8'd7;//8'd7

224.        endcase

225.

226.

227.      assign oDone = isDone;

228.      assign oCall[1:0] = isCall[1:0];

229.      assign oDATA = D1;

230.

231.endmodule

代码6‑5 lcd1602_funcmod代码

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-05-19 21:06:32

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-06-29 01:08:17

7.//# Description:

8.//# @Modification History: 2019-05-19 20:58:19

9.//# Date                By             VerDATAn            Change Description:

10.//# ========================================================================= #

11.//# 2019-05-19 20:58:19

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module lcd1602_funcmod

17.(

18.    input CLOCK, RST_n,

19.

20.    //lcd1602 interface

21.    output              LCD1602_RS,     //H: Data; L: Instruction code

22.    output              LCD1602_RW,     //H: Read; L: Write

23.    output              LCD1602_EN,     //LCD1602 Chip enable signal

24.    output      [7:0]   LCD1602_D,      //LCD1602 Data interface

25.

26.    input       [127:0] line_rom1,  //LCD1602 1th row display

27.    input       [127:0] line_rom2,  //LCD1602 2th row display

28.    //Signal

29.    input iCall,

30.    output oDone

31.);

32.     parameter DELAY_TIME = 1000_000;   //Delay for 20ms

33.     //localparam DELAY_TIME = 20'd1000;        //Just for test

34.     parameter FCLK = 20'd100_000, FHALF = 20'd50_000; // 500hz,(1/500hz)/(1/50Mhz) FCLK 为一个周期

35.     //localparam FCLK = 20'd100, FHALF = 20'd50;        //Just for test

36.     parameter FF_Write = 6'd60;//FHALF 为半周期  //tsp1的延时

37.     //localparam FF_Write = 20'd16;        //Just for test

38.

39.

40.     assign LCD1602_RW=1'b0;

41.     reg [19:0]C1,C2;

42.    reg [5:0]i,Go;

43.     reg [7:0]T; //D1 为暂存读取结果 T 为伪函数的操作空间

44.     reg rRS, rEN;

45.     reg [7:0]rDATA;

46.     reg isDone; //isQ 为 IO 的控制输出

47.

48.//LCD1602 init

49.localparam  DISP_SET    =   8'h38;  //Display mode: Set 16X2,5X8, 8 bits data

50.localparam  DISP_OFF    =   8'h08;  //Display off

51.localparam  CLR_SCR     =   8'h01;  //Clear the LCD

52.localparam  CURSOR_SET1 =   8'h06;  //Set Cursor

53.localparam  CURSOR_SET2 =   8'h0C;  //Display on

54.//Display 1th line

55.localparam  ROW1_ADDR   =   8'h80;  //Line1's first address

56.

57.//Display 2th line

58.localparam  ROW2_ADDR   =   8'hC0;  //Line2's first address

59.

60.    always @ ( posedge CLOCK or negedge RST_n )

61.         if( !RST_n )

62.              begin

63.                    { C1,C2 } <={ 20'd0,20'd0 };

64.                    { i,Go } <= { 6'd0,6'd0 };

65.                     T  <= 8'd0;

66.                     { rRS, rEN, rDATA } <= 3'b000;

67.                      isDone <= 1'b0;

68.                end

69./***********************************************************************

70.下面步骤是写一个字节的伪函数。步骤 0 拉高片选,准备访问字节,并且进入伪函数。

71.步骤 1 准备写入数据并且进入伪函数。

72.步骤 2 拉低片选,步骤 3~4 则是用来产生完成信号。

73.***********************************************************************/

74.           else if( iCall )

75.                case( i )

76.

77.                    0://延时20ms

78.                        begin

79.                            { rRS,rEN } <= 2'b01;

80.                            if( C2 == DELAY_TIME -1) begin C2 <= 20'd0; i <= i + 1'b1; end

81.                            else C2 <= C2 + 1'b1;

82.                        end

83.

84.                    1:

85.                        begin  rRS <=1< span="">'b0;i <= i + 1'b1; end //{ rRS,rEN } <= 2'b01;

86.

87.                    2:

88.                        begin T <= 8'h00; i <= FF_Write; Go <= i + 1'b1; end   //IDLE

89.

90.                    3:

91.                        begin T <= DISP_SET; i <= FF_Write; Go <= i + 1'b1; end

92.

93.                    4:

94.                        begin T <= DISP_OFF; i <= FF_Write; Go <= i + 1'b1; end

95.

96.                    5:

97.                        begin T <= CLR_SCR; i <= FF_Write; Go <= i + 1'b1; end

98.

99.                    6:

100.                        begin T <= CURSOR_SET1; i <= FF_Write; Go <= i + 1'b1; end

101.

102.                    7:

103.                         begin T <= CURSOR_SET2; i <= FF_Write; Go <= i + 1'b1; end

104.

105.

106.                    8:

107.                        begin isDone <= 1'b1; i <= i + 1'b1; end

108.

109.                    9:

110.                        begin isDone <= 1'b0; i <= i + 1'b1; end

111.

112.                    10:

113.                        begin rRS <=1< span="">'b0; i <= i + 1'b1; end//{ rRS,rEN } <= 2'b00;

114.                    11:

115.                         begin T <= ROW1_ADDR; i <= FF_Write; Go <= i + 1'b1; end

116.                    12:

117.                        begin rRS <=1< span="">'b1; i <= i + 1'b1; end//{ rRS,rEN } <= 2'b11;

118.

119.                    13:

120.                         begin T <= line_rom1[127:120]; i <= FF_Write; Go <= i + 1'b1; end

121.                    14:

122.                         begin T <= line_rom1[119:112]; i <= FF_Write; Go <= i + 1'b1; end

123.                    15:

124.                         begin T <= line_rom1[111:104]; i <= FF_Write; Go <= i + 1'b1; end

125.                    16:

126.                         begin T <= line_rom1[103: 96]; i <= FF_Write; Go <= i + 1'b1; end

127.                    17:

128.                         begin T <= line_rom1[ 95: 88]; i <= FF_Write; Go <= i + 1'b1; end

129.                    18:

130.                         begin T <= line_rom1[ 87: 80]; i <= FF_Write; Go <= i + 1'b1; end

131.                    19:

132.                         begin T <= line_rom1[ 79: 72]; i <= FF_Write; Go <= i + 1'b1; end

133.                    20:

134.                         begin T <= line_rom1[ 71: 64]; i <= FF_Write; Go <= i + 1'b1; end

135.                    21:

136.                         begin T <= line_rom1[ 63: 56]; i <= FF_Write; Go <= i + 1'b1; end

137.                    22:

138.                         begin T <= line_rom1[ 55: 48]; i <= FF_Write; Go <= i + 1'b1; end

139.                    23:

140.                         begin T <= line_rom1[ 47: 40]; i <= FF_Write; Go <= i + 1'b1; end

141.                    24:

142.                         begin T <= line_rom1[ 39: 32]; i <= FF_Write; Go <= i + 1'b1; end

143.                    25:

144.                         begin T <= line_rom1[ 31: 24]; i <= FF_Write; Go <= i + 1'b1; end

145.                    26:

146.                         begin T <= line_rom1[ 23: 16]; i <= FF_Write; Go <= i + 1'b1; end

147.                    27:

148.                         begin T <= line_rom1[ 15:  8]; i <= FF_Write; Go <= i + 1'b1; end

149.                    28:

150.                         begin T <= line_rom1[  7:  0]; i <= FF_Write; Go <= i + 1'b1; end

151.

152.                    /**********************************************************************/

153.                    29:

154.                        begin rRS <=1< span="">'b0; i <= i + 1'b1; end//{ rRS,rEN } <= 2'b00;

155.                    30:

156.                         begin T <= ROW2_ADDR; i <= FF_Write; Go <= i + 1'b1; end

157.                    31:

158.                        begin  rRS <=1< span="">'b1;i <= i + 1'b1; end//{ rRS,rEN } <= 2'b11;

159.                   32:

160.                        i <= i + 1'b1;

161.                    33:

162.                        begin T <= line_rom2[127:120]; i <= FF_Write; Go <= i + 1'b1; end

163.                   34:

164.                        begin T <= line_rom2[119:112]; i <= FF_Write; Go <= i + 1'b1; end

165.                    35:

166.                        begin T <= line_rom2[111:104]; i <= FF_Write; Go <= i + 1'b1; end

167.                    36:

168.                        begin T <= line_rom2[103: 96]; i <= FF_Write; Go <= i + 1'b1; end

169.                    37:

170.                        begin T <= line_rom2[ 95: 88]; i <= FF_Write; Go <= i + 1'b1; end

171.                    38:

172.                        begin T <= line_rom2[ 87: 80]; i <= FF_Write; Go <= i + 1'b1; end

173.                    39:

174.                        begin T <= line_rom2[ 79: 72]; i <= FF_Write; Go <= i + 1'b1; end

175.                    40:

176.                        begin T <= line_rom2[ 71: 64]; i <= FF_Write; Go <= i + 1'b1; end

177.                    41:

178.                        begin T <= line_rom2[ 63: 56]; i <= FF_Write; Go <= i + 1'b1; end

179.                    42:

180.                        begin T <= line_rom2[ 55: 48]; i <= FF_Write; Go <= i + 1'b1; end

181.                    43:

182.                        begin T <= line_rom2[ 47: 40]; i <= FF_Write; Go <= i + 1'b1; end

183.                    44:

184.                        begin T <= line_rom2[ 39: 32]; i <= FF_Write; Go <= i + 1'b1; end

185.                    45:

186.                        begin T <= line_rom2[ 31: 24]; i <= FF_Write; Go <= i + 1'b1; end

187.                    46:

188.                        begin T <= line_rom2[ 23: 16]; i <= FF_Write; Go <= i + 1'b1; end

189.                    47:

190.                        begin T <= line_rom2[ 15:  8]; i <= FF_Write; Go <= i + 1'b1; end

191.                    48:

192.                        begin T <= line_rom2[  7:  0]; i <= FF_Write; Go <= i + 1'b1; end//Go <= i + 1'b1;

193.                    49:

194.                        begin { rRS,rEN } <= 2'b01; i <= i + 1'b1; end

195.

196.                    50:

197.                      begin isDone <= 1'b1; i <= i + 1'b1; end

198.

199.                    51:

200.                      begin isDone <= 1'b0; i <= 6'd10; end//

201.

202.                      /******************/

203.

204.                      60:

205.                      begin

206.

207.                          rDATA <= T;//

208.

209.                        if( C1 == 0 ) rEN <= 1'b1;

210.                        else if( C1 == FHALF ) rEN <= 1'b0;

211.

212.                        if( C1 == FCLK -1) begin C1 <= 20'd0; i <= i + 1'b1; end

213.                        else C1 <= C1 + 1'b1;

214.                      end

215.

216.                     61:

217.                      i <= Go;

218.

219.                 endcase

220.

221./***********************************************************************

222.以下内容为相关输出驱动声明,其中 rDATA 驱动 LCD1602_D_DATA, D 驱动 oData    。

223.***********************************************************************/

224.        assign { LCD1602_RS,LCD1602_EN } = { rRS,rEN };

225.        assign LCD1602_D = rDATA ;  //isQ ? rDATA : 1'bz;

226.        assign oDone = isDone;

227.

228.endmodule

调用过程也非常简单,只需要在lcd1602_basemod 代码中将line_rom1和line_rom2分别赋值就可以在LCD1602中显示需要显示的内容,下一章节将介绍自定义字符设计。

1.1.6LCD1602的自定义字符应用设计

LCD1602自定义字符只需要按照下面的步骤进行设置就可了,如下:

步骤一:系统初始化和LCD初始化

步骤二:LCD液晶屏上面每个字符对应于DDRAM的地址,你想要把字符写进屏幕哪个位置,就往DDRAM写入该位置所对应的地址。(对应的地址在上述已说)

步骤三:字库中本来已经存在的字符各自有对应的字符区位码,其实就是每个字符对应的ASCII码(见字符表格)。你要显示哪个字符,只要将该字符对应的ASCII码写入DDRAM就搞定了,这个是很简单的。

流程基本和自带字库差不多,这里就不进行建模设计,直接贴上代码,如下:

代码6‑6 lcd1602_basemod代码

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-05-19 20:56:01

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-06-29 00:54:50

7.//# Description:

8.//# @Modification History: 2019-05-19 20:57:52

9.//# Date                By             Version             Change Description:

10.//# ========================================================================= #

11.//# 2019-05-19 20:57:52

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module lcd1602_basemod

17.(

18.    input CLOCK, RST_n,

19.     //lcd1602 interface

20.    output              LCD1602_RS,     //H: Data; L: Instruction code

21.    output              LCD1602_RW,     //H: Read; L: Write

22.    output              LCD1602_EN,     //LCD1602 Chip enable signal

23.    output      [7:0]   LCD1602_D       //LCD1602 Data interface

24.

25.    // input iCall,

26.     //output oDone,

27.     //input [5:0]iData

28.

29.);

30.

31.//****************************************************************************//

32.//   取模数据

33.//****************************************************************************//

34.//--------------------------------

35.//Driver of LCD1602

36.localparam  [127:0] line_rom1 = "OpenFPGAOpenFPGA";//"Hello World*^_^*";//第一行固定显示

37.wire    [127:0]  line_rom2; //= "OpenFPGA   *^_^*";//"I am OpenFPGA!";  //第二行滚动显示

38.

39.//***************************************************************************//

40.wire DoneU1;

41.//wire [7:0] oDATA;

42.

43.

44.     lcd1602_funcmod U1

45.     (

46.         .CLOCK( CLOCK ),

47.          .RST_n( RST_n ),

48.          .LCD1602_RS( LCD1602_RS ),   // > top

49.          .LCD1602_RW( LCD1602_RW ),         // > top

50.          .LCD1602_EN( LCD1602_EN ),         // <> top

51.          .LCD1602_D(LCD1602_D),

52.          .line_rom1( line_rom1 ),    // > top

53.          .line_rom2( line_rom2 ),  // > U2

54.          .iCall( 1'b1 ),            // < U1

55.          .oDone( DoneU1 )             // > U1

56.

57.

58.     );

59.

60.     reg [7:0]i;

61.//   reg [127:0]isLine_rom2;

62.    reg [23:0] Data;

63.     reg [7:0]isData;

64.     always @ ( posedge CLOCK or negedge RST_n )

65.         if( !RST_n )

66.              begin

67.                    i  <= 8'd0;

68.                    Data <= 24'd0;

69.                    isData <= 8'd0;

70.//                  isLine_rom2 <= {"Number:",Data};

71.                end

72.          else

73.              case( i )

74.//************************初始化操作*********************************//

75.                     0 :

76.

77.                     if( DoneU1 ) begin i <= i + 1'b1;end

78.

79.

80.                     1 :

81.                     if( DoneU1) begin  isData<= isData+1'b1;i <= i + 1'b1; end

82.//                   else begin isCall[1]<= 1'b1; end//Display off

83.

84.                     2 :

85.                     if( DoneU1 ) begin

86.

87.                            if(isData==16) begin isData<=8< span="">'d0;i <= i + 1'b1; end

88.                          else begin i <= i + 1'b1; end

89.

90.                     end//Clear the LCD

91.

92.                     3:

93.                      case (isData)

94.                       0:

95.                            begin Data = "0";i <=i+1'b1;  end

96.                        1:

97.                           begin Data = "1";i <=i+1'b1;  end

98.                       2:

99.                            begin Data = "2";i <=i+1'b1;  end

100.                        3:

101.                           begin Data = "3";i <=i+1'b1;  end

102.                       4:

103.                            begin Data = "4";i <=i+1'b1;  end

104.                        5:

105.                          begin Data = "5";i <=i+1'b1;  end

106.                       6:

107.                            begin Data = "6";i <=i+1'b1;  end

108.                        7:

109.                           begin Data = "7";i <=i+1'b1;  end

110.                       8:

111.                            begin Data = "8";i <=i+1'b1;  end

112.                        9:

113.                           begin Data = "9";i <=i+1'b1;  end

114.                       10:

115.                            begin Data = "10";i <=i+1'b1;  end

116.                        11:

117.                           begin Data = "11";i <=i+1'b1;  end

118.                        12:

119.                           begin Data = "12";i <=i+1'b1;  end

120.                       13:

121.                            begin Data = "13";i <=i+1'b1;  end

122.                        14:

123.                           begin Data = "14";i <=i+1'b1;  end

124.                       15:

125.                            begin Data = "15";i <=i+1'b1;  end

126.                        16:

127.                           begin Data = "16";i <=i+1'b1;  end

128.

129.                        default :begin Data = "000";i <=i+1'b1;  end

130.

131.                      endcase

132.

133.                     4:

134.                     i <= 8'd0;//8'd7

135.        endcase

136.

137.

138.      assign line_rom2 = {"    ",8'h00,8'h01,8'h02,8'h68,8'h61,8'h70,8'h70,8'h79,8'h00,"   "};//"Number:",Data

139.//    assign oDATA = D1;

140.

141.

142.endmodule

代码6‑7 lcd1602_ctrlmod代码

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-05-19 20:55:44

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-06-28 23:43:55

7.//# Description:

8.//# @Modification History: 2019-05-19 20:58:05

9.//# Date                By             Version             Change Description:

10.//# ========================================================================= #

11.//# 2019-05-19 20:58:05

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module lcd1602_ctrlmod

17.(

18.    input CLOCK, RST_n,

19.     input iCall,

20.     output oDone,

21.    input       [127:0] line_rom1,  //LCD1602 1th row display

22.    input       [127:0] line_rom2,  //LCD1602 2th row display

23.     output [1:0]oCall,

24.     input iDone,

25.     output [7:0]oDATA

26.);

27.//LCD1602 init

28.localparam  DISP_SET    =   8'h38;  //Display mode: Set 16X2,5X8, 8 bits data

29.localparam  DISP_OFF    =   8'h08;  //Display off

30.localparam  CLR_SCR     =   8'h01;  //Clear the LCD

31.localparam  CURSOR_SET1 =   8'h06;  //Set Cursor

32.localparam  CURSOR_SET2 =   8'h0C;  //Display on

33.//Display 1th line

34.localparam  ROW1_ADDR   =   8'h05;  //Line1's first address

35.

36.//Display 2th line

37.localparam  ROW2_ADDR   =   8'h1C;  //Line2's first address

38.

39.

40.//---------------------------------------

41.

42.//   reg [63:0]iData;

43.     reg [7:0]D1;

44.     reg [7:0]i;

45.     reg [1:0]isCall;

46.     reg isDone;

47.     always @ ( posedge CLOCK or negedge RST_n )

48.         if( !RST_n )

49.              begin

50.                    D1 <= 8'd0;

51.                    i  <= 8'd0;

52.                    //iData <= 64'd0;

53.                    isCall[1:0] <= 2'b00;

54.                end

55.          else if ( iCall )

56.              case( i )

57.//************************初始化操作*********************************//

58.                     0 :

59.

60.                    if( iDone ) begin isCall[1]<= 1'b0;i <= i + 1'b1;end

61.                     else begin isCall[1] <= 1'b1; end//Display mode

62.

63.                     1 :

64.                     if( iDone ) begin isCall[1]<= 1'b0; i <= i + 1'b1; end

65.                     else begin isCall[1]<= 1'b1; end//Display off

66.

67.                     2 :

68.                     if( iDone ) begin isCall[1] <= 1'b0; i <= i + 1'b1; end

69.                     else begin isCall[1] <= 1'b1; end//Clear the LCD

70.

71.                    3 :

72.                     if( iDone ) begin isCall[1] <= 1'b0; i <= i + 1'b1;  end

73.                     else begin isCall[1] <= 1'b1; end//Set Cursor

74.

75.                     4 :

76.                     if( iDone ) begin isCall[1] <= 1'b0; i <= i + 1'b1;  end

77.                     else begin isCall[1] <= 1'b1; end//Display on

78.

79.                     5 :

80.                     begin isDone <= 1'b1; i <= i + 1'b1; end

81.                     6 :

82.                     begin isDone <= 1'b0; i <= i + 1'b1; end//初始化完成

83.                    //Display 1th line

84.

85.                    7 :

86.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = 8'h80; end

87.                     else begin isCall[0] <= 1'b1; end////Line1's first address

88.

89.                     8 :

90.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[127:120]; end

91.                     else begin isCall[0] <= 1'b1; end

92.

93.                     9 :

94.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[119:112]; end

95.                     else begin isCall[0] <= 1'b1; end

96.

97.                     10 :

98.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[111:104]; end

99.                     else begin isCall[0] <= 1'b1; end

100.

101.                     11 :

102.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[103: 96]; end

103.                     else begin isCall[0] <= 1'b1; end

104.

105.                     12 :

106.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 95: 88]; end

107.                     else begin isCall[0] <= 1'b1; end

108.

109.                     13 :

110.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 87: 80]; end

111.                     else begin isCall[0] <= 1'b1; end

112.

113.                     14 :

114.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 79: 72]; end

115.                     else begin isCall[0] <= 1'b1; end

116.

117.                     15 :

118.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 71: 64]; end

119.                     else begin isCall[0] <= 1'b1; end

120.

121.                     16 :

122.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 63: 56]; end

123.                     else begin isCall[0] <= 1'b1; end

124.

125.                     17 :

126.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 55: 48]; end

127.                     else begin isCall[0] <= 1'b1; end

128.

129.                     18 :

130.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 47: 40]; end

131.                     else begin isCall[0] <= 1'b1; end

132.

133.                     19 :

134.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 39: 32]; end

135.                     else begin isCall[0] <= 1'b1; end

136.

137.                     20 :

138.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 31: 24]; end

139.                     else begin isCall[0] <= 1'b1; end

140.

141.                     21 :

142.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 23: 16]; end

143.                     else begin isCall[0] <= 1'b1; end

144.

145.                     22 :

146.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[ 15:  8]; end

147.                     else begin isCall[0] <= 1'b1; end

148.

149.                     23 :

150.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom1[  7:  0]; end

151.                     else begin isCall[0] <= 1'b1; end//

152.        //Display 2th line

153.

154.                    24 :

155.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = 8'hC0; end

156.                     else begin isCall[0] <= 1'b1; end//Line2's first address

157.                     25 :

158.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[127:120]; end

159.                     else begin isCall[0] <= 1'b1; end

160.

161.                     26 :

162.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[119:112]; end

163.                     else begin isCall[0] <= 1'b1; end

164.

165.                     27 :

166.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[111:104]; end

167.                     else begin isCall[0] <= 1'b1; end

168.

169.                     28 :

170.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[103: 96]; end

171.                     else begin isCall[0] <= 1'b1; end

172.

173.                     29 :

174.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 95: 88]; end

175.                     else begin isCall[0] <= 1'b1; end

176.

177.                     30 :

178.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 87: 80]; end

179.                     else begin isCall[0] <= 1'b1; end

180.

181.                     31 :

182.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 79: 72]; end

183.                     else begin isCall[0] <= 1'b1; end

184.

185.                     32 :

186.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 71: 64]; end

187.                     else begin isCall[0] <= 1'b1; end

188.

189.                     33 :

190.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 63: 56]; end

191.                     else begin isCall[0] <= 1'b1; end

192.

193.                     34 :

194.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 55: 48]; end

195.                     else begin isCall[0] <= 1'b1; end

196.

197.                     35 :

198.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 47: 40]; end

199.                     else begin isCall[0] <= 1'b1; end

200.

201.                     36 :

202.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 39: 32]; end

203.                     else begin isCall[0] <= 1'b1; end

204.

205.                     37 :

206.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 31: 24]; end

207.                     else begin isCall[0] <= 1'b1; end

208.

209.                     38 :

210.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 23: 16]; end

211.                     else begin isCall[0] <= 1'b1; end

212.

213.                     39 :

214.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[ 15:  8]; end

215.                     else begin isCall[0] <= 1'b1; end

216.

217.                     40 :

218.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1;D1 = line_rom2[  7:  0]; end

219.                     else begin isCall[0] <= 1'b1; end//

220.

221.

222.                     41:

223.                     i <= 8'd7;//8'd7

224.        endcase

225.

226.

227.      assign oDone = isDone;

228.      assign oCall[1:0] = isCall[1:0];

229.      assign oDATA = D1;

230.

231.endmodule

代码6‑8 lcd1602_funcmod代码

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-05-19 21:06:32

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-06-30 22:59:30

7.//# Description:

8.//# @Modification History: 2019-05-19 20:58:19

9.//# Date                By             VerDATAn            Change Description:

10.//# ========================================================================= #

11.//# 2019-05-19 20:58:19

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module lcd1602_funcmod

17.(

18.    input CLOCK, RST_n,

19.

20.    //lcd1602 interface

21.    output              LCD1602_RS,     //H: Data; L: Instruction code

22.    output              LCD1602_RW,     //H: Read; L: Write

23.    output              LCD1602_EN,     //LCD1602 Chip enable signal

24.    output      [7:0]   LCD1602_D,      //LCD1602 Data interface

25.

26.    input       [127:0] line_rom1,  //LCD1602 1th row display

27.    input       [127:0] line_rom2,  //LCD1602 2th row display

28.    //Signal

29.    input iCall,

30.    output oDone

31.);

32.     parameter DELAY_TIME = 1000_000;   //Delay for 20ms

33.     //localparam DELAY_TIME = 20'd1000;        //Just for test

34.     parameter FCLK = 20'd100_000, FHALF = 20'd50_000; // 500hz,(1/500hz)/(1/50Mhz) FCLK 为一个周期

35.     //localparam FCLK = 20'd100, FHALF = 20'd50;        //Just for test

36.     parameter FF_Write = 8'd120;//FHALF 为半周期  //tsp1的延时

37.     //localparam FF_Write = 20'd16;        //Just for test

38.

39.reg [7:0] data_character1  [7:0];    //this is 心形   00H

40.reg [7:0] data_character2 [7:0];    //节           01H

41.reg [7:0] data_character3 [7:0];   //日           02H

42.always @(posedge CLOCK )

43.begin

44.    data_character1[0] <= 8'h00;

45.    data_character1[1] <= 8'h00;

46.    data_character1[2] <= 8'h00;

47.    data_character1[3] <= 8'h0a;

48.    data_character1[4] <= 8'h15;

49.    data_character1[5] <= 8'h0a;

50.    data_character1[6] <= 8'h04;

51.    data_character1[7] <= 8'h00;

52.

53.    data_character2[0] <= 8'h04;

54.    data_character2[1] <= 8'h14;

55.    data_character2[2] <= 8'h1f;

56.    data_character2[3] <= 8'h14;

57.    data_character2[4] <= 8'h0e;

58.    data_character2[5] <= 8'h04;

59.    data_character2[6] <= 8'h1f;

60.    data_character2[7] <= 8'h00;

61.

62.    data_character3[0] <= 8'h00;

63.    data_character3[1] <= 8'h1F;

64.    data_character3[2] <= 8'h11;

65.    data_character3[3] <= 8'h11;

66.    data_character3[4] <= 8'h1f;

67.    data_character3[5] <= 8'h11;

68.    data_character3[6] <= 8'h11;

69.    data_character3[7] <= 8'h1f;

70.end

71.

72.

73.     assign LCD1602_RW=1'b0;

74.     reg [19:0]C1,C2;

75.    reg [7:0]i,Go;

76.     reg [7:0]T; //D1 为暂存读取结果 T 为伪函数的操作空间

77.     reg rRS, rEN;

78.     reg [7:0]rDATA;

79.     reg isDone; //isQ 为 IO 的控制输出

80.

81.//LCD1602 init

82.localparam  DISP_SET    =   8'h38;  //Display mode: Set 16X2,5X8, 8 bits data

83.localparam  DISP_OFF    =   8'h08;  //Display off

84.localparam  CLR_SCR     =   8'h01;  //Clear the LCD

85.localparam  CURSOR_SET1 =   8'h06;  //Set Cursor

86.localparam  CURSOR_SET2 =   8'h0C;  //Display on

87.

88.//CGRAM 指令操作

89.localparam  CGRAM_SET  = 8'h40;

90.

91.//CGRAM 00H address

92.localparam  CGRAM0_ADDR  = 8'h48;

93.

94.//CGRAM 01H address

95.localparam  CGRAM1_ADDR  = 8'h50;

96.

97.//CGRAM 02H address

98.localparam  CGRAM2_ADDR  = 8'h80;

99.

100.//Display 1th line

101.localparam  ROW1_ADDR   =   8'h80;  //Line1's first address

102.

103.//Display 2th line

104.localparam  ROW2_ADDR   =   8'hC0;  //Line2's first address

105.

106.    always @ ( posedge CLOCK or negedge RST_n )

107.         if( !RST_n )

108.              begin

109.                    { C1,C2 } <={ 20'd0,20'd0 };

110.                    { i,Go } <= { 8'd0,6'd0 };

111.                     T  <= 8'd0;

112.                     { rRS, rEN, rDATA } <= 3'b000;

113.                      isDone <= 1'b0;

114.                end

115./***********************************************************************

116.下面步骤是写一个字节的伪函数。步骤 0 拉高片选,准备访问字节,并且进入伪函数。

117.步骤 1 准备写入数据并且进入伪函数。

118.步骤 2 拉低片选,步骤 3~4 则是用来产生完成信号。

119.***********************************************************************/

120.           else if( iCall )

121.                case( i )

122.

123.                    0://延时20ms

124.                        begin

125.                            { rRS,rEN } <= 2'b01;

126.                            if( C2 == DELAY_TIME -1) begin C2 <= 20'd0; i <= i + 1'b1; end

127.                            else C2 <= C2 + 1'b1;

128.                        end

129.

130.                    1:

131.                        begin  rRS <=1< span="">'b0;i <= i + 1'b1; end //{ rRS,rEN } <= 2'b01;

132.

133.                    2:

134.                        begin T <= 8'h00; i <= FF_Write; Go <= i + 1'b1; end   //IDLE

135.

136.                    3:

137.                        begin T <= DISP_SET; i <= FF_Write; Go <= i + 1'b1; end

138.

139.                    4:

140.                        begin T <= DISP_OFF; i <= FF_Write; Go <= i + 1'b1; end

141.

142.                    5:

143.                        begin T <= CLR_SCR; i <= FF_Write; Go <= i + 1'b1; end

144.

145.                    6:

146.                        begin T <= CURSOR_SET1; i <= FF_Write; Go <= i + 1'b1; end

147.

148.                    7:

149.                         begin T <= CURSOR_SET2; i <= FF_Write; Go <= i + 1'b1; end

150.

151.

152.                    8:

153.                        begin isDone <= 1'b1; i <= i + 1'b1; end

154.

155.                    9:

156.                        begin isDone <= 1'b0; i <= i + 1'b1; end

157.

158.                    10://write CGRAM

159.                        begin rRS <=1< span="">'b0; i <= i + 1'b1; end//{ rRS,rEN } <= 2'b00;CGRAM_SET

160.                    11:

161.                         i <= i + 1'b1;//begin T <= CGRAM_SET; i <= FF_Write; Go <= i + 1'b1; end

162.                    12:

163.                         begin T <= CGRAM_SET; i <= FF_Write; Go <= i + 1'b1; end  //CGRAM0_ADDR

164.                    13:

165.                        begin rRS <=1< span="">'b1; i <= i + 1'b1; end//{ rRS,rEN } <= 2'b11;

166.

167.                    14,15,16,17,18,19,20,21 :

168.                         begin T <= data_character1[i-14]; i <= FF_Write; Go <= i + 1'b1; end

169.

170.                    22://write CGRAM

171.                        begin rRS <=1< span="">'b0; i <= i + 1'b1; end//{ rRS,rEN } <= 2'b00;CGRAM_SET

172.                    23:

173.                         begin T <= CGRAM0_ADDR; i <= FF_Write; Go <= i + 1'b1; end

174.                    24:

175.                        begin rRS <=1< span="">'b1; i <= i + 1'b1; end//{ rRS,rEN } <= 2'b11;

176.                    25,26,27,28,29,30,31,32 :

177.                         begin T <= data_character2[i-25]; i <= FF_Write; Go <= i + 1'b1; end

178.

179.                    33://write CGRAM

180.                        begin rRS <=1< span="">'b0; i <= i + 1'b1; end//{ rRS,rEN } <= 2'b00;CGRAM_SET

181.                    34:

182.                         begin T <= CGRAM1_ADDR; i <= FF_Write; Go <= i + 1'b1; end

183.                    35:

184.                        begin rRS <=1< span="">'b1; i <= i + 1'b1; end//{ rRS,rEN } <= 2'b11;

185.                    36,37,38,39,40,41,42,43 :

186.                         begin T <= data_character3[i-36]; i <= FF_Write; Go <= i + 1'b1; end

187.

188.                    44:

189.                        begin rRS <=1< span="">'b0; i <= i + 1'b1; end//{ rRS,rEN } <= 2'b00;

190.                    45:

191.                         begin T <= ROW1_ADDR; i <= FF_Write; Go <= i + 1'b1; end

192.                    46:

193.                        begin rRS <=1< span="">'b1; i <= i + 1'b1; end//{ rRS,rEN } <= 2'b11;

194.

195.                    47:

196.                         begin T <= line_rom1[127:120]; i <= FF_Write; Go <= i + 1'b1; end

197.                    48:

198.                         begin T <= line_rom1[119:112]; i <= FF_Write; Go <= i + 1'b1; end

199.                    49:

200.                         begin T <= line_rom1[111:104]; i <= FF_Write; Go <= i + 1'b1; end

201.                    50:

202.                         begin T <= line_rom1[103: 96]; i <= FF_Write; Go <= i + 1'b1; end

203.                    51:

204.                         begin T <= line_rom1[ 95: 88]; i <= FF_Write; Go <= i + 1'b1; end

205.                    52:

206.                         begin T <= line_rom1[ 87: 80]; i <= FF_Write; Go <= i + 1'b1; end

207.                    53:

208.                         begin T <= line_rom1[ 79: 72]; i <= FF_Write; Go <= i + 1'b1; end

209.                    54:

210.                         begin T <= line_rom1[ 71: 64]; i <= FF_Write; Go <= i + 1'b1; end

211.                    55:

212.                         begin T <= line_rom1[ 63: 56]; i <= FF_Write; Go <= i + 1'b1; end

213.                    56:

214.                         begin T <= line_rom1[ 55: 48]; i <= FF_Write; Go <= i + 1'b1; end

215.                    57:

216.                         begin T <= line_rom1[ 47: 40]; i <= FF_Write; Go <= i + 1'b1; end

217.                    58:

218.                         begin T <= line_rom1[ 39: 32]; i <= FF_Write; Go <= i + 1'b1; end

219.                    59:

220.                         begin T <= line_rom1[ 31: 24]; i <= FF_Write; Go <= i + 1'b1; end

221.                    60:

222.                         begin T <= line_rom1[ 23: 16]; i <= FF_Write; Go <= i + 1'b1; end

223.                    61:

224.                         begin T <= line_rom1[ 15:  8]; i <= FF_Write; Go <= i + 1'b1; end

225.                    62:

226.                         begin T <= line_rom1[  7:  0]; i <= FF_Write; Go <= i + 1'b1; end

227.

228.                    /**********************************************************************/

229.                    63:

230.                        begin rRS <=1< span="">'b0; i <= i + 1'b1; end//{ rRS,rEN } <= 2'b00;

231.                    64:

232.                         begin T <= ROW2_ADDR; i <= FF_Write; Go <= i + 1'b1; end

233.                    65:

234.                        begin  rRS <=1< span="">'b1;i <= i + 1'b1; end//{ rRS,rEN } <= 2'b11;

235.                   66:

236.                        i <= i + 1'b1;

237.                    67:

238.                        begin T <= line_rom2[127:120]; i <= FF_Write; Go <= i + 1'b1; end

239.                   68:

240.                        begin T <= line_rom2[119:112]; i <= FF_Write; Go <= i + 1'b1; end

241.                    69:

242.                        begin T <= line_rom2[111:104]; i <= FF_Write; Go <= i + 1'b1; end

243.                    70:

244.                        begin T <= line_rom2[103: 96]; i <= FF_Write; Go <= i + 1'b1; end

245.                    71:

246.                        begin T <= line_rom2[ 95: 88]; i <= FF_Write; Go <= i + 1'b1; end

247.                    72:

248.                        begin T <= line_rom2[ 87: 80]; i <= FF_Write; Go <= i + 1'b1; end

249.                    73:

250.                        begin T <= line_rom2[ 79: 72]; i <= FF_Write; Go <= i + 1'b1; end

251.                    74:

252.                        begin T <= line_rom2[ 71: 64]; i <= FF_Write; Go <= i + 1'b1; end

253.                    75:

254.                        begin T <= line_rom2[ 63: 56]; i <= FF_Write; Go <= i + 1'b1; end

255.                    76:

256.                        begin T <= line_rom2[ 55: 48]; i <= FF_Write; Go <= i + 1'b1; end

257.                    77:

258.                        begin T <= line_rom2[ 47: 40]; i <= FF_Write; Go <= i + 1'b1; end

259.                    78:

260.                        begin T <= line_rom2[ 39: 32]; i <= FF_Write; Go <= i + 1'b1; end

261.                    79:

262.                        begin T <= line_rom2[ 31: 24]; i <= FF_Write; Go <= i + 1'b1; end

263.                    80:

264.                        begin T <= line_rom2[ 23: 16]; i <= FF_Write; Go <= i + 1'b1; end

265.                    81:

266.                        begin T <= line_rom2[ 15:  8]; i <= FF_Write; Go <= i + 1'b1; end

267.                    82:

268.                        begin T <= line_rom2[  7:  0]; i <= FF_Write; Go <= i + 1'b1; end//Go <= i + 1'b1;

269.                    83:

270.                        begin { rRS,rEN } <= 2'b01; i <= i + 1'b1; end

271.

272.                    84:

273.                      begin isDone <= 1'b1; i <= i + 1'b1; end

274.

275.                    85:

276.                      begin isDone <= 1'b0; i <= 8'd44; end//

277.

278.                      /******************/

279.

280.                      120:

281.                      begin

282.

283.                          rDATA <= T;//

284.

285.                        if( C1 == 0 ) rEN <= 1'b1;

286.                        else if( C1 == FHALF ) rEN <= 1'b0;

287.

288.                        if( C1 == FCLK -1) begin C1 <= 20'd0; i <= i + 1'b1; end

289.                        else C1 <= C1 + 1'b1;

290.                      end

291.

292.                     121:

293.                      i <= Go;

294.

295.                 endcase

296.

297./***********************************************************************

298.以下内容为相关输出驱动声明,其中 rDATA 驱动 LCD1602_D_DATA, D 驱动 oData    。

299.***********************************************************************/

300.        assign { LCD1602_RS,LCD1602_EN } = { rRS,rEN };

301.        assign LCD1602_D = rDATA ;  //isQ ? rDATA : 1'bz;

302.        assign oDone = isDone;

303.

304.endmodule

(0)

相关推荐