2020年2月29日 星期六

Verilog應用範例 : 二進制轉BCD碼 適用於DE2-115 (DE2-70)


Verilog應用範例 :  二進制轉BCD碼

在項目設計中,經常需要顯示一些數值,比如溫濕度,時間等等。在數字電路中數據都是用二進制的形式存儲,要想顯示就需要進行轉換,對於一個兩位的數值,對10取除可以得到其十位的數值,對10取余可以得到個位的數值。對於Verilog來說它的標準是支持除法和取余運算的,綜合器也會有IP可以進行除法運算。但是這樣未免會耗費太多資源,使用移位加3算法就可以實現二進制到BCD碼之間的轉換。
BCD碼(Binary-Coded Decimal‎)亦稱二進碼十進數或二-十進制代碼。用4位二進制數來表示1位十進制數中的0~910個數碼。
移位加3算法簡單來說就是,有多少位二進制說,就進行多少次移位,以八位的二進制為例,其數值最高可為三位十進制數,進行如下表左移,在移位的過程中,如果移位出的數值大於4,則將改為的數值加3後再進行移位。
技術分享圖片
這裏為什麽大於四,BCD碼是四位二進制數表示一個十進制數的一位,如果這以為大於4,比如54’b0101,下一次移位後變成了4’b1010BCD碼中是沒有4’b1010的,所以要加6,向高位進位。這裏就是移位後加6和移位前加3,兩種方法修正,我這裏選擇了移位前加3。(4’b0011左移後也是4’b0110,移位前和移位後都是一樣的對BCD碼的位數進行修正)。
為什麽用左移的方法呢?這是因為二進制數和十進制數之間的位權的關系。所以二進數和十進制數之間的轉化是乘以2,也就是左移一位。轉換公式大概就是這個樣子。
技術分享圖片
 代碼實現起來不是很復雜,在網上搜索到有些代碼使用純組合邏輯實現的,用了一個for循環,我個人認為這種寫法不是很好,所以自己用狀態機寫了一個。模塊設計如下,tran_en是轉換使能信號,可以使電平使能也可以是脈沖使能,作為脈沖使能使用的時候,需要在數據來臨之後的一個時鐘周期給出使能(我的模塊是這樣的特點),電平使能有效時,需要18個時鐘周期完成轉換,輸入二進制位16bit,輸出為四組千百十個位。轉換完成後輸出一個轉換完成標誌tran_done
技術分享圖片
內部的時序我采用了三段式狀態機來完成。IDLE狀態接收到使能信號,調到移位狀態,經過16次移位。在shift_cnt17時(這裏是因為我狀態機的原理所以shift_cnt會計數到17,但移位次數為16),數據轉換完成。跳到DONE狀態,輸出轉換完成標誌。
技術分享圖片
采用組合邏輯來實現,移位後的數據值的判斷,大於43後再進行移位。最後將轉換完成後的結果輸出。
技術分享圖片
代碼如下:
  1 `timescale      1ns/1ps
  2 // *********************************************************************************
  3 // Project Name :      
  4 // Author       : NingHeChuan
  5 // Email        : ninghechuan@foxmail.com
  6 // Blogs        : http://www.cnblogs.com/ninghechuan/
  7 // File Name    : Bin_BCD.v
  8 // Module Name  :
  9 // Called By    :
 10 // Abstract     :
 11 //
 12 // CopyRight(c) 2018, NingHeChuan Studio..
 13 // All Rights Reserved
 14 //
 15 // *********************************************************************************
 16 // Modification History:
 17 // Date         By              Version                 Change Description
 18 // -----------------------------------------------------------------------
 19 // 2018/8/12    NingHeChuan       1.0                     Original
 20 // 
 21 // *********************************************************************************
 22
 23 module Bin_BCD
 24 #(
 25     parameter       DATA_WIDTH  =   16,
 26     parameter       SHIFT_WIDTH =   5,
 27     parameter       SHIFT_DEPTH =   16
 28    
 29 )
 30 (
 31     input               clk,
 32     input               rst_n,
 33     input               tran_en,
 34     input       [DATA_WIDTH - 1:0]  data_in,
 35     output   reg        tran_done,
 36     output      [3:0]   thou_data,      //千位
 37     output        [3:0]    hund_data,      //百位
 38     output        [3:0]    tens_data,      //十位
 39     output        [3:0]    unit_data       //個位
 40
 41 );
 42 //-------------------------------------------------------
 43 localparam  IDLE    =   3‘b001;
 44 localparam   SHIFT   =   3‘b010;
 45 localparam   DONE    =   3‘b100;
 46
 47 //-------------------------------------------------------
 48 reg     [2:0]   pre_state;
 49 reg     [2:0]   next_state;
 50 //
 51 reg     [SHIFT_DEPTH-1:0]   shift_cnt;
 52 //
 53 reg     [DATA_WIDTH:0]  data_reg;
 54 reg     [3:0]   thou_reg;
 55 reg        [3:0]    hund_reg;
 56 reg        [3:0]    tens_reg;
 57 reg        [3:0]    unit_reg;
 58 reg     [3:0]   thou_out;
 59 reg        [3:0]    hund_out;
 60 reg        [3:0]    tens_out;
 61 reg        [3:0]    unit_out;
 62 wire    [3:0]   thou_tmp;
 63 wire    [3:0]    hund_tmp;
 64 wire    [3:0]    tens_tmp;
 65 wire    [3:0]    unit_tmp;
 66
 67 //-------------------------------------------------------
 68 //FSM step1
 69 always  @(posedge clk or negedge rst_n)begin
 70     if(rst_n == 1‘b0)begin
 71         pre_state <= IDLE;
 72     end
 73     else begin
 74         pre_state <= next_state;
 75     end
 76 end
 77
 78 //FSM step2
 79 always  @(*)begin
 80     case(pre_state)
 81     IDLE:begin
 82         if(tran_en == 1‘b1)
 83             next_state = SHIFT;
 84         else
 85             next_state = IDLE;
 86     end
 87     SHIFT:begin
 88         if(shift_cnt == SHIFT_DEPTH + 1)
 89             next_state = DONE;
 90         else
 91             next_state = SHIFT;
 92     end
 93     DONE:begin
 94         next_state = IDLE;
 95     end
 96     default:next_state = IDLE;
 97     endcase
 98 end
 99
100 //FSM step3
101 always  @(posedge clk or negedge rst_n)begin
102     if(rst_n == 1‘b0)begin
103         thou_reg <= 4‘b0;
104         hund_reg <= 4‘b0;
105         tens_reg <= 4‘b0;
106         unit_reg <= 4‘b0;
107         tran_done <= 1‘b0;
108         shift_cnt <= ‘d0;
109         data_reg <= ‘d0;
110     end
111     else begin
112         case(next_state)
113         IDLE:begin
114             thou_reg <= 4‘b0;
115             hund_reg <= 4‘b0;
116             tens_reg <= 4‘b0;
117             unit_reg <= 4‘b0;
118             tran_done <= 1‘b0;
119             shift_cnt <= ‘d0;
120             data_reg <= data_in;
121         end
122         SHIFT:begin
123             if(shift_cnt == SHIFT_DEPTH + 1)
124                 shift_cnt <= ‘d0;
125             else begin
126                 shift_cnt <= shift_cnt + 1‘b1;
127                 data_reg <= data_reg << 1;
128                 unit_reg <= {unit_tmp[2:0], data_reg[16]};
129                 tens_reg <= {tens_tmp[2:0], unit_tmp[3]};
130                 hund_reg <= {hund_tmp[2:0], tens_tmp[3]};
131                 thou_reg <= {thou_tmp[2:0], hund_tmp[3]};
132             end
133         end
134         DONE:begin
135             tran_done <= 1‘b1;
136         end
137         default:begin
138             thou_reg <= thou_reg;
139             hund_reg <= hund_reg;
140             tens_reg <= tens_reg;
141             unit_reg <= unit_reg;
142             tran_done <= tran_done;
143             shift_cnt <= shift_cnt;
144         end
145         endcase
146     end
147 end
148 //-------------------------------------------------------
149 always  @(posedge clk or negedge rst_n)begin
150     if(rst_n == 1‘b0)begin
151         thou_out <= ‘d0;
152         hund_out <= ‘d0;
153         tens_out <= ‘d0;
154         unit_out <= ‘d0;
155     end
156     else if(tran_done == 1‘b1)begin
157         thou_out <= thou_reg;
158         hund_out <= hund_reg;
159         tens_out <= tens_reg;
160         unit_out <= unit_reg;
161     end
162     else begin
163         thou_out <= thou_out;
164         hund_out <= hund_out;
165         tens_out <= tens_out;
166         unit_out <= unit_out;
167     end
168 end
169
170
171 //-------------------------------------------------------
172 assign  thou_tmp = (thou_reg > 4‘d4)?  (thou_reg + 2d3) : thou_reg;
173 assign  hund_tmp = (hund_reg > 4‘d4)?  (hund_reg + 2d3) : hund_reg;
174 assign  tens_tmp = (tens_reg > 4‘d4)?  (tens_reg + 2d3) : tens_reg;
175 assign  unit_tmp = (unit_reg > 4‘d4)?  (unit_reg + 2d3) : unit_reg;
176
177 assign thou_data = thou_out;
178 assign hund_data = hund_out;
179 assign tens_data = tens_out;
180 assign unit_data = unit_out;
181
182
183 endmodule


//適用於DE2-115

module Binary_BCD(
  input  CLOCK_50, // 50 MHz clock
  input  [3:0] KEY,   // Pushbutton[3:0]
  input  [17:0] SW, // Toggle Switch[17:0]
  output [6:0] HEX0,HEX1,HEX2,HEX3,HEX4,HEX5,HEX6,HEX7,  // Seven Segment Digits
  output [8:0] LEDG,  // LED Green
  output [17:0] LEDR,  // LED Red
  inout  [35:0] GPIO_0,GPIO_1, // GPIO Connections
// LCD Module 16X2
  output LCD_ON, // LCD Power ON/OFF
  output LCD_BLON, // LCD Back Light ON/OFF
  output LCD_RW, // LCD Read/Write Select, 0 = Write, 1 = Read
  output LCD_EN, // LCD Enable
  output LCD_RS, // LCD Command/Data Select, 0 = Command, 1 = Data
  inout [7:0] LCD_DATA, // LCD Data bus 8 bits
  input [2:0] mess, // MESSAGE STATUS (see lcd_test)
  input [1:0] isServer // SERVER STATUS (see lcd_test)
);

// All inout port turn to tri-state
assign GPIO_0  = 36'hzzzzzzzzz;
assign GPIO_1  = 36'hzzzzzzzzz;


// blank unused 7-segment digits
// blank unused 7-segment digits
//assign HEX0 = 7'b111_1111;
//assign HEX1 = 7'b111_1111;
//assign HEX2 = 7'b111_1111;
//assign HEX3 = 7'b111_1111;
assign HEX4 = 7'b111_1111;
assign HEX5 = 7'b111_1111;
assign HEX6 = 7'b111_1111;
assign HEX7 = 7'b111_1111;

wire [7:0] segout0;   //HEX 0
wire [7:0] segout1;   //HEX 1
wire [7:0] segout2;   //HEX 2
wire [7:0] segout3;   //HEX 3

wire [3:0] othou_data;      //千位
wire [3:0] ohund_data;      //百位
wire [3:0] otens_data;      //十位
wire [3:0] ounit_data;       //個位

assign LEDR =SW ;

Bin_BCD
(
     CLOCK_50,
     KEY[0],
     SW[17],
     SW[15:0],
     LEDG[0],
     othou_data,      //千位
     ohund_data,      //百位
     otens_data,      //十位
     ounit_data       //個位

);


  _7seg UUT0(.hex(ounit_data),
               .seg(segout0));
               
    _7seg UUT1(.hex(otens_data),
               .seg(segout1));           
               
    _7seg UUT2(.hex(ohund_data),
               .seg(segout2));
               
    _7seg UUT3(.hex(othou_data),
               .seg(segout3));   
               
    assign HEX0=segout0[6:0];
    assign HEX1=segout1[6:0];     
    assign HEX2=segout2[6:0];
    assign HEX3=segout3[6:0];   

endmodule



module Bin_BCD
#(

 parameter       DATA_WIDTH  =   16,
 parameter       SHIFT_WIDTH =   5,
 parameter       SHIFT_DEPTH =   16
)
(
     input  clk,
     input  rst_n,
     input  tran_en,
     input  [DATA_WIDTH - 1:0]  data_in,
     output reg  tran_done,
     output [3:0] thou_data,      //千位
     output [3:0] hund_data,      //百位
     output [3:0] tens_data,      //十位
     output [3:0] unit_data       //個位

);
//-------------------------------------------------------

 localparam  IDLE    =    3'b001;
 localparam   SHIFT   =   3'b010;
 localparam   DONE    =   3'b100;

 //-------------------------------------------------------
 reg     [2:0]   pre_state;
 reg     [2:0]   next_state;
 //
 reg     [SHIFT_DEPTH-1:0]   shift_cnt;
 //
 reg     [DATA_WIDTH:0]  data_reg;
 reg     [3:0]   thou_reg;
 reg        [3:0]    hund_reg;
 reg        [3:0]    tens_reg;
 reg        [3:0]    unit_reg; 
 reg     [3:0]   thou_out;
 reg        [3:0]    hund_out;
 reg        [3:0]    tens_out;
 reg        [3:0]    unit_out; 
 wire    [3:0]   thou_tmp;
 wire    [3:0]    hund_tmp;
 wire    [3:0]    tens_tmp;
 wire    [3:0]    unit_tmp;

 //-------------------------------------------------------
 //FSM step1
 always  @(posedge clk or negedge rst_n)begin
     if(rst_n == 1'b0)begin
         pre_state <= IDLE;
     end
     else begin
         pre_state <= next_state;
     end
 end

 //FSM step2
 always  @(*)begin
     case(pre_state)
     IDLE:begin
         if(tran_en == 1'b1)
             next_state = SHIFT;
         else 
             next_state = IDLE;
     end
     SHIFT:begin
         if(shift_cnt == SHIFT_DEPTH + 1)
             next_state = DONE;
         else 
             next_state = SHIFT;
     end
     DONE:begin
         next_state = IDLE;
     end
     default:next_state = IDLE;
     endcase
 end

 //FSM step3
 always  @(posedge clk or negedge rst_n)begin
     if(rst_n == 1'b0)begin
         thou_reg <= 4'b0; 
         hund_reg <= 4'b0;
         tens_reg <= 4'b0; 
         unit_reg <= 4'b0;
         tran_done <= 1'b0;
         shift_cnt <= 'd0; 
         data_reg <= 'd0;
     end
     else begin
         case(next_state)
         IDLE:begin
            thou_reg <= 4'b0;  
            hund_reg <= 4'b0;  
            tens_reg <= 4'b0; 
            unit_reg <= 4'b0; 
            tran_done <= 1'b0;
            shift_cnt <= 'd0; 
            data_reg <= data_in;
        end
        SHIFT:begin
             if(shift_cnt == SHIFT_DEPTH + 1)
                shift_cnt <= 'd0;
             else begin
                 shift_cnt <= shift_cnt + 1'b1;
                 data_reg <= data_reg << 1;
                 unit_reg <= {unit_tmp[2:0], data_reg[16]};
                 tens_reg <= {tens_tmp[2:0], unit_tmp[3]};
                 hund_reg <= {hund_tmp[2:0], tens_tmp[3]};
                 thou_reg <= {thou_tmp[2:0], hund_tmp[3]};
             end
         end
         DONE:begin
             tran_done <= 1'b1;
         end
         default:begin
             thou_reg <= thou_reg; 
             hund_reg <= hund_reg; 
             tens_reg <= tens_reg; 
             unit_reg <= unit_reg; 
             tran_done <= tran_done;
             shift_cnt <= shift_cnt; 
         end
         endcase
     end
 end
 //-------------------------------------------------------
 always  @(posedge clk or negedge rst_n)begin
     if(rst_n == 1'b0)begin
         thou_out <= 'd0;
         hund_out <= 'd0;
         tens_out <= 'd0;
         unit_out <= 'd0;
     end
     else if(tran_done == 1'b1)begin
         thou_out <= thou_reg;
         hund_out <= hund_reg;
         tens_out <= tens_reg;
         unit_out <= unit_reg;
     end
     else begin
         thou_out <= thou_out;
         hund_out <= hund_out;
         tens_out <= tens_out;
         unit_out <= unit_out;
     end
 end


 //-------------------------------------------------------
 assign  thou_tmp = (thou_reg > 4'd4)?  (thou_reg + 2'd3) : thou_reg;
 assign  hund_tmp = (hund_reg > 4'd4)?  (hund_reg + 2'd3) : hund_reg;
 assign  tens_tmp = (tens_reg > 4'd4)?  (tens_reg + 2'd3) : tens_reg; 
 assign  unit_tmp = (unit_reg > 4'd4)?  (unit_reg + 2'd3) : unit_reg; 

 assign thou_data = thou_out;
 assign hund_data = hund_out;
 assign tens_data = tens_out;
 assign unit_data = unit_out;


endmodule 


//-----------------------------------------
//Common-cathod seven segment display
//using case.....endcase statement
//Filename : sevenseg_case.v
//----------------------------------------- 
module _7seg(hex , seg);
    input  [3:0] hex;
    output [7:0] seg;
    reg    [7:0] seg;
    
        

 // segment encoding
 //      0
 //     ---  
 //  5 |   | 1
 //     ---   <- 6
 //  4 |   | 2
 //     ---
 //      3
 always @(hex)
 begin
  case (hex)
       // Dot point is always disable
       4'b0001 : seg = 8'b11111001;   //1 = F9H
       4'b0010 : seg = 8'b10100100;   //2 = A4H
       4'b0011 : seg = 8'b10110000;   //3 = B0H
       4'b0100 : seg = 8'b10011001;   //4 = 99H
       4'b0101 : seg = 8'b10010010;   //5 = 92H
       4'b0110 : seg = 8'b10000010;   //6 = 82H
       4'b0111 : seg = 8'b11111000;   //7 = F8H
       4'b1000 : seg = 8'b10000000;   //8 = 80H
       4'b1001 : seg = 8'b10010000;   //9 = 90H
       4'b1010 : seg = 8'b10001000;   //A = 88H
       4'b1011 : seg = 8'b10000011;   //b = 83H
       4'b1100 : seg = 8'b11000110;   //C = C6H
       4'b1101 : seg = 8'b10100001;   //d = A1H
       4'b1110 : seg = 8'b10000110;   //E = 86H
       4'b1111 : seg = 8'b10001110;   //F = 8EH
       default : seg = 8'b11000000;   //0 = C0H
     endcase
   end
   
endmodule

沒有留言:

張貼留言

Messaging API作為替代方案

  LINE超好用功能要沒了!LINE Notify明年3月底終止服務,有什麼替代方案? LINE Notify將於2025年3月31日結束服務,官方建議改用Messaging API作為替代方案。 //CHANNEL_ACCESS_TOKEN = 'Messaging ...