FPGA中使用LCD1602的驱动问题

VHDL代码如下,输入的时钟clk为50MHz,代码中的counter有什么用?且为什么要设置成000f?

module Lcd1602Drv(
input clk,
input rst,

input          [7:0]    dis_data0, dis_data10, dis_data20,
input          [7:0]    dis_data1, dis_data11, dis_data21,
input          [7:0]    dis_data2, dis_data12, dis_data22,
input          [7:0]    dis_data3, dis_data13, dis_data23,
input          [7:0]    dis_data4, dis_data14, dis_data24,
input          [7:0]    dis_data5, dis_data15, dis_data25,
input          [7:0]    dis_data6, dis_data16, dis_data26,
input          [7:0]    dis_data7, dis_data17, dis_data27,
input          [7:0]    dis_data8, dis_data18, dis_data28,
input          [7:0]    dis_data9, dis_data19, dis_data29,dis_data30,dis_data31,

output  reg    [7:0]    dat,
output  reg             rs,
output                  rw,
output                  en
);


reg         [15:0]      counter; 
reg         [ 5:0]      current; 
reg                     clkr; 
reg                     e;

 parameter    [5:0]      set0 =6'd0; 
 parameter    [5:0]      set1 =6'd1; 
 parameter    [5:0]      set2 =6'd2; 
 parameter    [5:0]      set3 =6'd3; 
 parameter    [5:0]      set4 =6'd4;   
 parameter    [5:0]      dat0 =6'd5; 
 parameter    [5:0]      dat1 =6'd6; 
 parameter    [5:0]      dat2 =6'd7; 
 parameter    [5:0]      dat3 =6'd8; 
 parameter    [5:0]      dat4 =6'd9;
              
 parameter    [5:0]      dat5 =6'd10;
 parameter    [5:0]      dat6 =6'd11; 
 parameter    [5:0]      dat7 =6'd12; 
 parameter    [5:0]      dat8 =6'd13; 
 parameter    [5:0]      dat9 =6'd14;
 parameter    [5:0]      dat10=6'd15; 
 parameter    [5:0]      dat11=6'd16;
 parameter    [5:0]      dat12=6'd17;  
 parameter    [5:0]      dat13=6'd18; 
 parameter    [5:0]      dat14=6'd19;
             
 parameter    [5:0]      dat15=6'd20; 
 parameter    [5:0]      dat16=6'd21;
 parameter    [5:0]      dat17=6'd22; 
 parameter    [5:0]      dat18=6'd23; 
 parameter    [5:0]      dat19=6'd24; 
 parameter    [5:0]      dat20=6'd26; 
 parameter    [5:0]      dat21=6'd27; 
 parameter    [5:0]      dat22=6'd28; 
 parameter    [5:0]      dat23=6'd29;
            
 parameter    [5:0]      dat24=6'd30; 
 parameter    [5:0]      dat25=6'd31; 
 parameter    [5:0]      dat26=6'd32; 
 parameter    [5:0]      dat27=6'd33; 
 parameter    [5:0]      dat28=6'd34; 
 parameter    [5:0]      dat29=6'd35; 
 parameter    [5:0]      dat30=6'd36; 
 parameter    [5:0]      dat31=6'd37;  
             
 parameter    [5:0]      set5 =6'd38;
              
 parameter    [5:0]      fini0 =6'd39; 
  

always @(posedge clk)begin         
    if(rst)begin
        counter <=0;
        clkr    <=0;
    end
    else begin
        counter<=counter+1; 
        if(counter==16'h000f)  
            clkr=~clkr; 
    end
end 

      
always @(posedge clkr) begin 
    if(rst)begin
            current <=set0;
            dat     <=0;
            rs      <=0;
            e       <=1;
    end
    else begin
        case(current) 
            set0:   begin  e<=0;rs<=0; dat<=8'h38;     current<=set1;         end //0X38 采用5*10点阵显示
            set1:   begin  e<=0;rs<=0; dat<=8'h0C;     current<=set2;         end //0x0c 显示光标,光标出现的字符会闪烁
            set2:   begin  e<=0;rs<=0; dat<=8'h06;     current<=set3;         end //0x06 读或写完一个数据操作之后 地址指针加1,光标右移一格 整屏显示不移动
            set3:   begin  e<=0;rs<=0; dat<=8'h01;     current<=set4;         end //0x01 清除屏幕
            set4:   begin  e<=0;rs<=0; dat<=8'h80;     current<=dat0;         end //0X80 设定当前要读/写数据的显示缓冲区DDRAM地址 一共可以设定128个地址
            
            dat0:   begin  e<=0;rs<=1; dat<=dis_data0;  current<=dat1;      end    
            dat1:   begin  e<=0;rs<=1; dat<=dis_data1;     current<=dat2;      end 
            dat2:   begin  e<=0;rs<=1; dat<=dis_data2;     current<=dat3;      end 
            dat3:   begin  e<=0;rs<=1; dat<=dis_data3;     current<=dat4;      end 
            dat4:   begin  e<=0;rs<=1; dat<=dis_data4;     current<=dat5;      end 
            dat5:   begin  e<=0;rs<=1; dat<=dis_data5;     current<=dat6;      end 
            dat6:   begin  e<=0;rs<=1; dat<=dis_data6;     current<=dat7;      end 
            dat7:   begin  e<=0;rs<=1; dat<=dis_data7;     current<=dat8;      end 
            dat8:   begin  e<=0;rs<=1; dat<=dis_data8;     current<=dat9;      end 
            dat9:   begin  e<=0;rs<=1; dat<=dis_data9;     current<=dat10;     end 
            dat10:  begin  e<=0;rs<=1; dat<=dis_data10;    current<=dat11;     end 
            dat11:  begin  e<=0;rs<=1; dat<=dis_data11;    current<=dat12;     end 
            dat12:  begin  e<=0;rs<=1; dat<=dis_data12;    current<=dat13;     end 
            dat13:  begin  e<=0;rs<=1; dat<=dis_data13;    current<=dat14;     end 
            dat14:  begin  e<=0;rs<=1; dat<=dis_data14;    current<=dat15;     end 
            dat15:  begin  e<=0;rs<=1; dat<=dis_data15;    current<=set5;      end 
            
            set5:   begin  e<=0;rs<=0; dat<=8'hC0; current<=dat16;         end   //0xc0?
            dat16:  begin  e<=0;rs<=1; dat<=dis_data16;   current<=dat17;         end 
            dat17:  begin  e<=0;rs<=1; dat<=dis_data17;   current<=dat18;         end 
            dat18:  begin  e<=0;rs<=1; dat<=dis_data18;   current<=dat19;         end 
            dat19:  begin  e<=0;rs<=1; dat<=dis_data19;   current<=dat20;         end 
            dat20:  begin  e<=0;rs<=1; dat<=dis_data20;   current<=dat21;         end 
            dat21:  begin  e<=0;rs<=1; dat<=dis_data21;   current<=dat22;         end 
            dat22:  begin  e<=0;rs<=1; dat<=dis_data22;   current<=dat23;         end 
            dat23:  begin  e<=0;rs<=1; dat<=dis_data23;   current<=dat24;         end 
            dat24:  begin  e<=0;rs<=1; dat<=dis_data24;   current<=dat25;         end 
            dat25:  begin  e<=0;rs<=1; dat<=dis_data25;   current<=dat26;         end 
            dat26:  begin  e<=0;rs<=1; dat<=dis_data26;   current<=dat27;         end 
            dat27:  begin  e<=0;rs<=1; dat<=dis_data27;   current<=dat28;         end 
            dat28:  begin  e<=0;rs<=1; dat<=dis_data28;   current<=dat29;         end 
            dat29:  begin  e<=0;rs<=1; dat<=dis_data29;   current<=dat30;         end 
            dat30:  begin  e<=0;rs<=1; dat<=dis_data30;   current<=dat31;         end 
            dat31:  begin  e<=0;rs<=1; dat<=dis_data31;   current<=fini0;         end
                 fini0:   begin  e<=0;rs<=0; dat<=8'h00; current<=set4;       end
            default:   current<=set0; 
        endcase 
    end
 end 

// assign en = clkr|e;
assign en = clkr;
assign rw = 0;

endmodule

counter有什么用?
counter是计数器,用来为clkr时钟产生做周期计数。
counter==0f 的判断,也就是每16个时钟clkr反转一次,clkr反转2次一个时钟周期完成。也就是 clkr 是时钟的32分频。
counter==0f ,0f 转成10进制就是 15