采用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时钟进行时钟累加,最终实现串口每秒发送一次数据每次发送的有效数据进行累加

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值