zoukankan      html  css  js  c++  java
  • lcd1602如何自定义汉字(verilog)

    今天一鼓作气,再研究了一下如何用LCD1602自定义汉字

    1、用字模软件获取汉字所对应的数据(因为嫌麻烦所以直接用了网上一个帖子里有关“电”的数据,如下:04,1f,15,1f,15,15,1f,04,07)帖子链接:http://www.51hei.com/mcu/3696.html

    2、主要知识点

    (1)lcd1602的11个指令集与lcd1602的基本显示,前两篇文章已经详细说过,链接如下  

    http://www.cnblogs.com/aslmer/p/5801363.html

    http://www.cnblogs.com/aslmer/p/5819422.html

    (2)DDRAM 与 CGRAM 的区别,根据数据手册知道我们可以定义8个汉字,具体更多知识点请自己百度。

    (3)主要的两个指令 Set CGRAM Address 、 Write data to RAM 。

    3、在上篇文章的基础上修改代码如下:
    难点就在状态机的控制,重点修改部分都用红色标注
    module lcd_1602_driver(
                    clk    ,
                    rst_n  ,
                    lcd_en ,
                    lcd_rw ,
                    lcd_rs ,
                    lcd_data
    
                  );
    input        clk    ;
    input        rst_n  ;
    
    output       lcd_en ;
    output       lcd_rw ;
    output       lcd_rs ;
    output [7:0] lcd_data;
    wire         clk ;
    wire         rst_n  ;
    wire         lcd_en ;
    wire         lcd_rw;
    reg  [7:0]   lcd_data;
    reg          lcd_rs  ;
    reg [7:0]    c_state ;
    reg [7:0]    n_state ;
    wire  [127:0]  row_1;
    wire write_flag;
    //wire  [127:0]  row_2;
    assign row_1 ="i am liu xiao yi" ;
    //assign row_2 ="happy everyday !";
    //----------------------------------------------------------------------
    //initialize
    //first step is waitng more than 20 ms.
    parameter TIME_20MS = 1000_000 ; //20000000/20=1000_000
    //parameter TIME_15MS = 9'h100 ; //just for test
    parameter TIME_500HZ= 100_000  ; //
    //parameter TIME_500HZ= 4'hf;  //just for test
    //use gray code   这里本来用的是格雷码,但是由于增添了两个状态,就随机写了f1,f2这两个数字。
    parameter         IDLE=    8'h00  ;                             
    parameter SET_FUNCTION=    8'h01  ;
    parameter     DISP_OFF=    8'h03  ;
    parameter   DISP_CLEAR=    8'h02  ;
    parameter   ENTRY_MODE=    8'h06  ;
    parameter   DISP_ON   =    8'h07  ;
    parameter    ROW1_ADDR=    8'h05  ;
    //----------------------修改1,增添这两个状态
    parameter  CGRAM_ADDR   =   8'hf1;
    parameter  CGRAM_DATA   =   8'hf2;
    //-----------------------
    parameter       ROW1_0=    8'h04  ;
    parameter       ROW1_1=    8'h0C  ;
    parameter       ROW1_2=    8'h0D  ;
    parameter       ROW1_3=    8'h0F  ;
    parameter       ROW1_4=    8'h0E  ;
    parameter       ROW1_5=    8'h0A  ;
    parameter       ROW1_6=    8'h0B  ;
    parameter       ROW1_7=    8'h09  ;
    parameter       ROW1_8=  8'h08  ;
    parameter       ROW1_9=    8'h18  ;
    parameter       ROW1_A=    8'h19  ;
    parameter       ROW1_B=    8'h1B  ;
    parameter       ROW1_C=    8'h1A  ;
    parameter       ROW1_D=    8'h1E  ;
    parameter       ROW1_E=    8'h1F  ;
    parameter       ROW1_F=    8'h1D  ;
    
    parameter    ROW2_ADDR=    8'h1C  ;
    parameter       ROW2_0=    8'h14  ;
    parameter       ROW2_1=    8'h15  ;
    parameter       ROW2_2=    8'h17  ;
    parameter       ROW2_3=    8'h16  ;
    parameter       ROW2_4=    8'h12  ;
    parameter       ROW2_5=    8'h13  ;
    parameter       ROW2_6=    8'h11  ;
    parameter       ROW2_7=    8'h10  ;
    parameter       ROW2_8=    8'h30  ;
    parameter       ROW2_9=    8'h31  ;
    parameter       ROW2_A=    8'h33  ;
    parameter       ROW2_B=    8'h32  ;
    parameter       ROW2_C=    8'h36  ;
    parameter       ROW2_D=    8'h37  ;
    parameter       ROW2_E=    8'h35  ;
    parameter       ROW2_F=    8'h34  ;
    
    
    
    reg [19:0] cnt_20ms ;
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            cnt_20ms<=0;
        end
        else if(cnt_20ms == TIME_20MS -1)begin
            cnt_20ms<=cnt_20ms;
        end
        else
            cnt_20ms<=cnt_20ms + 1 ;
    end
    wire delay_done = (cnt_20ms==TIME_20MS-1)? 1'b1 : 1'b0 ;
    //----------------------------------------------------------------------
    //500ns  lcd1602工作在500HZ,因此此处要分频
    reg [19:0] cnt_500hz;
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            cnt_500hz <= 0;
        end
        else if(delay_done==1)begin
            if(cnt_500hz== TIME_500HZ - 1)
                cnt_500hz<=0;
            else
                cnt_500hz<=cnt_500hz + 1 ;
        end
        else
            cnt_500hz<=0;
    end
    
    assign lcd_en = (cnt_500hz>(TIME_500HZ-1)/2)? 1'b0 : 1'b1;  //下降沿
    assign write_flag = (cnt_500hz==TIME_500HZ - 1) ? 1'b1 : 1'b0 ;
    
    //set_function ,display off ,display clear ,entry mode set
    //----------------------------------------------------------------------
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            c_state <= IDLE    ;
        end
        else if(write_flag==1) begin
            c_state<= n_state  ;
        end
        else
            c_state<=c_state   ;
    end
    
    //-------------------------修改2 因为自定义一个汉字需要写8次地址并且给8次数据,所以用num和num1来控制。
    reg [2:0]num,num1;
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            num<=0;
        end
        else if(c_state== CGRAM_ADDR&&write_flag) begin
            if(num==7)
                num<=0;
            else
                num<=num+8'b1;
        end
        else
            num<=num;
    end
    
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            num1<=0;
        end
        else if(c_state== CGRAM_DATA&&write_flag) begin
            if(num1==7)
                num1<=0;
            else
                num1<=num1+8'b1;
        end
        else
            num1<=num1;
    end
    
    //------------------------------------------------------------
    
    always  @(*)begin
        case (c_state)
            IDLE: n_state = SET_FUNCTION ;
    SET_FUNCTION: n_state = DISP_OFF     ;
        DISP_OFF: n_state = DISP_CLEAR   ;
      DISP_CLEAR: n_state = ENTRY_MODE   ;
      ENTRY_MODE: n_state = DISP_ON      ;
      DISP_ON   : n_state = CGRAM_ADDR   ;
      //------------------------------------------------ 修改3 当8个数据都写进相应地址里的时候,状态机才跳到ROW1_ADDR状态
      CGRAM_ADDR: n_state = CGRAM_DATA   ;   // 8'hfe;
      CGRAM_DATA:   if(num1==7)
                      n_state = ROW1_ADDR;
                    else
                      n_state= CGRAM_ADDR;
      //------------------------------------------------ 
       ROW1_ADDR: n_state = ROW1_0       ;
          ROW1_0: n_state = ROW1_1       ;
          ROW1_1: n_state = ROW1_2       ;
          ROW1_2: n_state = ROW1_3       ;
          ROW1_3: n_state = ROW1_4       ;
          ROW1_4: n_state = ROW1_5       ;
          ROW1_5: n_state = ROW1_6       ;
          ROW1_6: n_state = ROW1_7       ;
          ROW1_7: n_state = ROW1_8       ;
          ROW1_8: n_state = ROW1_9       ;
          ROW1_9: n_state = ROW1_A       ;
          ROW1_A: n_state = ROW1_B       ;
          ROW1_B: n_state = ROW1_C       ;
          ROW1_C: n_state = ROW1_D       ;
          ROW1_D: n_state = ROW1_E       ;
          ROW1_E: n_state = ROW1_F       ;
          ROW1_F: n_state = ROW2_ADDR    ;
    
       ROW2_ADDR: n_state = ROW2_0       ;
          ROW2_0: n_state = ROW2_1       ;
          ROW2_1: n_state = ROW2_2       ;
          ROW2_2: n_state = ROW2_3       ;
          ROW2_3: n_state = ROW2_4       ;
          ROW2_4: n_state = ROW2_5       ;
          ROW2_5: n_state = ROW2_6       ;
          ROW2_6: n_state = ROW2_7       ;
          ROW2_7: n_state = ROW2_8       ;
          ROW2_8: n_state = ROW2_9       ;
          ROW2_9: n_state = ROW2_A       ;
          ROW2_A: n_state = ROW2_B       ;
          ROW2_B: n_state = ROW2_C       ;
          ROW2_C: n_state = ROW2_D       ;
          ROW2_D: n_state = ROW2_E       ;
          ROW2_E: n_state = ROW2_F       ;
          ROW2_F: n_state = ROW1_ADDR    ;
         default: n_state = n_state      ;
       endcase 
       end   
    
       assign lcd_rw = 0;
       always  @(posedge clk or negedge rst_n)begin
           if(rst_n==1'b0)begin
               lcd_rs <= 0 ;   //order or data  0: order 1:data
           end
           else if(write_flag == 1)begin
               if((n_state==SET_FUNCTION)||(n_state==DISP_OFF)||
                  (n_state==DISP_CLEAR)||(n_state==ENTRY_MODE)||
                  (n_state==DISP_ON ) ||(n_state==ROW1_ADDR)||
                  (n_state==ROW2_ADDR)||(n_state==CGRAM_ADDR))begin //修改4
               lcd_rs<=0 ;
               end 
               else  begin
               lcd_rs<= 1;
               end
           end
           else begin
               lcd_rs<=lcd_rs;
           end     
       end                   
    
       always  @(posedge clk or negedge rst_n)begin
           if(rst_n==1'b0)begin
               lcd_data<=0 ;
           end
           else  if(write_flag)begin
               case(n_state)
    
                     IDLE: lcd_data <= 8'hxx;
             SET_FUNCTION: lcd_data <= 8'h38; //2*16 5*8 8位数据
                 DISP_OFF: lcd_data <= 8'h08;
               DISP_CLEAR: lcd_data <= 8'h01;
               ENTRY_MODE: lcd_data <= 8'h06;
               DISP_ON   : lcd_data <= 8'h0c;  //显示功能开,没有光标,且不闪烁,
    // ------------------------------------修改5
               CGRAM_ADDR:   begin
                        case(num)
                            0: lcd_data <= 8'h40;
                            1: lcd_data <= 8'h41;
                            2: lcd_data <= 8'h42;
                            3: lcd_data <= 8'h43;
                            4: lcd_data <= 8'h44;
                            5: lcd_data <= 8'h45;
                            6: lcd_data <= 8'h46;
                            7: lcd_data <= 8'h47;
                                endcase
                         end
    
               CGRAM_DATA:  begin
                        case(num1)
                            0: lcd_data <= 8'h04;
                            1: lcd_data <= 8'h1f;
                            2: lcd_data <= 8'h15;
                            3: lcd_data <= 8'h1f;
                            4: lcd_data <= 8'h15;
                            5: lcd_data <= 8'h1f;
                            6: lcd_data <= 8'h04;
                            7: lcd_data <= 8'h07;
                        endcase
                        end
       //-------------------------------------修改6第一行显示 i am liu xiao yi  第二行全部显示汉字电
                ROW1_ADDR: lcd_data <= 8'h80; //00+80
                   ROW1_0: lcd_data <= row_1 [127:120];
                   ROW1_1: lcd_data <= row_1 [119:112];
                   ROW1_2: lcd_data <= row_1 [111:104];
                   ROW1_3: lcd_data <= row_1 [103: 96];
                   ROW1_4: lcd_data <= row_1 [ 95: 88];
                   ROW1_5: lcd_data <= row_1 [ 87: 80];
                   ROW1_6: lcd_data <= row_1 [ 79: 72];
                   ROW1_7: lcd_data <= row_1 [ 71: 64];
                   ROW1_8: lcd_data <= row_1 [ 63: 56];
                   ROW1_9: lcd_data <= row_1 [ 55: 48];
                   ROW1_A: lcd_data <= row_1 [ 47: 40];
                   ROW1_B: lcd_data <= row_1 [ 39: 32];
                   ROW1_C: lcd_data <= row_1 [ 31: 24];
                   ROW1_D: lcd_data <= row_1 [ 23: 16];
                   ROW1_E: lcd_data <= row_1 [ 15:  8];
                   ROW1_F: lcd_data <= row_1 [  7:  0];
    
                ROW2_ADDR: lcd_data <= 8'hc0;      //40+80
                   ROW2_0: lcd_data <=8'h00; //电
                   ROW2_1: lcd_data <=8'h00;
                   ROW2_2: lcd_data <=8'h00;
                   ROW2_3: lcd_data <=8'h00;
                   ROW2_4: lcd_data <=8'h00;
                   ROW2_5: lcd_data <=8'h00;
                   ROW2_6: lcd_data <=8'h00;
                   ROW2_7: lcd_data <=8'h00;
                   ROW2_8: lcd_data <=8'h00;
                   ROW2_9: lcd_data <=8'h00;
                   ROW2_A: lcd_data <=8'h00;
                   ROW2_B: lcd_data <=8'h00;
                   ROW2_C: lcd_data <=8'h00;
                   ROW2_D: lcd_data <=8'h00;
                   ROW2_E: lcd_data <=8'h00;
                   ROW2_F: lcd_data <=8'h00;
               endcase                     
           end
           else
                  lcd_data<=lcd_data ;
       end
    
    endmodule

    4、显示结果

     转载请注明出处:http://www.cnblogs.com/aslmer/p/5819868.html

  • 相关阅读:
    JavaScript打造很酷的图片放大效果实例代码
    【荐】CSS实现的鼠标点击小图无刷新放大图片代码
    JavaScript+CSS实现的文字幻灯切换代码
    【荐】很棒的图片友情链接带控制按钮的横向滚动代码
    jquery制作一个漂亮带渐隐效果的跑动区域
    JS打造的一款响应鼠标变化很炫的图片特效代码
    JS+CSS控制鼠标移上图片滑出文字提示代码
    Jquery+CSS实现的大气漂亮图片切换效果代码
    【荐】JS+CSS防FLASH效果带倒影的图片切换效果代码
    JavaScript限制对图片右键代码
  • 原文地址:https://www.cnblogs.com/aslmer/p/5819868.html
Copyright © 2011-2022 走看看