天天看點

采用FPGA實作序列槽多位元組發送

所用序列槽為RS232,

波特率設定為5種速率可調,其中預設為115200bps,

在csdn上見多了采用Moore類型狀态機編寫的序列槽單位元組發送子產品和多位元組發送子產品,部落客偏要自己寫一份Mealy類型的狀态機,用來實作單位元組發送和多位元組發送。

另外,根據我自己的個人情況,我認為Mealy型狀态機要比Moore型狀态機友善的多!!

代碼及最終的測試結果如下:

歡迎大家進行借鑒和讨論,其中,多位元組發送子產品部落客根據實際需求命名為資料回報子產品,使用者可根據自己想法進行更改。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/08/17 14:33:07
// Design Name: 
// Module Name: uart_tx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 序列槽單位元組發送
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module uart_tx(
    input clk,          //50Mhz
    input rst_n,
    input [3:0]bps_set, //波特率設定
    input [7:0]byte,    //待發送資料
    input byte_en,      //待發送資料使能
    output tx,          //序列槽發送引腳
    output tx_done      //序列槽單位元組發送完畢
    );
    
    reg st;
    reg byte_en_r1;
    reg byte_en_r2;
    reg [7:0]byte_r;
    reg [9:0]data;
    reg bps_clk_r1;
    reg bps_clk_r2;
    reg tx_r;
    reg [3:0]bit_cnt;
    reg tx_done_r;
    
    wire bps_clk;
    
    //資料發送
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            st<=1'b0;
            byte_en_r1<=1'b1;
            byte_en_r2<=1'b1;
            byte_r<=8'd0;
            data<=10'd0; 
            bps_clk_r1<=1'b1;
            bps_clk_r2<=1'b1;  
            tx_r<=1'b1;			//序列槽發送引腳常高,
            bit_cnt<=4'd0;
            tx_done_r<=1'b0;     
        end
        else begin
        byte_en_r1<=byte_en;
        byte_en_r2<=byte_en_r1;
        byte_r<=byte;
        bps_clk_r1<=bps_clk;
        bps_clk_r2<=bps_clk_r1;
        case(st)
        1'b0:begin
            if(byte_en_r1==1'b1 && byte_en_r2==1'b0)begin	//單位元組發送使能
                st<=8'd1;
                data<={1'b1,byte_r,1'b0};	//起始位低電平,停止位高電平,中間8位是待發送位元組,
            end
            else begin
                st<=8'd0;
                data<=10'd0;
                tx_done_r<=1'b0;
            end
        end
        8'd1:begin
            if(bps_clk_r1==1'b1 && bps_clk_r2==1'b0)begin	//序列槽時鐘上升沿到來,更新序列槽發送引腳上的資料,
                if(bit_cnt>=4'd10)begin		//判斷序列槽是否發送完10bits資料,
                    st<=1'b0;
                    bit_cnt<=4'd0;
                    tx_r<=1'b1;
                    data<=10'd0;
                    tx_done_r<=1'b1;
                end
                else begin
                    st<=1'b1;
                    bit_cnt<=bit_cnt+1'b1;
                    tx_r<=data[0];
                    data<={1'b0,data[9:1]};
                    tx_done_r<=1'b0;
                end                
            end
            else begin
                st<=st;
                bit_cnt<=bit_cnt;
                tx_r<=tx_r;
                data<=data;
                tx_done_r<=tx_done_r;
            end
        end
        endcase
        end
    end
    
    assign tx       =tx_r;          //序列槽發送引腳
    assign tx_done  =tx_done_r;     //序列槽單位元組發送完畢
        
    //時鐘分頻,生成序列槽時鐘,
    bps_div bps_div(
        .clk_in(clk),
        .rst_n(rst_n && st),	//序列槽工作時,st==1'b1,即隻有在序列槽工作時才産生分頻,
        .bps_set(bps_set),
        .clk_out(bps_clk)
        );
    
endmodule
           
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/08/17 18:54:08
// Design Name: 
// Module Name: Data_Feedback
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 資料回報子產品
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module Data_Feedback(
    input clk,
    input rst_n,
    input [15:0]frame_cnt,      //回報目前圖像幀數,也是目前子產品的多位元組發送資料,
    input frame_en,				//序列槽多位元組發送使能,
    input tx_done,				//序列槽單位元組發送完畢,
    output [7:0]tx_byte,		//序列槽單位元組待發送資料,
    output tx_en				//序列槽單位元組待發送資料使能,
    );
    
    reg [1:0]st;
    reg frame_r1;
    reg frame_r2;
    reg [15:0]frame_cnt_r;
    reg [31:0]data;
    reg [7:0]tx_byte_r;
    reg tx_en_r;
    reg tx_done_r1;
    reg tx_done_r2;
    reg [7:0]byte_cnt;
    
    //将多位元組資料逐個發送
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            st<=2'd0;
            frame_r1<=1'b1;
            frame_r2<=1'b1;
            frame_cnt_r<=16'd0;
            data<=32'd0;
            tx_byte_r<=8'd0;
            tx_en_r<=1'b0;
            tx_done_r1<=1'b1;
            tx_done_r2<=1'b1;
            byte_cnt<=8'd0;   
        end
        else begin
            frame_r1<=frame_en;
            frame_r2<=frame_r1;
            frame_cnt_r<=frame_cnt;
            tx_done_r1<=tx_done;
            tx_done_r2<=tx_done_r1;
            case(st)
            2'd0:begin
                if(frame_r1==1'b1 && frame_r2==1'b0)begin		//檢測到序列槽多位元組發送使能信号,
                    st<=2'd1;
                    data<={8'hFE,frame_cnt_r[7:0],frame_cnt_r[15:8],8'hEF};		//将待發送資料鎖存,其中EF是幀頭,FE是幀尾,		
                end
                else begin
                    st<=2'd0;
                    data<=32'd0;
                end
            end
            2'd1:begin
                st<=2'd2;
                tx_byte_r<=data[7:0];	//更新待發送的單位元組資料,
                tx_en_r<=1'b1;          //單位元組發送使能,  
                data<={{8{1'b0}},data[31:8]};	//進行一個資料的移位,
            end
            2'd2:begin
                tx_en_r<=1'b0;
                if(tx_done_r1==1'b1 && tx_done_r2==1'b0)begin	//檢測到單位元組發送完畢後進行下一個位元組發送,直至多位元組發送完畢。
                    if(byte_cnt>=8'd3)begin
                        st<=8'd0;
                        byte_cnt<=8'd0;                          
                    end
                    else begin
                        st<=8'd1;
                        byte_cnt<=byte_cnt+1'b1;
                    end                
                end
                else begin
                    st<=st;
                    byte_cnt<=byte_cnt;
                end
            end
            default:st<=2'd0;
            endcase
        end
    end
    
    assign tx_byte      =tx_byte_r;
    assign tx_en        =tx_en_r;
    
endmodule
           

以下是采用50Mhz時鐘進行時鐘累加,最終實作序列槽每秒發送一次資料,每次發送的有效資料進行累加。

采用FPGA實作序列槽多位元組發送

繼續閱讀