[Verilog HDL] verilog写的LCD1602 显示

[复制链接]
 楼主| gaochy1126 发表于 2023-1-31 21:48 | 显示全部楼层 |阅读模式
  1. module lcd_1602_driver(
  2.                 clk    ,
  3.                 rst_n  ,
  4.                 lcd_en ,
  5.                 lcd_rw ,  //因为只执行写操作,所以永远为0.
  6.                 lcd_rs ,
  7.                 lcd_data

  8.               );
  9. input        clk    ;
  10. input        rst_n  ;

  11. output       lcd_en ;
  12. output       lcd_rw ;
  13. output       lcd_rs ;
  14. output [7:0] lcd_data;
  15. wire         clk ;
  16. wire         rst_n  ;
  17. wire         lcd_en ;
  18. wire         lcd_rw;
  19. reg  [7:0]   lcd_data;
  20. reg          lcd_rs  ;
  21. reg [5:0]    c_state ;
  22. reg [5:0]    n_state ;
  23. wire  [127:0]  row_1;
  24. wire  [127:0]  row_2;
  25. assign row_1 ="i am liu xiao yi" ;  //第一行显示的内容
  26. assign row_2 ="happy everyday !";  //第二行显示的内容
  27. //----------------------------------------------------------------------
  28. //initialize
  29. //first step is waitng more than 20 ms. 数据手册要求的,目的是等待系统上电稳定。
  30. parameter TIME_20MS = 1000_000 ; //20000000/20=1000_000
  31. //parameter TIME_15MS = 9'h100 ; //just for test
  32. parameter TIME_500HZ= 100_000  ; //
  33. //parameter TIME_500HZ= 4'hf;  //just for test
  34. //use gray code   
  35. parameter         IDLE=    8'h00  ;  //因为此状态机一共有40个状态,所以这里用了格雷码,一次只有1位发生改变。00 01 03 02                     
  36. parameter SET_FUNCTION=    8'h01  ;      
  37. parameter     DISP_OFF=    8'h03  ;
  38. parameter   DISP_CLEAR=    8'h02  ;
  39. parameter   ENTRY_MODE=    8'h06  ;
  40. parameter   DISP_ON   =    8'h07  ;
  41. parameter    ROW1_ADDR=    8'h05  ;      
  42. parameter       ROW1_0=    8'h04  ;
  43. parameter       ROW1_1=    8'h0C  ;
  44. parameter       ROW1_2=    8'h0D  ;
  45. parameter       ROW1_3=    8'h0F  ;
  46. parameter       ROW1_4=    8'h0E  ;
  47. parameter       ROW1_5=    8'h0A  ;
  48. parameter       ROW1_6=    8'h0B  ;
  49. parameter       ROW1_7=    8'h09  ;
  50. parameter       ROW1_8=  8'h08  ;
  51. parameter       ROW1_9=    8'h18  ;
  52. parameter       ROW1_A=    8'h19  ;
  53. parameter       ROW1_B=    8'h1B  ;
  54. parameter       ROW1_C=    8'h1A  ;
  55. parameter       ROW1_D=    8'h1E  ;
  56. parameter       ROW1_E=    8'h1F  ;
  57. parameter       ROW1_F=    8'h1D  ;

  58. parameter    ROW2_ADDR=    8'h1C  ;
  59. parameter       ROW2_0=    8'h14  ;
  60. parameter       ROW2_1=    8'h15  ;
  61. parameter       ROW2_2=    8'h17  ;
  62. parameter       ROW2_3=    8'h16  ;
  63. parameter       ROW2_4=    8'h12  ;
  64. parameter       ROW2_5=    8'h13  ;
  65. parameter       ROW2_6=    8'h11  ;
  66. parameter       ROW2_7=    8'h10  ;
  67. parameter       ROW2_8=    8'h30  ;
  68. parameter       ROW2_9=    8'h31  ;
  69. parameter       ROW2_A=    8'h33  ;
  70. parameter       ROW2_B=    8'h32  ;
  71. parameter       ROW2_C=    8'h36  ;
  72. parameter       ROW2_D=    8'h37  ;
  73. parameter       ROW2_E=    8'h35  ;
  74. parameter       ROW2_F=    8'h34  ;


  75. //20ms的计数器,即初始化第一步
  76. reg [19:0] cnt_20ms ;
  77. always  @(posedge clk or negedge rst_n)begin
  78.     if(rst_n==1'b0)begin
  79.         cnt_20ms<=0;
  80.     end
  81.     else if(cnt_20ms == TIME_20MS -1)begin
  82.         cnt_20ms<=cnt_20ms;
  83.     end
  84.     else
  85.         cnt_20ms<=cnt_20ms + 1 ;
  86. end
  87. wire delay_done = (cnt_20ms==TIME_20MS-1)? 1'b1 : 1'b0 ;
  88. //----------------------------------------------------------------------
  89. //500ns  这里是分频,因为LCD1602的工作频率是500HZ,而FPGA是50Mhz,所以要分频
  90. reg [19:0] cnt_500hz;
  91. always  @(posedge clk or negedge rst_n)begin
  92.     if(rst_n==1'b0)begin
  93.         cnt_500hz <= 0;
  94.     end
  95.     else if(delay_done==1)begin
  96.         if(cnt_500hz== TIME_500HZ - 1)
  97.             cnt_500hz<=0;
  98.         else
  99.             cnt_500hz<=cnt_500hz + 1 ;
  100.     end
  101.     else
  102.         cnt_500hz<=0;
  103. end

  104. assign lcd_en = (cnt_500hz>(TIME_500HZ-1)/2)? 1'b0 : 1'b1;  //下降沿
  105. assign write_flag = (cnt_500hz==TIME_500HZ - 1) ? 1'b1 : 1'b0 ;

  106. //set_function ,display off ,display clear ,entry mode set
  107. //----------------------------------------------------------------------状态机
  108. always  @(posedge clk or negedge rst_n)begin
  109.     if(rst_n==1'b0)begin
  110.         c_state <= IDLE    ;
  111.     end
  112.     else if(write_flag==1) begin
  113.         c_state<= n_state  ;
  114.     end
  115.     else
  116.         c_state<=c_state   ;
  117. end

  118. always  @(*)begin
  119.     case (c_state)
  120.         IDLE: n_state = SET_FUNCTION ;
  121. SET_FUNCTION: n_state = DISP_OFF     ;
  122.     DISP_OFF: n_state = DISP_CLEAR   ;
  123.   DISP_CLEAR: n_state = ENTRY_MODE   ;
  124.   ENTRY_MODE: n_state = DISP_ON      ;
  125.   DISP_ON   : n_state = ROW1_ADDR    ;
  126.    ROW1_ADDR: n_state = ROW1_0       ;
  127.       ROW1_0: n_state = ROW1_1       ;
  128.       ROW1_1: n_state = ROW1_2       ;
  129.       ROW1_2: n_state = ROW1_3       ;
  130.       ROW1_3: n_state = ROW1_4       ;
  131.       ROW1_4: n_state = ROW1_5       ;
  132.       ROW1_5: n_state = ROW1_6       ;
  133.       ROW1_6: n_state = ROW1_7       ;
  134.       ROW1_7: n_state = ROW1_8       ;
  135.       ROW1_8: n_state = ROW1_9       ;
  136.       ROW1_9: n_state = ROW1_A       ;
  137.       ROW1_A: n_state = ROW1_B       ;
  138.       ROW1_B: n_state = ROW1_C       ;
  139.       ROW1_C: n_state = ROW1_D       ;
  140.       ROW1_D: n_state = ROW1_E       ;
  141.       ROW1_E: n_state = ROW1_F       ;
  142.       ROW1_F: n_state = ROW2_ADDR    ;

  143.    ROW2_ADDR: n_state = ROW2_0       ;
  144.       ROW2_0: n_state = ROW2_1       ;
  145.       ROW2_1: n_state = ROW2_2       ;
  146.       ROW2_2: n_state = ROW2_3       ;
  147.       ROW2_3: n_state = ROW2_4       ;
  148.       ROW2_4: n_state = ROW2_5       ;
  149.       ROW2_5: n_state = ROW2_6       ;
  150.       ROW2_6: n_state = ROW2_7       ;
  151.       ROW2_7: n_state = ROW2_8       ;
  152.       ROW2_8: n_state = ROW2_9       ;
  153.       ROW2_9: n_state = ROW2_A       ;
  154.       ROW2_A: n_state = ROW2_B       ;
  155.       ROW2_B: n_state = ROW2_C       ;
  156.       ROW2_C: n_state = ROW2_D       ;
  157.       ROW2_D: n_state = ROW2_E       ;
  158.       ROW2_E: n_state = ROW2_F       ;
  159.       ROW2_F: n_state = ROW1_ADDR    ;
  160.      default: n_state = n_state      ;
  161.    endcase
  162.    end   

  163.    assign lcd_rw = 0;
  164.    always  @(posedge clk or negedge rst_n)begin
  165.        if(rst_n==1'b0)begin
  166.            lcd_rs <= 0 ;   //order or data  0: order 1:data
  167.        end
  168.        else if(write_flag == 1)begin
  169.            if((n_state==SET_FUNCTION)||(n_state==DISP_OFF)||
  170.               (n_state==DISP_CLEAR)||(n_state==ENTRY_MODE)||
  171.               (n_state==DISP_ON ) ||(n_state==ROW1_ADDR)||
  172.               (n_state==ROW2_ADDR))begin
  173.            lcd_rs<=0 ;
  174.            end
  175.            else  begin
  176.            lcd_rs<= 1;
  177.            end
  178.        end
  179.        else begin
  180.            lcd_rs<=lcd_rs;
  181.        end     
  182.    end                  

  183.    always  @(posedge clk or negedge rst_n)begin
  184.        if(rst_n==1'b0)begin
  185.            lcd_data<=0 ;
  186.        end
  187.        else  if(write_flag)begin
  188.            case(n_state)

  189.                  IDLE: lcd_data <= 8'hxx;
  190.          SET_FUNCTION: lcd_data <= 8'h38; //2*16 5*8 8位数据
  191.              DISP_OFF: lcd_data <= 8'h08;
  192.            DISP_CLEAR: lcd_data <= 8'h01;
  193.            ENTRY_MODE: lcd_data <= 8'h06;
  194.            DISP_ON   : lcd_data <= 8'h0c;  //显示功能开,没有光标,且不闪烁,
  195.             ROW1_ADDR: lcd_data <= 8'h80; //00+80
  196.                ROW1_0: lcd_data <= row_1 [127:120];
  197.                ROW1_1: lcd_data <= row_1 [119:112];
  198.                ROW1_2: lcd_data <= row_1 [111:104];
  199.                ROW1_3: lcd_data <= row_1 [103: 96];
  200.                ROW1_4: lcd_data <= row_1 [ 95: 88];
  201.                ROW1_5: lcd_data <= row_1 [ 87: 80];
  202.                ROW1_6: lcd_data <= row_1 [ 79: 72];
  203.                ROW1_7: lcd_data <= row_1 [ 71: 64];
  204.                ROW1_8: lcd_data <= row_1 [ 63: 56];
  205.                ROW1_9: lcd_data <= row_1 [ 55: 48];
  206.                ROW1_A: lcd_data <= row_1 [ 47: 40];
  207.                ROW1_B: lcd_data <= row_1 [ 39: 32];
  208.                ROW1_C: lcd_data <= row_1 [ 31: 24];
  209.                ROW1_D: lcd_data <= row_1 [ 23: 16];
  210.                ROW1_E: lcd_data <= row_1 [ 15:  8];
  211.                ROW1_F: lcd_data <= row_1 [  7:  0];

  212.             ROW2_ADDR: lcd_data <= 8'hc0;      //40+80
  213.                ROW2_0: lcd_data <= row_2 [127:120];
  214.                ROW2_1: lcd_data <= row_2 [119:112];
  215.                ROW2_2: lcd_data <= row_2 [111:104];
  216.                ROW2_3: lcd_data <= row_2 [103: 96];
  217.                ROW2_4: lcd_data <= row_2 [ 95: 88];
  218.                ROW2_5: lcd_data <= row_2 [ 87: 80];
  219.                ROW2_6: lcd_data <= row_2 [ 79: 72];
  220.                ROW2_7: lcd_data <= row_2 [ 71: 64];
  221.                ROW2_8: lcd_data <= row_2 [ 63: 56];
  222.                ROW2_9: lcd_data <= row_2 [ 55: 48];
  223.                ROW2_A: lcd_data <= row_2 [ 47: 40];
  224.                ROW2_B: lcd_data <= row_2 [ 39: 32];
  225.                ROW2_C: lcd_data <= row_2 [ 31: 24];
  226.                ROW2_D: lcd_data <= row_2 [ 23: 16];
  227.                ROW2_E: lcd_data <= row_2 [ 15:  8];
  228.                ROW2_F: lcd_data <= row_2 [  7:  0];
  229.            endcase                     
  230.        end
  231.        else
  232.               lcd_data<=lcd_data ;
  233.    end

  234. endmodule


您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:这个社会混好的两种人:一是有权有势,二是没脸没皮的。

1148

主题

11651

帖子

26

粉丝
快速回复 在线客服 返回列表 返回顶部