網絡消費網 >  5G > > 正文
        【從零開始走進FPGA】 LCD 1602 Hello World
        時間:2022-02-14 06:22:03

        前面說過,在C,C++等語言學習中,“Hello World”將會是第一個學習的代碼,但是在FPGA中由于電路驅動的復雜性,與單片機雷同,我們無法在電腦上實現“Hello World”的顯示,而必須依靠相關硬件。因此我們不得不在一定的基礎上,才能講解關于LCD1602字符液晶的驅動,以及Hello World的顯示。

        雷同于前面MCU按鍵消抖動移植代碼,此處也可以移植MCU LCD1602驅動代碼。本例程不是Bingo原創,是按照網友“小時不識月”的代碼,移植修改最后定型為Bingo版本(O(∩_∩)O哈哈~)。

        電路圖此處不解釋,太簡單了。

        一、驅動說明

        由于FPGA的高速并行操作,并非順序執行,在代碼上與MCU有所不同。此處先講解驅動原理:

        (1)分頻以得到500KHz固定的頻率,初始化LCD1602。如下圖所示,LCD_EN的頻率應該控制在2M以內(不同的LCD1602參數會有所不同)。

        (2)通過三段式狀態機,來初始化以及給數據。

        (3)通過循環讀取某一“數組”,循環給LCD1602數據,以接口形式方便改變。

        二、FPGALCD1602 FSM

        1. 代碼

        /*************************************************

        * Module Name : lcd1602_driver

        * Engineer : Crazy Bingo

        * Target Device : EP2C8Q208C8

        * Tool versions : Quartus II 11.0

        * Create Date : 2011-7-3

        * Revision : v1.0

        * Description :

        **************************************************/

        module lcd1602_driver

        (

        input clk,

        input rst_n,

        output lcd_en, // lcd enable

        output reg lcd_rs, // record,statement

        output lcd_rw,

        output reg [7:0] lcd_data

        );

        parameter [127:0] line_rom1 = "I am CrazyBingo!";

        parameter [127:0] line_rom2 = "Hello World*^_^*";

        //--------------------------------------

        reg [15:0] cnt;

        always @ (posedge clk or negedge rst_n)

        begin

        if(!rst_n)

        cnt <= 0;

        else

        cnt <= cnt + 1"b1;

        end

        assign lcd_en = cnt[15]; //lcd enable,keep same time

        assign lcd_rw = 1"b0; //write only

        wire cmd_flag = (cnt == 16"h7FFF) ? 1"b1 : 1"b0; //when lcd_en is steady,write a cmd

        //---------------------------------------

        // Gray code : 40 states

        parameter IDLE = 8"h00; // IDLE

        // lcd init

        parameter DISP_SET = 8"h01; // display mode

        parameter DISP_OFF = 8"h03; // off display

        parameter CLR_SCR = 8"h02; // clear the lcd

        parameter CURSOR_SET1 = 8"h06; // cursor set

        parameter CURSOR_SET2 = 8"h07; // on display, cursor set

        // display 1th line

        parameter ROW1_ADDR = 8"h05;

        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;

        // display 2th line

        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 [5:0] current_state, next_state;

        // FSM: always1

        always @ (posedge clk or negedge rst_n)

        begin

        if(!rst_n)

        current_state <= IDLE;

        else if(cmd_flag)

        current_state <= next_state;

        end

        //---------------------------------------

        // FSM: always2

        always@*

        begin

        case(current_state)

        // lcd init

        IDLE : next_state = DISP_SET;

        DISP_SET : next_state = DISP_OFF;

        DISP_OFF : next_state = CLR_SCR;

        CLR_SCR : next_state = CURSOR_SET1;

        CURSOR_SET1 : next_state = CURSOR_SET2;

        CURSOR_SET2 : next_state = ROW1_ADDR;

        // display 1th line

        ROW1_ADDR : next_state = ROW1_0;

        ROW1_0 : next_state = ROW1_1;

        ROW1_1 : next_state = ROW1_2;

        ROW1_2 : next_state = ROW1_3;

        ROW1_3 : next_state = ROW1_4;

        ROW1_4 : next_state = ROW1_5;

        ROW1_5 : next_state = ROW1_6;

        ROW1_6 : next_state = ROW1_7;

        ROW1_7 : next_state = ROW1_8;

        ROW1_8 : next_state = ROW1_9;

        ROW1_9 : next_state = ROW1_A;

        ROW1_A : next_state = ROW1_B;

        ROW1_B : next_state = ROW1_C;

        ROW1_C : next_state = ROW1_D;

        ROW1_D : next_state = ROW1_E;

        ROW1_E : next_state = ROW1_F;

        ROW1_F : next_state = ROW2_ADDR;

        // display 2th line

        ROW2_ADDR : next_state = ROW2_0;

        ROW2_0 : next_state = ROW2_1;

        ROW2_1 : next_state = ROW2_2;

        ROW2_2 : next_state = ROW2_3;

        ROW2_3 : next_state = ROW2_4;

        ROW2_4 : next_state = ROW2_5;

        ROW2_5 : next_state = ROW2_6;

        ROW2_6 : next_state = ROW2_7;

        ROW2_7 : next_state = ROW2_8;

        ROW2_8 : next_state = ROW2_9;

        ROW2_9 : next_state = ROW2_A;

        ROW2_A : next_state = ROW2_B;

        ROW2_B : next_state = ROW2_C;

        ROW2_C : next_state = ROW2_D;

        ROW2_D : next_state = ROW2_E;

        ROW2_E : next_state = ROW2_F;

        ROW2_F : next_state = ROW1_ADDR;

        default : next_state = IDLE ;

        endcase

        end

        //---------------------------------------

        // FSM: always3

        always @ (posedge clk or negedge rst_n)

        begin

        if(!rst_n)

        begin

        lcd_rs <= 0;

        lcd_data <= 8"hXX;

        end

        else if(cmd_flag)

        begin

        // write statement

        case(next_state)

        IDLE : lcd_rs <= 0; //statement

        //lcd init

        DISP_SET : lcd_rs <= 0; //statement

        DISP_OFF : lcd_rs <= 0; //statement

        CLR_SCR : lcd_rs <= 0; //statement

        CURSOR_SET1 : lcd_rs <= 0; //statement

        CURSOR_SET2 : lcd_rs <= 0; //statement

        // display 1th line

        ROW1_ADDR : lcd_rs <= 0; //statement

        ROW1_0 : lcd_rs <= 1; //record

        ROW1_1 : lcd_rs <= 1; //record

        ROW1_2 : lcd_rs <= 1; //record

        ROW1_3 : lcd_rs <= 1; //record

        ROW1_4 : lcd_rs <= 1; //record

        ROW1_5 : lcd_rs <= 1; //record

        ROW1_6 : lcd_rs <= 1; //record

        ROW1_7 : lcd_rs <= 1; //record

        ROW1_8 : lcd_rs <= 1; //record

        ROW1_9 : lcd_rs <= 1; //record

        ROW1_A : lcd_rs <= 1; //record

        ROW1_B : lcd_rs <= 1; //record

        ROW1_C : lcd_rs <= 1; //record

        ROW1_D : lcd_rs <= 1; //record

        ROW1_E : lcd_rs <= 1; //record

        ROW1_F : lcd_rs <= 1; //record

        // display 2th line

        ROW2_ADDR : lcd_rs <= 0; //statement

        ROW2_0 : lcd_rs <= 1; //record

        ROW2_1 : lcd_rs <= 1; //record

        ROW2_2 : lcd_rs <= 1; //record

        ROW2_3 : lcd_rs <= 1; //record

        ROW2_4 : lcd_rs <= 1; //record

        ROW2_5 : lcd_rs <= 1; //record

        ROW2_6 : lcd_rs <= 1; //record

        ROW2_7 : lcd_rs <= 1; //record

        ROW2_8 : lcd_rs <= 1; //record

        ROW2_9 : lcd_rs <= 1; //record

        ROW2_A : lcd_rs <= 1; //record

        ROW2_B : lcd_rs <= 1; //record

        ROW2_C : lcd_rs <= 1; //record

        ROW2_D : lcd_rs <= 1; //record

        ROW2_E : lcd_rs <= 1; //record

        ROW2_F : lcd_rs <= 1; //record

        endcase

        // write lcd_data

        case(next_state)

        IDLE : lcd_data <= 8"hxx;

        //lcd init

        DISP_SET : lcd_data <= 8"h38; //set 16X2,5X7 ,8 bits record

        DISP_OFF : lcd_data <= 8"h08; //off display

        CLR_SCR : lcd_data <= 8"h01; //clear lcd

        CURSOR_SET1 : lcd_data <= 8"h06; //cursor set

        CURSOR_SET2 : lcd_data <= 8"h0C; //on display

        // display 1th line

        ROW1_ADDR : lcd_data <= 8"h80;

        ROW1_0 : lcd_data <= line_rom1[127:120];

        ROW1_1 : lcd_data <= line_rom1[119:112];

        ROW1_2 : lcd_data <= line_rom1[111:104];

        ROW1_3 : lcd_data <= line_rom1[103: 96];

        ROW1_4 : lcd_data <= line_rom1[ 95: 88];

        ROW1_5 : lcd_data <= line_rom1[ 87: 80];

        ROW1_6 : lcd_data <= line_rom1[ 79: 72];

        ROW1_7 : lcd_data <= line_rom1[ 71: 64];

        ROW1_8 : lcd_data <= line_rom1[ 63: 56];

        ROW1_9 : lcd_data <= line_rom1[ 55: 48];

        ROW1_A : lcd_data <= line_rom1[ 47: 40];

        ROW1_B : lcd_data <= line_rom1[ 39: 32];

        ROW1_C : lcd_data <= line_rom1[ 31: 24];

        ROW1_D : lcd_data <= line_rom1[ 23: 16];

        ROW1_E : lcd_data <= line_rom1[ 15: 8];

        ROW1_F : lcd_data <= line_rom1[ 7: 0];

        // display 2th line

        ROW2_ADDR : lcd_data <= 8"hC0;

        ROW2_0 : lcd_data <= line_rom2[127:120];

        ROW2_1 : lcd_data <= line_rom2[119:112];

        ROW2_2 : lcd_data <= line_rom2[111:104];

        ROW2_3 : lcd_data <= line_rom2[103: 96];

        ROW2_4 : lcd_data <= line_rom2[ 95: 88];

        ROW2_5 : lcd_data <= line_rom2[ 87: 80];

        ROW2_6 : lcd_data <= line_rom2[ 79: 72];

        ROW2_7 : lcd_data <= line_rom2[ 71: 64];

        ROW2_8 : lcd_data <= line_rom2[ 63: 56];

        ROW2_9 : lcd_data <= line_rom2[ 55: 48];

        ROW2_A : lcd_data <= line_rom2[ 47: 40];

        ROW2_B : lcd_data <= line_rom2[ 39: 32];

        ROW2_C : lcd_data <= line_rom2[ 31: 24];

        ROW2_D : lcd_data <= line_rom2[ 23: 16];

        ROW2_E : lcd_data <= line_rom2[ 15: 8];

        ROW2_F : lcd_data <= line_rom2[ 7: 0];

        endcase

        end

        end

        endmodule

        2. 狀態機

        (1)以下是State machine如下所示:

        (2)模塊可分為一下幾個狀態

        3. “Hello World”實物顯示

        parameter [127:0] line_rom1 = "I am CrazyBingo!";

        parameter [127:0] line_rom2 = "Hello World*^_^*";

        關鍵詞:

        版權聲明:
            凡注明來網絡消費網的作品,版權均屬網絡消費網所有,未經授權不得轉載、摘編或利用其它方式使用上述作品。已經本網授權使用作品的,應在授權范圍內使用,并注明"來源:網絡消費網"。違反上述聲明者,本網將追究其相關法律責任。
            除來源署名為網絡消費網稿件外,其他所轉載內容之原創性、真實性、完整性、及時性本站不作任何保證或承諾,請讀者僅作參考并自行核實。
        熱文

        網站首頁 |網站簡介 | 關于我們 | 廣告業務 | 投稿信箱
         

        Copyright © 2000-2020 www.fnsyft.com All Rights Reserved.
         

        中國網絡消費網 版權所有 未經書面授權 不得復制或建立鏡像
         

        聯系郵箱:920 891 263@qq.com

        備案號:京ICP備2022016840號-15

        營業執照公示信息

        亚洲AV无码成人精品区狼人影院| 中文字幕亚洲综合久久| 国产A在亚洲线播放| 亚洲人成网站色在线入口| 精品无码专区亚洲| 亚洲精品无码av中文字幕| 亚洲AV无码精品蜜桃| 亚洲人成人77777在线播放| 亚洲欧洲日产v特级毛片| 亚洲码在线中文在线观看| 亚洲第一页中文字幕| 亚洲欧洲日本精品| 91亚洲精品自在在线观看| 亚洲理论精品午夜电影| 亚洲欧洲精品一区二区三区| 亚洲短视频在线观看| 亚洲人成777在线播放| 久久综合久久综合亚洲| 亚洲人成网亚洲欧洲无码| 亚洲精品无码日韩国产不卡av| 亚洲码和欧洲码一码二码三码| 亚洲av永久中文无码精品| AV激情亚洲男人的天堂国语| 国产亚洲成在线播放va| 亚洲午夜无码片在线观看影院猛| 狠狠亚洲狠狠欧洲2019| 久久被窝电影亚洲爽爽爽| 亚洲av无码片在线播放| 91亚洲导航深夜福利| 亚洲国产精品综合一区在线| 亚洲第一成人在线| 亚洲αⅴ无码乱码在线观看性色 | 亚洲精品无码少妇30P| 亚洲avav天堂av在线网毛片| www国产亚洲精品久久久| 相泽亚洲一区中文字幕| 亚洲va无码手机在线电影| 亚洲综合一区二区国产精品| 亚洲人成毛片线播放| 亚洲精品无码高潮喷水A片软| 国产成人亚洲精品电影|