找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 6662|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

FPGA學(xué)習(xí)-BCD計(jì)數(shù)器設(shè)計(jì)與驗(yàn)證

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:108531 發(fā)表于 2016-3-12 22:40 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
Love 夢(mèng)想

BCD碼(Binary-Coded Decimal)亦稱二進(jìn)碼十進(jìn)數(shù)或二-十進(jìn)制代碼。用4位二進(jìn)制數(shù)來(lái)表示1位十進(jìn)制數(shù)中的0~910個(gè)數(shù)碼。是一種二進(jìn)制的數(shù)字編碼形式,用二進(jìn)制編碼的十進(jìn)制代碼。BCD碼這種編碼形式利用了四個(gè)位元來(lái)儲(chǔ)存一個(gè)十進(jìn)制的數(shù)碼,使二進(jìn)制和十進(jìn)制之間的轉(zhuǎn)換得以快捷進(jìn)行。(百度百科)

 

例子:158 以BCD編碼方式編碼就會(huì)變成

0

0

0

1

0

1

0

1

1

0

0

0

1

5

8

在C語(yǔ)言中如果不通過(guò)位運(yùn)算,一般都會(huì)采用一下方式進(jìn)行拆分,涉及到除法運(yùn)算:

A = 158/100 = 1   B = (158 % 100)/10 = 5  C = 158 %10 = 8

在FPGA中可以通過(guò)級(jí)聯(lián)3個(gè)4位計(jì)數(shù)器的方式實(shí)現(xiàn)該BCD編碼器。

 

一、實(shí)現(xiàn)單個(gè)4位計(jì)數(shù)器

1、源程序:

/* 實(shí)驗(yàn)名稱:計(jì)數(shù)器

 * 程序功能:In_cin 來(lái)一個(gè)高電平則計(jì)數(shù)一次

 * 約定俗成:所有需要外部輸入的信號(hào)加入前綴"In_" ,所有需往外部輸出的信號(hào)加入前綴"Out_"   

 */

module my_Counter(In_clk, In_cin, In_rst_n, Out_cout, Out_q);

 

    input In_clk;        // 時(shí)鐘輸入

    input In_cin;        // 觸發(fā)計(jì)數(shù)

    input In_rst_n;    // 復(fù)位信號(hào) 低復(fù)位

    output Out_cout;    // 溢出或與預(yù)定數(shù)值相等時(shí)輸出一個(gè)時(shí)鐘的高電平

    output [3:0]Out_q; // 存儲(chǔ)計(jì)數(shù)的數(shù)值

   

    reg[3:0] cnt;        // 存儲(chǔ)計(jì)數(shù)值

 

    // 捕獲 In_clk 上升沿,捕獲 In_rst_n 下降沿

    // 計(jì)數(shù)程序塊

    always@(posedge In_clk or negedge In_rst_n)

        if(1'b0 == In_rst_n)                // 復(fù)位信號(hào)處理 計(jì)數(shù)歸零

            cnt <= 4'd0;                   

        else if(1'b1 == In_cin)            // In_cin 為高時(shí)計(jì)數(shù)

            begin

                if(4'd9 == cnt)            // cnt 等于 9 則歸零

                    cnt <=4'd0;

                else

                    cnt <= cnt + 1'b1;    // cnt 小于 9 則累加

            end   

        else

            ;

   

    // 捕獲 In_clk 上升沿,捕獲 In_rst_n 下降沿

    // 溢出或匹配輸出程序塊

    always@(posedge In_clk or negedge In_rst_n)

        if(1'b0 == In_rst_n)                // 復(fù)位信號(hào)處理 計(jì)數(shù)歸零

            Out_cout <= 1'b0;

        else if(1'b1 == In_cin && 4'd9 == cnt) // 注意1'b1 == In_cin 不可省略

            Out_cout <= 1'b1;    // In_cin 為高并且同時(shí)上個(gè)計(jì)數(shù)器計(jì)數(shù)到9則輸出1

        else

            Out_cout <= 1'b0; // 反之輸出0   

    assign Out_q = cnt;

   

endmodule 

 

問(wèn)題點(diǎn):在上述代碼中的我做了一次實(shí)驗(yàn),將1'b1 == In_cin 省略了導(dǎo)致不行出現(xiàn)如下現(xiàn)象:


正常的波形
:(其實(shí)cout波形也是不對(duì)的,數(shù)到9就已經(jīng)是第10個(gè)數(shù)了,就應(yīng)該給高電平,可對(duì)比IP核

差異在這里:



假如
1'b1 == In_cin省略了,那么意味著只要計(jì)數(shù)一到9,無(wú)論In_cin當(dāng)前狀態(tài)是高還是低電平,cout就會(huì)輸出高電平,這就導(dǎo)致cout提前被拉高(波形對(duì)比),同時(shí)由會(huì)延后到計(jì)數(shù)器復(fù)位歸零之后才會(huì)拉低。

 

2、仿真測(cè)試代碼

/* 實(shí)驗(yàn)名稱:BCD 計(jì)數(shù)器驗(yàn)證 */

`timescale 1ns/1ns

`define clock_period 20

module mytest_tb;

    reg clk;

    reg cin;

    reg rst_n;

       

    wire cout;   

    wire [3:0]q;

   

    my_Counter BCD_Counter(

            .In_clk(clk),

            .In_cin(cin),

            .In_rst_n(rst_n),

            .Out_cout(cout),

            .Out_q(q)   

        );

       

    initial clk = 1'b1;

    always #(`clock_period / 2) clk = ~clk;

   

    initial begin

        rst_n = 1'b0;

        cin = 1'b0;

        #(`clock_period * 20);

        rst_n = 1'b1;

        #(`clock_period * 20);

        repeat(30)begin

            cin = 1'b1;

            #`clock_period;

            cin = 1'b0;

            #(`clock_period * 5);   

        end

        #(`clock_period * 20);

        $stop;

   

    end

endmodule

 

 

 

二、計(jì)數(shù)器級(jí)聯(lián)

1、源程序

/* 實(shí)驗(yàn)名稱:級(jí)聯(lián)計(jì)數(shù)器

 * 程序功能:

 * 約定俗成:所有需要外部輸入的信號(hào)加入前綴"In_",所有需往外部輸出的信號(hào)加入前綴"Out_"

 */

module mytest(In_clk, In_cin, In_rst_n, Out_cout, Out_q);

 

    input In_clk;

    input In_cin;

    input In_rst_n;

    output Out_cout;

    output[11:0] Out_q;

   

    wire Out_line0;    // 計(jì)數(shù)器0的Out_cout端與計(jì)數(shù)器1的Out_cout端鏈接

    wire Out_line1;    // 計(jì)數(shù)器1的Out_cout端與計(jì)數(shù)器2的Out_cout端鏈接

    wire[3:0] q0, q1, q2;   

    // 將三組4位信號(hào)合并成一組12位的信號(hào)

    assign Out_q = {q2, q1, q0};

   

    my_Counter Conuter0(

            .In_clk(In_clk),

            .In_cin(In_cin),         // 重點(diǎn)

            .In_rst_n(In_rst_n),

            .Out_cout(Out_line0), // 重點(diǎn)

            //.Out_q(Out_q[3:0])    // 方式1

            .Out_q(q0)                // 方式2

            );

           

    my_Counter Conuter1(

            .In_clk(In_clk),

            .In_cin(Out_line0),     // 重點(diǎn) 這里來(lái)一次高電平意味這計(jì)數(shù)器0計(jì)滿

            .In_rst_n(In_rst_n),

            .Out_cout(Out_line1), // 重點(diǎn)

            //.Out_q(Out_q[7:4]) // 方式1

            .Out_q(q1)                // 方式2

            );

           

    my_Counter Conuter2(

            .In_clk(In_clk),

            .In_cin(Out_line1),     // 重點(diǎn) 這里來(lái)一次高電平意味這計(jì)數(shù)器1計(jì)滿

            .In_rst_n(In_rst_n),

            .Out_cout(Out_cout), // 重點(diǎn)

            //.Out_q(Out_q[11:8]) // 方式1

            .Out_q(q2)                // 方式2

            );

 

endmodule

 

/* 實(shí)驗(yàn)名稱:計(jì)數(shù)器

 * 程序功能:

 * 約定俗成:所有需要外部輸入的信號(hào)加入前綴"In_"

 *               所有需往外部輸出的信號(hào)加入前綴"Out_"

 */

module my_Counter(In_clk, In_cin, In_rst_n, Out_cout, Out_q);

 

    input In_clk;

    input In_cin;

    input In_rst_n;

    output reg Out_cout;

    output [3:0]Out_q;

   

    reg[3:0] cnt;                            // 存儲(chǔ)計(jì)數(shù)值

 

    // 捕獲 In_clk 上升沿,捕獲 In_rst_n 下降沿

    // 計(jì)數(shù)程序塊

    always@(posedge In_clk or negedge In_rst_n)

        if(1'b0 == In_rst_n)                // 復(fù)位信號(hào)處理 計(jì)數(shù)歸零

            cnt <= 4'd0;                   

        else if(1'b1 == In_cin)            // In_cin 為高時(shí)開(kāi)始計(jì)數(shù)

            begin

                if(4'd9 == cnt)            // cnt 等于 9 則歸零

                    cnt <=4'd0;

                else

                    cnt <= cnt + 1'b1;    // cnt 小于 9 則累加

            end   

        else

            ;

   

    // 捕獲 In_clk 上升沿,捕獲 In_rst_n 下降沿

    // 溢出輸出程序塊

    always@(posedge In_clk or negedge In_rst_n)

        if(1'b0 == In_rst_n)                // 復(fù)位信號(hào)處理 計(jì)數(shù)歸零

            Out_cout <= 1'b0;

        else if(1'b1 == In_cin && 4'd9 == cnt)

            Out_cout <= 1'b1;    // In_cin 為高并且同時(shí)上個(gè)計(jì)數(shù)器計(jì)數(shù)到9則輸出1

        else

            Out_cout <= 1'b0; // 反之輸出0   

   

    assign Out_q = cnt;        // 與計(jì)數(shù)器相連輸出

   

endmodule

 

 

2、仿真測(cè)試源程序

/* 實(shí)驗(yàn)名稱:BCD 級(jí)聯(lián)計(jì)數(shù)器驗(yàn)證 */

`timescale 1ns/1ns

`define clock_period 20

module mytest_tb;

    reg clk;

    reg cin;

    reg rst_n;

       

    wire cout;   

    wire [11:0]q;

   

    mytest BCD_Counter(

            .In_clk(clk),

            .In_cin(cin),

            .In_rst_n(rst_n),

            .Out_cout(cout),

            .Out_q(q)   

        );

       

    initial clk = 1'b1;

    always #(`clock_period / 2) clk = ~clk;

   

    initial begin

        // 復(fù)位

        rst_n = 1'b0;

        cin = 1'b0;

        #(`clock_period * 200);

        rst_n = 1'b1;           

        #(`clock_period * 20);

        // 直接給高電平,讓它在每個(gè)時(shí)鐘周期都計(jì)數(shù)

        cin = 1'b1;           

        #(`clock_period * 5000);

       

        $stop;

    end

 

endmodule

 

 

仿真后出現(xiàn)如下波形:

那么該如何解決了,小梅哥給出一個(gè)很好的調(diào)試方式:

1、由于是三級(jí)級(jí)聯(lián)計(jì)數(shù)器,那么我們要先看每一級(jí)計(jì)數(shù)器的狀態(tài)。需要作如下步驟:

在ModelSim找到SIM窗口:

將Conuter0、Conuter1、Conuter2、都 【Add Wave】同時(shí)也看到可以通過(guò)快捷鍵【Ctrl+W】添加。

 

然后返回到【W(wǎng)ave】窗口在信號(hào)窗口中依次按下【Ctrl+A】全選、【Ctrl+G】根據(jù)模塊自動(dòng)分組

 

 

這是可以看到那些模塊是看不到信號(hào)的,需要重新編譯重新運(yùn)行才能看到:

接著就可以看到每個(gè)信號(hào)的現(xiàn)象了:

 

修復(fù)代碼如下:( 目前得到的解釋是:總之非阻塞賦值有1個(gè)時(shí)鐘周期的延遲才會(huì)生效

/* 實(shí)驗(yàn)名稱:級(jí)聯(lián)計(jì)數(shù)器

 * 程序功能:

 * 約定俗成:所有需要外部輸入的信號(hào)加入前綴"In_",所有需往外部輸出的信號(hào)加入前綴"Out_"

 */

module mytest(In_clk, In_cin, In_rst_n, Out_cout, Out_q);

 

    input In_clk;

    input In_cin;

    input In_rst_n;

    output Out_cout;

    output[11:0] Out_q;

   

    wire Out_line0;    // 計(jì)數(shù)器0的Out_cout端與計(jì)數(shù)器1的Out_cout端鏈接

    wire Out_line1;    // 計(jì)數(shù)器1的Out_cout端與計(jì)數(shù)器2的Out_cout端鏈接

    wire[3:0] q0, q1, q2;   

    // 將三組4位信號(hào)合并成一組12位的信號(hào)

    assign Out_q = {q2, q1, q0};

   

    my_Counter Conuter0(

            .In_clk(In_clk),

            .In_cin(In_cin),         // 重點(diǎn)

            .In_rst_n(In_rst_n),

            .Out_cout(Out_line0), // 重點(diǎn)

            //.Out_q(Out_q[3:0])    // 方式1

            .Out_q(q0)                // 方式2

            );

           

    my_Counter Conuter1(

            .In_clk(In_clk),

            .In_cin(Out_line0),     // 重點(diǎn) 這里來(lái)一次高電平意味這計(jì)數(shù)器0計(jì)滿

            .In_rst_n(In_rst_n),

            .Out_cout(Out_line1), // 重點(diǎn)

            //.Out_q(Out_q[7:4]) // 方式1

            .Out_q(q1)                // 方式2

            );

           

    my_Counter Conuter2(

            .In_clk(In_clk),

            .In_cin(Out_line1),     // 重點(diǎn) 這里來(lái)一次高電平意味這計(jì)數(shù)器1計(jì)滿

            .In_rst_n(In_rst_n),

            .Out_cout(Out_cout), // 重點(diǎn)

            //.Out_q(Out_q[11:8]) // 方式1

            .Out_q(q2)                // 方式2

            );

 

endmodule

 

/* 實(shí)驗(yàn)名稱:計(jì)數(shù)器

 * 程序功能:

 * 約定俗成:所有需要外部輸入的信號(hào)加入前綴"In_"

 *               所有需往外部輸出的信號(hào)加入前綴"Out_"

 */

module my_Counter(In_clk, In_cin, In_rst_n, Out_cout, Out_q);

 

    input In_clk;

    input In_cin;

    input In_rst_n;

    output reg Out_cout;

    output [3:0]Out_q;

   

    reg[3:0] cnt;                            // 存儲(chǔ)計(jì)數(shù)值

 

    // 捕獲 In_clk 上升沿,捕獲 In_rst_n 下降沿

    // 計(jì)數(shù)程序塊

    always@(posedge In_clk or negedge In_rst_n)

        if(1'b0 == In_rst_n)                // 復(fù)位信號(hào)處理 計(jì)數(shù)歸零

            cnt <= 4'd0;                   

        else if(1'b1 == In_cin)            // In_cin 為高時(shí)開(kāi)始計(jì)數(shù)

            begin

                if(4'd9 == cnt)            // cnt 等于 9 則歸零

                    cnt <=4'd0;

                else

                    cnt <= cnt + 1'b1;    // cnt 小于 9 則累加

            end   

        else

            ;

   

    /* 這段代碼會(huì)導(dǎo)致在級(jí)聯(lián)的時(shí)候每一級(jí) Out_cout 都會(huì)延遲一個(gè)時(shí)鐘周期

    // 捕獲 In_clk 上升沿,捕獲 In_rst_n 下降沿

    // 溢出輸出程序塊

    always@(posedge In_clk or negedge In_rst_n)

        if(1'b0 == In_rst_n)                // 復(fù)位信號(hào)處理 計(jì)數(shù)歸零

            Out_cout <= 1'b0;

        else if(1'b1 == In_cin && 4'd9 == cnt)

            Out_cout <= 1'b1;    // In_cin 為高并且同時(shí)上個(gè)計(jì)數(shù)器計(jì)數(shù)到9則輸出1

        else

            Out_cout <= 1'b0; // 反之輸出0   

    */

    // 修改如下

    assign Out_cout = (1'b1 == In_cin && 4'd9 == cnt);   

    assign Out_q = cnt;

   

endmodule

 

 

關(guān)于邏輯單元:

如果邏輯單元后面的數(shù)目為0,那么說(shuō)明無(wú)法實(shí)現(xiàn),說(shuō)明設(shè)計(jì)是有問(wèn)題的。

 

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩

相關(guān)帖子

回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:642632 發(fā)表于 2020-7-4 13:12 | 只看該作者
不進(jìn)行級(jí)聯(lián)的話沒(méi)有cin是可以的,你自己可能都沒(méi)搞清楚,有點(diǎn)誤導(dǎo)別人
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表