• 基于FPGA的LCD1602驱动(含代码)


    目录

     LCD1602显示原理

    LCD1602接口

    LCD1602操作时序

    (1)读操作时序

    (2)写操作时序

     LCD1602初始化

    LCD1602读写数据 


     LCD1602显示原理

    将LCD显示屏与FPGA连接之后,需要做的第一件事就是进行LCD驱动(也就是LCD初始化),之后往LCD里写一些字符,调试LCD是否可以正常使用

    这里用的是LCD1602如下图:一共2行,一行16个显示块,其地址和屏幕的对应关系如下:

     如果想在屏幕左上角显示字符‘A’,那么就把字符‘A’的字符代码41H写入DDRAM的00H地址处即可

    但如果要显示CGROM中没有的字符,比如摄氏温标的符号,那么就只有先在CGRAM中定义,然后再在DDRAM中写入这个自定义字符的字符代码即可。具体参考这篇:基于FPGA的LCD1602显示屏驱动_panhongfeng111的博客-CSDN博客_基于fpga的lcd显示

    LCD1602接口

     对这里面比较重要的几个接口进行说明:

    (1)RS 命令/数据选择引脚当RS为低电平时,选择命令;当RS为高电平时,选择数据。

    (2)RW 读/写选择引脚,当RW为低电平时,向LCD1602写入命令或数据;当RW为高电平时,从LCD1602读取状态或数据。如果不需要进行读取操作,可以直接将其接VSS。

    (3) 执行命令的使能引脚。

    (4)D0—D7 并行数据输入/输出引脚

    LCD1602操作时序

    (1)读操作时序

    读状态:输入RS=0,RW=1,E=高脉冲。输出:D0—D7为状态字。

    读数据:输入RS=1,RW=1,E=高脉冲。输出:D0—D7为数据。

    (2)写操作时序

     写命令:输入RS=0,RW=0,E=高脉冲。输出:无。

     写数据:输入RS=1,RW=0,E=高脉冲。输出:无。
     

     LCD1602初始化

    根据数据手册,LCD的初始化需要完成下面12步:

    1   延时15ms
    2   写指令38H(不检测忙信号)
    3   延时5ms
    4   写指令38H(不检测忙信号)
    5   延时5ms
    6   写指令38H(不检测忙信号)
    7   以后每次写指令、读/写数据操作均需要检测忙信号
    8   写指令38H:显示模式设置
    9   写指令08H:显示关闭
    10  写指令01H:显示清屏
    11  写指令06H:显示光标移动设置
    12  写指令0CH:显示开及光标设置

     这里面有1次15ms延时,和2次5ms延时,写指令是38H,我们可以把1~8步合在一起,延时25ms,写指令38H,那么初始化就可以简化为5步:

    LCD1602读写数据 

    初始化完成之后一般往LCD里写入一些字符串,验证一下是否可以正常显示

    写的时候,要先指定地址,如果在第一行写入,首地址是00H,再加上DB7的1,即80H

    如果在第二行写入,首地址是40H,再加上DB7的1,即C0H

    因此在初始化完成之后,加入addr1 write1 addr2 write2 四个状态

    把写数据和初始化放在一起,完整状态机如下:

    1. module lcd(
    2. input clk ,
    3. input rst ,
    4. input delay_en , //延时完成
    5. output reg lcd_rs ,//状态or数据选择
    6. output reg lcd_rw ,//or写选择
    7. output reg lcd_en ,//使能信号
    8. output reg [7:0] lcd_data //输出LCD指令
    9. );
    10. reg [7:0] data_display ;//显示数据
    11. reg [5:0] data_cnt; //数据计数器
    12. reg [3:0] state; //状态
    13. parameter IDLE =4'd0;
    14. parameter S0 =4'd1;
    15. parameter S1 =4'd2;
    16. parameter S2 =4'd3;
    17. parameter S3 =4'd4;
    18. parameter S4 =4'd5;
    19. parameter Addr1=4'd6;
    20. parameter WR1 =4'd7;
    21. parameter Addr2=4'd8;
    22. parameter WR2 =4'd9;
    23. parameter stop =4'd10;
    24. always @(*) begin//根据数据计数器输出显示数据
    25. case(data_cnt)
    26. 5'd0: data_display = "H";
    27. 5'd1: data_display = "E";
    28. 5'd2: data_display = "L";
    29. 5'd3: data_display = "L";
    30. 5'd4: data_display = "O";
    31. 5'd5: data_display = "W";
    32. 5'd6: data_display = "-";
    33. 5'd7: data_display = "W";
    34. 5'd8: data_display = "O";
    35. 5'd9: data_display = "R";
    36. 5'd10: data_display = "L";
    37. 5'd11: data_display = "D";
    38. 5'd12: data_display = "1";
    39. 5'd13: data_display = "6";
    40. 5'd14: data_display = "0";
    41. 5'd15: data_display = "2";
    42. 5'd16: data_display = "h";
    43. 5'd17: data_display = "e";
    44. 5'd18: data_display = "l";
    45. 5'd19: data_display = "l";
    46. 5'd20: data_display = "o";
    47. 5'd21: data_display = "w";
    48. 5'd22: data_display = "h";
    49. 5'd23: data_display = "e";
    50. 5'd24: data_display = "l";
    51. 5'd26: data_display = "l";
    52. 5'd27: data_display = "o";
    53. 5'd28: data_display = "w";
    54. 5'd29: data_display = "-";
    55. 5'd30: data_display = "-";
    56. 5'd31: data_display = "-";
    57. default:data_display = "-";
    58. endcase
    59. end
    60. always@(posedge clk)begin
    61. if(rst)begin
    62. lcd_rs <=1'd0;
    63. lcd_rw <=1'd0;
    64. lcd_en <=1'd0;
    65. lcd_data<=8'd0;
    66. data_cnt<=6'd0;
    67. state <=IDLE;
    68. end
    69. else begin
    70. case(state)
    71. IDLE :begin
    72. if(delay_en)begin
    73. state <=S0;
    74. end
    75. else begin
    76. state <=IDLE;
    77. end
    78. end
    79. S0 :begin
    80. lcd_rs <=1'd0;
    81. lcd_rw <=1'd0;
    82. lcd_en <=1'd1;
    83. lcd_data<=8'h38;
    84. state <=S1;
    85. end
    86. S1 :begin
    87. lcd_rs <=1'd0;
    88. lcd_rw <=1'd0;
    89. lcd_en <=1'd1;
    90. lcd_data<=8'h08;
    91. state <=S2;
    92. end
    93. S2 :begin
    94. lcd_rs <=1'd0;
    95. lcd_rw <=1'd0;
    96. lcd_en <=1'd1;
    97. lcd_data<=8'h01;
    98. state <=S3;
    99. end
    100. S3 :begin
    101. lcd_rs <=1'd0;
    102. lcd_rw <=1'd0;
    103. lcd_en <=1'd1;
    104. lcd_data<=8'h06;
    105. state <=S4;
    106. end
    107. S4 :begin
    108. lcd_rs <=1'd0;
    109. lcd_rw <=1'd0;
    110. lcd_en <=1'd1;
    111. lcd_data<=8'h0C;
    112. state <=Addr1;
    113. end
    114. Addr1:begin
    115. lcd_rs <=1'd0;
    116. lcd_rw <=1'd0;
    117. lcd_en <=1'd1;
    118. lcd_data<=8'h80;//第一行地址
    119. state <=WR1;
    120. end
    121. WR1 :begin
    122. lcd_rs <=1'd1;
    123. lcd_rw <=1'd0;
    124. lcd_en <=1'd1;
    125. if(data_cnt==6'd15)begin//第一行写完
    126. state <=Addr2;
    127. data_cnt<=6'd0;
    128. end
    129. else begin
    130. data_cnt<=data_cnt+6'd1;
    131. state <=WR1;
    132. lcd_data<=data_display;//显示第一行数据
    133. end
    134. end
    135. Addr2:begin
    136. lcd_rs <=1'd0;
    137. lcd_rw <=1'd0;
    138. lcd_en <=1'd1;
    139. lcd_data<=8'hC0;//第二行地址
    140. state <=WR2;
    141. end
    142. WR2 :begin
    143. lcd_rs <=1'd1;
    144. lcd_rw <=1'd0;
    145. lcd_en <=1'd1;
    146. if(data_cnt==6'd15)begin//第二行写完
    147. state <=stop;
    148. data_cnt<=6'd0;
    149. end
    150. else begin
    151. data_cnt<=data_cnt+6'd1;
    152. lcd_data<=data_display;//显示第二行数据
    153. state <=WR2;
    154. end
    155. end
    156. stop :begin
    157. lcd_rs <=1'd0;
    158. lcd_rw <=1'd0;
    159. lcd_en <=1'd0;
    160. lcd_data<=8'h38;
    161. state <=IDLE;
    162. end
    163. endcase
    164. end
    165. end
    166. endmodule

    仿真结果如下:

  • 相关阅读:
    Hyperf微服务搭建
    mybatis 连接mysql 实现CRUD
    使用 OpenSSL 创建ssl证书
    Chapter6:线性离散系统的分析
    vue3 的系统学习(依据菜鸟教程)
    java计算机毕业设计网上图书销售系统源程序+mysql+系统+lw文档+远程调试
    带433遥控紫外线照明灯触摸芯片-DLT8SA20A-杰力科创
    php mb_strpos() 函数详解
    基于 Python 解析 XML 文件并将数据存储到 MongoDB 数据库
    【Leetcode笔记】236.二叉树的最近公共祖先
  • 原文地址:https://blog.csdn.net/weixin_46188211/article/details/126601323