基於basys2驅動LCDQC12864B的verilog設計圖片顯示


  話不多說先上圖

 

前言

       在做這個實驗的時候在網上找了許多資料,都是關於使用單片機驅動LCD顯示,確實用單片機驅動是要簡單不少,記得在FPGA學習交流群里問問題的時候,被前輩指教,說給我最好的指教便是別在玩這個了,多看看關於FPGA方面的書籍,比做這個單片機做的東西價值強多了。現在想來確實,自從學習FPGA以來,看過的書沒有多少,只是想做個什么了,就在網上找找例程,照抄下來,把算法推理一遍,下個板子實現了,便以為自己會了懂了,要是自己在寫一個便問題百出。那么菜鳥始終是菜鳥。自己根本沒有掌握FPGA的設計思想和優勢,用着FPGA做着單片機的東西,這種東西練練手就足夠了,所以,做完這個實驗LCD就到此為止了,我也要好好想想該如何進行下面的學習了。在這個上面我還是花費了不少時間,所以寫一篇博文總結記錄想,回頭看的時候,以警醒自己。

摘要                                                                 

         做完這個實驗我最大的感觸是一定要會讀數據手冊。拿到元件(LCD12864),上面有16個的引腳,先要搞清楚每個引腳的功能,這時候就一定要會讀數據手冊。我個qc12864b的中文手冊琢磨了很久才看懂了一些簡單的操作指令,包括在手冊上要提取出來,元件的驅動時序,掃描時鍾,引腳定義,操作指令,功能描述等。

LCD顯示原理

掃描時鍾

      

  從手冊上可以讀出,qc12864b(這是我所使用LCD12864的型號)的掃描時鍾介於470—590khz之間,最適為530khz,為了方便分頻,所以取500khz。

 

引腳說明

  VSS        電源地,0v ­——接開發板GND就行

  VDD      電源正極(5v,3.3v)

  VO        液晶顯示偏壓,調整對比度

  RS         RS=1時,當mpu進行讀模塊操作,指向地址寄存器

          當mpu進行寫模塊操作,指向指令寄存器

               RS=0時,無論進行讀/寫操作,都指向數據寄存器

  R/W             高電平讀操作,低電平寫操作

  E           使能信號,高電平讀取信息,下降沿執行命令

  DB0      數據總線第0位

  DB1      數據總線第1位

  DB2      數據總線第2位

  DB3      數據總線第3位

  DB4      數據總線第4位

  DB5      數據總線第5位

  DB6      數據總線第6位

  DB7      數據總線第7位

  PSB      串並控制端口,H為並行,L為串行,直接接5v

  RST       液晶復位端口,低電平有效

  A           背光正極輸入,調整電壓大小可以調整亮度

  K           背光負極輸入,一般直接接地

指令說明

       具體指令說明,這里就不一一列出,可查閱qc12864b中文數據手冊,我在閱讀這一部分的時候耗費了很長時間,這些指令是驅動LCD顯示文字與圖片的核心,所以必須要掌握。

並口顯示時序

 

Verilog實現方案

  從時序圖可以看出在使能信號的一個周期內可以完成寫入數據操作,掃描時鍾與使能信號周期相同即可。

狀態轉移圖

  狀態機初始化位置          IDLE                            lcd_data = 8’hzz

  功能設計                          SETFUNCTION            lcd_data = 8’h36//擴充指令繪圖顯示

  顯示設置                          SWITCHMODE           lcd_data = 8’h0c//顯示狀態

  清屏                                  CLEAR                       lcd_data = 8’h01//清零指令

  設置Y坐標                      SETDDRAM_Y

  設置X坐標                      SETDDRAM_X

  寫入數據                          WRITERAM

  結束                                  STOP

 

繪圖指令下的坐標圖

代碼如下

  1 module lcd_qc12864b(
  2             input mclk,
  3             input rst_n,
  4             output reg lcd_rs,//H讀寫數據,L指令
  5             output lcd_rw, //高電平讀操作,低電平寫操作
  6             output lcd_e,//使能信號高電平有效
  7             output reg [7:0]lcd_data,//八位數據總線  
  8         output psb,//串並控制端口,H為並行,L為串行,直接接5v  
  9         output lcd_rst//液晶的復位端口,低電平有效
 10     );
 11         
 12     reg lcd_clk;//需要500khz頻率的時鍾
 13     reg [7:0] state;//狀態機寄存器
 14     reg [23:0] cnt;//分頻驅動12864計數器
 15     reg flag = 1'b1;//顯示完成標志 
 16     reg [9:0] char_cnt;// 
 17     wire [7:0] data_disp;//一個字節是八位,一個英文字符是一個字節,中文是倆個字節
 18     reg [5:0] cnt1;//行計數
 19     
 20     parameter T500KHZ=24'd49999;  
 21     
 22         //分頻500khz時鍾
 23         always @(posedge mclk or negedge rst_n)
 24         begin
 25             if(!rst_n)begin
 26                 lcd_clk <= 1'b0;
 27                 cnt <= 24'd0;
 28             end
 29             else if(cnt == T500KHZ)begin
 30                 cnt <= 24'd0;
 31                 lcd_clk <= ~lcd_clk;
 32             end
 33             else
 34                 cnt <= cnt + 1'd1;
 35         end        
 36         
 37         //狀態機8個狀態設置 
 38     parameter IDLE = 8'b00_000_000,//初始狀態  
 39                         SETFUNCTION = 8'b00_000_001,//功能設置  
 40                           SWITCHMODE = 8'b00_000_010,//設置顯示開和光標閃爍關閉  
 41                           CLEAR = 8'b00_000_100,//清屏操作  
 42                           SETDDRAM_Y = 8'b00_010_000,//設置y軸坐標
 43                             SETDDRAM_X = 8'b00_100_000,//設置x軸坐標
 44                           WRITERAM = 8'b01_000_000,//寫設置寫入寄存器  
 45                           STOP = 8'b10_000_000;//LCD操作停止,釋放其控制
 46       
 47       //三段式書寫狀態機
 48       always @(posedge lcd_clk or negedge rst_n)
 49       begin
 50           if(!rst_n)
 51               lcd_rs <= 1'b0;
 52           else begin
 53               if(state == WRITERAM)
 54                   lcd_rs <= 1'b1;//寫數據模式
 55               else
 56                   lcd_rs <= 1'b0;//寫命令模式
 57           end
 58       end
 59       
 60       //lcd_rst始終為高電平,psb始終為低電平即可
 61     assign lcd_rst = 1'b1;  
 62     assign psb = 1'b1;  
 63     assign lcd_rw = 1'b0;//只是寫操作,不需要讀操作  
 64     assign lcd_e = (flag==1)?lcd_clk:1'b0;//使能信號與液晶時鍾同步
 65       
 66       always @(posedge lcd_clk or negedge rst_n)
 67       begin
 68           if(!rst_n)begin
 69               cnt1<= 1'b0;
 70               state <= IDLE;     
 71               lcd_data <= 8'hzz;
 72               char_cnt <= 6'd0;
 73           end
 74           else begin
 75               case(state)
 76                   IDLE:begin
 77                       state <=  SETFUNCTION;//功能設置,8-bit+基本指令集0x30
 78                       lcd_data <= 8'h36;
 79                   end
 80                   
 81                   SETFUNCTION:begin
 82                       state <= SWITCHMODE;//設置顯示開和光標閃爍關閉
 83                       lcd_data <= 8'h36;
 84                   end                  
 85         
 86                   SWITCHMODE:begin
 87                       state <= CLEAR;
 88                       lcd_data <= 8'h3e;//顯示設置,全顯示開,光標和閃爍關
 89                   end                  
 90                   CLEAR:begin//清屏操作
 91                       state <= SETDDRAM_Y;//點設置  
 92             lcd_data <= 8'h01;//清屏
 93           end           
 94             SETDDRAM_Y:begin
 95              if(cnt1< 32)
 96                  lcd_data <= 8'h80 + cnt1;//80H~9fH
 97              else
 98                  lcd_data <= 8'h80 + (cnt1- 32); //80H~9fH
 99                  
100              state <= SETDDRAM_X;
101           end               
102                     SETDDRAM_X:begin
103                       if(cnt1< 32)
104                           lcd_data <=  8'h80;            //80H
105                       else
106                           lcd_data <=  8'h88;            //88H
107                       state <= WRITERAM;
108                     end           
109                     WRITERAM:begin 
110                         lcd_data <= data_disp;
111                  char_cnt <= char_cnt + 1'b1;
112                  if(char_cnt[3:0] == 4'hf)begin      //計算行
113                      cnt1<= cnt1+ 1'b1;
114                 if(cnt1== 63)                         
115                     state <= STOP;
116                      else
117                   state <= SETDDRAM_Y;
118                        end 
119                        else
120                  state <= WRITERAM;
121             end                        
122           STOP:begin
123               flag <= 1'b0;
124               state <= STOP;//LCD操作停止,釋放其控制
125             end
126           default: state <= IDLE;//回到初始狀態
127         endcase  
128       end           
129      end  
130          
131          // ROM
132         rom U1_rom (
133     .clka(mclk), 
134     .addra(char_cnt), 
135     .douta(data_disp)
136     );
137 
138 endmodule
lcd_qc12864b

配置ROM

  有分布式ROM/ROM和塊ROM/RAM,這里配置的是塊ROM/RAM。這兩種方式具體我也不是了解很深,以后再深入學習。

      該實驗最讓我頭疼的是調用ROM,第一次接觸IP核有許多地方都完全不懂。用LCD(帶中文字庫)顯示文字的時候,可以直接輸入文字的十六進制數值,設置顯示地址坐標即可,12864顯示原理點陣控制點的亮滅來實現,但是如果要顯示圖片的話一個個輸入難免太過麻煩,這個時候調用ROM就方便許多。找一張或做一張像素為128x64的單色圖片,使用取模軟件,按c51的方式取模。取模出來的數據為十六進制,行8個,64個。

 

       配置塊RAM/ROM時,要加載的是.coe文件,所以需要將取模的十六進制數據保存到.coe文件中。最開始我一直在找如何能直接將圖片取模出來的數據轉化成.coe文件,試了很多方法都失敗了,最后發現完全可以自己按文件格式編輯一個即可,最終文件保存格式如下。

 

  將圖片取模出來的每個數據前的ox去掉,這只是C語言中16進制的表示形式,文件第一行的MEMORY_INITIALIZATION_RADIX=16;表示數據全都為16進制數,這里的16可以換成8、2、10都行。

       打開ISE建立工程后,新建文件,選擇IP(CORE Generator & Architecture Wizard),填寫文件名,next

 

  找到Memories & Storage Elements單擊,選擇RAMs & ROMs單擊,選擇Block Memory Generator 7.3,next,finish。

 

  上面直接next,下面這里選Single Port ROM,next

 

  這里要填寫數據位寬和深度,位寬是你所需要輸出的數據位寬,LCD有8個數據位,故這里定義位寬為8,深度即有多少個這樣的數據,從取模出來的數據看,易得共有1024個數據位。我使用的basys2開發板使用的是Xilinx Spantan3E—100TQ144 FPGA包含73728位的塊RAM/ROM。因此,使用的塊RAM的最大容量為9216字節或4608個16位字。從這里來看,是完全夠用的。

  Next,加載.coe數據文件,勾選Load Init File 加載.coe文件,我這里是在桌面上保存着,直接找到選擇就好。

 

  然后一直點擊next直至最后一個界面,最后點擊Generate,生成rom.xco。生成的IP核在工程目錄下的ipcore_dir文件中。

 

  將rom.v文件打開端口定義如下,直接在頂層文件對其實例化,如代碼所示

         

  最后可直接仿真,新建tb文件查看仿真傳輸數據是否正確。由波形圖可得在功能設定指令傳輸完畢后,進入讀數據狀態,所讀入的數據與文件中數據相符,一行數據傳輸完畢進入下一行,繼續讀入數據,仿真圖結果正確。下板子也正確。

 

  最開始學習FPGA,最容易出現的就是兩個問題,一個是把verilog當C語言來寫,另一個就是把FPGA當單片機來用。前者我已經有了改善,后者我還需要繼續努力。

 

轉載請注明出處:NingHeChuan(寧河川)

個人微信訂閱號:NingHeChuan

如果你想及時收到個人撰寫的博文推送,可以掃描左邊二維碼(或者長按識別二維碼)關注個人微信訂閱號

知乎ID:NingHeChuan

微博ID:NingHeChuan

原文地址:http://www.cnblogs.com/ninghechuan/p/6340691.html 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM