一天一个设计实例-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 |