lcd1602如何自定義漢字(verilog)

来源:http://www.cnblogs.com/aslmer/archive/2016/08/29/5819868.html
-Advertisement-
Play Games

今天一鼓作氣,再研究了一下如何用LCD1602自定義漢字 1、用字模軟體獲取漢字所對應的數據(因為嫌麻煩所以直接用了網上一個帖子里有關“電”的數據,如下:04,1f,15,1f,15,15,1f,04,07)帖子鏈接:http://www.51hei.com/mcu/3696.html 2、主要知識 ...


今天一鼓作氣,再研究了一下如何用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_15MS = 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
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_15ms ;
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        cnt_15ms<=0;
    end
    else if(cnt_15ms == TIME_15MS -1)begin
        cnt_15ms<=cnt_15ms;
    end
    else
        cnt_15ms<=cnt_15ms + 1 ;
end
wire delay_done = (cnt_15ms==TIME_15MS-1)? 1'b1 : 1'b0 ;
//----------------------------------------------------------------------
//500ns
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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 為什麼現在有非常多的聰明人都在致力於互聯網? 最近在讀埃隆·馬斯克傳記,他說「我認為現在有非常多的聰明人都在致力於互聯網」。 仔細一想,好像真的是這樣的。 我問了自己一個問題:如果你不敲代碼了,你能做什麼? 答案令人極其恐怖。嚇得我趕緊又去寫了一句 system.out.print("Hello W ...
  • python phpbb3 2016年8月30日 04:50:48 codegay phpbb3是國外一個開源的PHP論壇,python phpbb3這個項目是用python3實現很多對phpbb3論壇操作的方法,比如登錄,發貼,刪貼之類的操作。 從時間上看作者是4年前寫的項目,不過從代碼上看貌似大 ...
  • 接上一節課,我們專門新建了一個godconfig類,設置了兩個屬性prj_name(項目名),prj_author(作者),然後我們獲取標準輸入(stdin)把結果保存在了類裡面。 好吧,這節課的名字比較奇葩-我得了”懶癌”,假如我們忘記寫godconfig類的屬性,我們的程式還會運行嗎?答案是依舊 ...
  • 此類主要用於加密與解密,採用128位ECB模式,PKCS5Padding填充補位。 可使用方法為加密返回二進位encryptBin(content, key)、加密返回十六進位encryptHex(content, key)、二進位內容解密decryptBin(content, key)、十六進位內 ...
  • C語言中字元串處理函數介紹 下麵介紹8種基本的常用的字元串處理函數,在數值數組中也常常用到(部分函數)。所有的C語言編譯系統中一般都提供這些函數。 1、puts函數——輸出字元串的函數 一般的形式為puts(字元串組) 作用:將一個字元串輸出到終端。如,char一個string,並賦予初值。調用pu ...
  • 為了避免同一個文件被include多次1#ifndef方式2#pragma once方式在能夠支持這兩種方式的編譯器上,二者並沒有太大的區別,但是兩者仍然還是有一些細微的區別。方式一: #ifndef lxx_somefile_h #define lxx_somefile_h ... ... // ... ...
  • 原諒我是初學者,這個方法寫的很爛,以後不會改進,謝謝 資料庫配置如下 ...
  • 在安裝Visual Studio Code插件的時候,由於谷歌的限制,在下載下列插件的時候會報錯: 下麵介紹如果繞過封鎖去獲取相應的插件: 前提是設置好 %GOPATH% 之後再執行以下操作: 可以參考下麵的網址設置Visual Studio Code http://www.cnblogs.com/ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...