gs001588 发表于 2022-1-20 20:55

【国产FPGA高云GW1N-4系列开发板测评】——11、点个LCD1602屏

本帖最后由 gs001588 于 2022-1-20 20:55 编辑

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;【国产FPGA高云GW1N-4系列开发板测评】&mdash;&mdash;11、点个LCD1602屏</span></span></p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;</span></span></p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;之前用在FPGA上写过12864带字库屏的显示应用,间隔时间比较长了,之前备份的资料暂时没有找到。手头正好有LCD1602的LCD屏,不妨先拿LCD1602来做个显示实验。LCD1602作为一款经典的LCD屏,在各种学习平台上的应用自然是少不了的,在FPGA上也不例外。</span></span></p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;本着拿来主义的想法,参考网友资料,做了适当修改。原本打算做成显存方式模块,对外接口为异步RAM方式,模块内部完成LCD初始化,有新显存数据后自动显示刷新操作。这样就需要写顶层文件,需要提供变化的数据源,把问题复杂化,因此可作为之后的改进实验。本贴先显示一下LCD1602。</span></span></p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;参考网址(<a href="https://blog.csdn.net/qq_33231534/article/details/108484995" target="_blank">基于FPGA的LCD1602显示屏驱动&nbsp;https://blog.csdn.net/qq_33231534/article/details/108484995</a>)</span></span></p>

<p>&nbsp;</p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;本实验使用到的FPGA管脚资源配置如下:<br />
</span></span></p>

<p>&nbsp;</p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; GWIN-4B与LCD1602屏之间对应关系接线表:</span></span></p>

<table align="center" border="1" cellpadding="1" cellspacing="1">
        <tbody>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">LCD1602</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">功能说明</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">GWIN-4B</span></span></td>
                </tr>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">1、VCC</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">电源地</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">JP7.2-5V</span></span></td>
                </tr>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">2、GND</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">电源正极</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">J19.1-GND</span></span></td>
                </tr>
                <tr>
                        <td rowspan="1">
                        <p><span style="font-size:16px;"><span style="font-family:宋体;">3、V0(接5.1K到GND)</span></span></p>
                        </td>
                        <td rowspan="1"><span style="font-size:16px;"><span style="font-family:宋体;">液晶显示偏压</span></span></td>
                        <td rowspan="1">&nbsp;</td>
                </tr>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">4、RS</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">命令/数据选择</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">J4.1-32</span></span></td>
                </tr>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">5、RW</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">读/写选择</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">J4.2-34</span></span></td>
                </tr>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">6、EN</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">使能信号</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">J4.3-38</span></span></td>
                </tr>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">7、DATA0</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">数据0</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">J4.4-39</span></span></td>
                </tr>
                <tr>
                        <td>
                        <p><span style="font-size:16px;"><span style="font-family:宋体;">8、DATA1</span></span></p>
                        </td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">数据1</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">J4.5-40</span></span></td>
                </tr>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">9、DATA2</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">数据2</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">J4.6-41</span></span></td>
                </tr>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">10、DATA3</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">数据3</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">J4.7-42</span></span></td>
                </tr>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">11、DATA4</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">数据4</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">J4.8-43</span></span></td>
                </tr>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">12、DATA5</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">数据5</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">J4.9-44</span></span></td>
                </tr>
                <tr>
                        <td>
                        <p><span style="font-size:16px;"><span style="font-family:宋体;">13、DATA6</span></span></p>
                        </td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">数据6</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">J4.10-45</span></span></td>
                </tr>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">14、DATA7</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">数据7</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">J4.11-46</span></span></td>
                </tr>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">15、A(5V)</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">背光正极</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">JP7.1-5V</span></span></td>
                </tr>
                <tr>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">16、K(GND)</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">背光负极</span></span></td>
                        <td><span style="font-size:16px;"><span style="font-family:宋体;">J19.16-GND</span></span></td>
                </tr>
        </tbody>
</table>

<p>&nbsp;</p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;LCD1602的1、3脚之间并个5.1K直插电阻,为3脚的液晶显示偏置电压V0提供参考。一般开发板上使用的话会在1、3脚之间接个10K的电位器来调节电压,为啥是5.1K?之前修过一块开发板,在板上3脚接到GND了,导致普通LCD1602不能显示。查询LCD1602数据手册,此管脚V0为液晶显示偏压,接地时对比度最高,对比度过高时会产生&ldquo;鬼影&rdquo;,显示发黑不易区分正常显示与底色;接正电源电压时对比度最弱,显示发白几乎看不见。接个5K左右的电阻即可正常显示,电阻不需要精确4到6K都可以。</span></span></p>

<p><span style="font-size:16px;"><span style="font-family:宋体;"></span></span></p>

<p>&nbsp;</p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;正好JP7有两针5V引出,其中一个给LCD逻辑供电,另一个给背光正极供电;GND比较多,随意选了两个,一个作为电源地,另一个作为背光负极。</span></span></p>

<p><span style="font-size:16px;"><span style="font-family:宋体;"></span></span></p>

<p>&nbsp;</p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;剩余11条数据线分别一一对应接到JP14的1到11脚。</span></span></p>

<p><span style="font-size:16px;"><span style="font-family:宋体;"></span></span></p>

<p>&nbsp;</p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;逻辑代码见下。具体功能及LCD1602相关寄存器功能等可以参考上面的&ldquo;参考网址&rdquo;中相关内容。</span></span></p>

<pre>
<code>module lcd(
        input                                clk                        ,
        input                                rst_n                ,
       
        output        reg                        lcd_rs                ,
        output        wire                lcd_rw                ,
        output        reg                        lcd_en                ,
        output        reg                lcd_data       
        );

        reg                cnt                                ;
        reg                state_c                        ;
        reg                state_n                        ;
        reg                char_cnt                ;
        reg                data_display        ;

        localparam
                IDLE                        = 4'd0        ,
                INIT                         = 4'd1        ,
                S0                                = 4'd2        ,
                S1                                = 4'd3        ,
                S2                                = 4'd4        ,
                S3                                = 4'd5        ,
                ROW1_ADDR                = 4'd6        ,
                WRITE                        = 4'd7        ,
                ROW2_ADDR                = 4'd8        ,
                stop                        = 4'd9        ;

    reg    disp_memory ;
    reg                disp_cnt;

        assign lcd_rw = 1'b0;

        always @(posedge clk or negedge rst_n) begin
                if (!rst_n) begin
                        cnt &lt;= 17'd0;
                end
                else begin
                        if (cnt==17'd100_000 - 1) begin
                                cnt &lt;= 17'd0;
                        end
                        else begin
                                cnt &lt;= cnt + 1'b1;
                        end
                end
        end

        always @(posedge clk or negedge rst_n) begin
                if (!rst_n) begin
                        lcd_en &lt;= 0;
                end
                else if (cnt==17'd50_000 - 1) begin
                        lcd_en &lt;= 1;
                end
                else if (cnt==17'd100_000 - 1) begin
                        lcd_en &lt;= 0;
                end
        end

        always @(posedge clk or negedge rst_n) begin
                if (!rst_n) begin
                        char_cnt &lt;= 0;
                end
                else if (state_c==WRITE &amp;&amp; cnt==17'd50_000 - 1) begin
                        if (char_cnt==5'd31) begin
                                char_cnt &lt;= 5'd0;
                        end
                        else begin
                                char_cnt &lt;= char_cnt + 1'b1;
                        end
                end
        end

    integer i;

    always @(posedge clk or negedge rst_n) begin
                if (!rst_n) begin
            for(i=0;i&lt;32;i=i+1)
            begin
                case(i)
                  5'd0: data_display   = "W";
                  5'd1: data_display   = "e";
                  5'd2: data_display   = "l";
                  5'd3: data_display   = "c";
                  5'd4: data_display   = "o";
                  5'd5: data_display   = "m";
                  5'd6: data_display   = "e";
                  5'd7: data_display   = " ";
                  5'd8: data_display   = "t";
                  5'd9: data_display   = "o";
                  5'd10: data_display= " ";
                  5'd11: data_display= "G";
                  5'd12: data_display= "O";
                  5'd13: data_display= "W";
                  5'd14: data_display= "I";
                  5'd15: data_display= "N";

                  5'd16: data_display= "M";
                  5'd17: data_display= "i";
                  5'd18: data_display= "n";
                  5'd19: data_display= "i";
                  5'd20: data_display= " ";
                  5'd21: data_display= "K";
                  5'd22: data_display= "i";
                  5'd23: data_display= "T";
                  5'd24: data_display= " ";
                  5'd25: data_display= "G";
                  5'd26: data_display= "W";
                  5'd27: data_display= "I";
                  5'd28: data_display= "N";
                  5'd29: data_display= "-";
                  5'd30: data_display= "4";
                  5'd31: data_display= "B";

                  default:data_display = "P";
                endcase

                disp_memory = data_display;
            end
                end
        end

        always @(posedge clk or negedge rst_n) begin
                if (!rst_n) begin
                        state_c &lt;= IDLE;
                end
                else if(cnt==17'd50_000 - 1) begin
                        state_c &lt;= state_n;
                end
        end

        reg                cnt_15ms;
        reg                flag        ;
        always@(posedge clk or negedge rst_n)begin
                if (!rst_n) begin
                        cnt_15ms &lt;= 0;
                end
                else if (state_c == IDLE) begin
                        cnt_15ms &lt;= cnt_15ms + 1'b1;
                end
        end

        always@(posedge clk or negedge rst_n)begin
                if (!rst_n) begin
                        flag &lt;= 0;
                end
                else if (state_c==IDLE &amp;&amp; cnt_15ms==20'd750000) begin
                        flag &lt;= 1;
                end
        end

        always @(*) begin
                case(state_c)
                        IDLE                :
                                begin
                                        if (flag) begin
                                                state_n = INIT;
                                        end
                                        else begin
                                                state_n = state_c;
                                        end
                                end
                        INIT         :
                                begin
                                        state_n = S0;
                                end
                        S0        :
                                begin
                                        state_n = S1;
                                end
                        S1        :
                                begin
                                        state_n = S2;
                                end
                        S2        :
                                begin
                                        state_n = S3;
                                end
                        S3        :
                                begin
                                        state_n = ROW1_ADDR;
                                end
                        ROW1_ADDR:
                                begin
                                        state_n = WRITE;
                                end
                        WRITE                :
                                begin
                                        if (char_cnt==5'd15) begin
                                                state_n = ROW2_ADDR;
                                        end
                                        else if (char_cnt==5'd31) begin
                                                state_n = stop;
                                        end
                                        else begin
                                                state_n = state_c;
                                        end
                                end
                        ROW2_ADDR:
                                begin
                                        state_n = WRITE;
                                end
                        stop                :
                                begin
                                        state_n = stop;
                                end
                        default:state_n = IDLE;
                endcase
        end

        always @(posedge clk or negedge rst_n) begin
                if (!rst_n) begin
                        lcd_data &lt;= 8'd0;
                end
                else begin
                        case(state_c)
                                IDLE                :begin lcd_data &lt;= 8'h38; lcd_rs &lt;= 0;end
                                INIT                 :begin lcd_data &lt;= 8'h38; lcd_rs &lt;= 0;end
                                S0                        :begin lcd_data &lt;= 8'h08; lcd_rs &lt;= 0;end
                                S1                        :begin lcd_data &lt;= 8'h01; lcd_rs &lt;= 0;end
                                S2                        :begin lcd_data &lt;= 8'h06; lcd_rs &lt;= 0;end
                                S3                        :begin lcd_data &lt;= 8'h0c; lcd_rs &lt;= 0;end
                                ROW1_ADDR        :begin lcd_data &lt;= 8'h80; lcd_rs &lt;= 0;end
                                //WRITE                :begin lcd_data &lt;= data_display; lcd_rs &lt;= 1;end
                WRITE                :begin lcd_data &lt;= disp_memory; lcd_rs &lt;= 1;end
                                ROW2_ADDR        :begin lcd_data &lt;= 8'hc0; lcd_rs &lt;= 0;end
                                stop                :begin lcd_data &lt;= 8'h38; lcd_rs &lt;= 0;end
                                default:;
                        endcase
                end
        end
endmodule
 </code></pre>

<p>&nbsp;</p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;本实验用到了复位功能,将双功能管脚选项中的RECONFIG_N作为普通IO选项打勾。</span></span></p>

<p><span style="font-size:16px;"><span style="font-family:宋体;"></span></span></p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp;</span></span></p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;逻辑代码编译通过,下载到开发板,LCD1602两行分别显示&ldquo;Welcome to GOWIN&rdquo;、&ldquo;Mini KiT GWIN-4B&rdquo;,效果见下图。</span></span></p>

<p><span style="font-size:16px;"><span style="font-family:宋体;"></span></span></p>

<p>&nbsp;</p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;本实验完成将LCD1602屏点亮显示字符。</span></span></p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp; &nbsp;疫情原因无法正常上般,家里条件有限,手头缺少扩展模块来实验,更多扩展功能之后有时间补上。</span></span></p>

<p><span style="font-size:16px;"><span style="font-family:宋体;">&nbsp;</span></span></p>

nmg 发表于 2022-1-21 10:08

<p>熟悉的lcd1602,我以为它已经被淘汰了</p>

<p>希望是疫情最后一波,明年可以解放啦</p>
页: [1]
查看完整版本: 【国产FPGA高云GW1N-4系列开发板测评】——11、点个LCD1602屏