fpga之状态机实现串口发送(初学FPGA,欢迎批评指正)

1.用三个状态实现串口多个字节的数据发送

module uart_send_data(  clk,
                        reset,
                        uart_tx,
                        data40,
                        trans_go,
                        trans_done,
                        byte_number
    );
    input clk,reset;//时钟,复位
	input [2:0]byte_number;//所需传输字节数
    input [39:0]data40;//所需传输数据
    input trans_go;//开始发送数据请求信号
    output uart_tx;//数据拆为多个8位发送
    output reg trans_done;//数据发送完成信号
	reg [7:0]data;
    reg send_go;
    wire tx_done;
    uart_send ins1(.clk(clk),
            .reset(reset),
            .send_go(send_go),
            .data(data),
            .baud_set(4),
            .uart_tx(uart_tx),
            .tx_done(tx_done)
                );
	
	reg [2:0]state;
	reg [5:0]cnt;
	reg [39:0]r_data40;
	always@(posedge trans_go )
	if(trans_go)
	   r_data40=data40;   
	else
	   r_data40=r_data40;//发送请求信号来,就将数据存储到r_data40中
	
	always@(posedge clk or negedge reset)
    if(!reset)
		cnt<=0;
    else if(tx_done)begin
        if(cnt==byte_number-1)
            cnt<=0;
        else
            cnt<=cnt+1'b1;    
    end//所需传输数据data40发送完成,就将计数器清0.每次发送8位完成后cnt加一
	
	
	always@(posedge tx_done)
	r_data40={r_data40[7:0],r_data40[39:8]};//每发送完一次8位数据,就将r_data40右移8位
	
	
    
	always@(posedge clk or negedge reset)
    if(!reset)begin
        state<=0;
        data<=0;
        send_go<=0;
        state<=0;
        trans_done<=0;
        end
    else begin
	case(state)
	0:begin
	    trans_done<=0;
		if(trans_go)begin
			state<=1;
			data<=r_data40[7:0];
			send_go<=1;
			end
	    else
			state<=0;	
	end//此状态下,等待trans_go。trans_go来临时,进入下一状态,同时启动发送8位数据
	
	1:begin
		if(cnt==byte_number-1)begin
			state<=2;			
			data<=r_data40[7:0];
		    send_go<=1;
			end//满足条件,进入下一状态,发最后8位信号
		else begin
			if(tx_done)begin
			    
				data<=r_data40[7:0];
				send_go<=1;
				state<=1;
				end
			else begin
				data<=data;
				send_go<=0;
				state<=1;
			
			end
				
			
		end
			
	end//
	
	2:begin
		if(tx_done) begin
			state<=0;
			send_go<=0;
            trans_done<=1;//判断最后8位是否发完,发完回到0状态,继续等待	
		end
		else begin
			state<=2;
			send_go<=0;
            trans_done<=0;
		end
		
			
	end
	endcase
	end
	
	
	

        
    
endmodule

2.串口发送模块uart_send的代码

module uart_send(clk,
reset,
send_go,
data,
baud_set,
uart_tx,
tx_done

    );
    input clk,reset,send_go;
    input [2:0]baud_set;
    input[7:0] data;
    output reg uart_tx,tx_done;
    
    reg [7:0]r_data;
    always@(posedge clk )
    if(send_go)
        r_data<=data;
    else
        r_data<=r_data;//数据锁存
            
    reg send_en;
    always@(posedge clk or posedge reset)
    if(!reset)
        send_en<=0;
    else if(send_go)
        send_en<=1;
    else if(tx_done)
        send_en<=0;//外部发送信号控制内部发送信号
    
    reg[17 :0] bps_DR;
    always@(posedge clk or posedge reset)
        if(!reset)
            bps_DR <= 17  'd5207;
        else begin
            case(baud_set)
            0:bps_DR <= 17'd5207;
            1:bps_DR <= 17'd2603;
            2:bps_DR <= 17'd1301;
            3:bps_DR <= 17'd867;
            4:bps_DR <= 17'd433;
            default:bps_DR <= 17'd5207;
            endcase
        end//波特率选择控制
        
    reg [17:0]counter;
    always@(posedge clk or posedge reset)
    if(!reset)
        counter<=0;
    else if(send_en)begin
        if(counter==bps_DR)
            counter<=0;
        else
            counter<=counter+1'b1;
    end
    else
        counter<=0;    
    
    reg [4:0]counter1;
    always@(posedge clk or posedge reset)
    if(!reset)
        counter1<=1;
    else if(send_en)begin
    if(counter==1)begin
        if(counter1==11)
            counter1<=0;
        else
            counter1<=counter1+1'b1;
    end
    end
    else
        counter1<=0;
        
        
    always@(posedge clk or posedge reset)
    if(!reset)begin
        uart_tx<=0;
        
        end
    else begin
        case(counter1)
       
        1:begin uart_tx<=0;end
        2:uart_tx<=r_data[0];
        3:uart_tx<=r_data[1];
        4:uart_tx<=r_data[2];
        5:uart_tx<=r_data[3];
        6:uart_tx<=r_data[4];
        7:uart_tx<=r_data[5];
        8:uart_tx<=r_data[6];
        9:uart_tx<=r_data[7];
        10:uart_tx<=1;
        11:begin uart_tx<=1;end
        default:uart_tx<=1;
        endcase       
    end//发送数据
        
    always@(posedge clk or posedge reset)
    if(!reset)
        tx_done<=0;
    else if(counter1==11&&counter==2)
        tx_done<=1;
    else 
        tx_done<=0;//发送完成信号
    
    
                
        
        
endmodule

3.仿真文件

module uart_send_data_tb();
reg clk,reset;
reg [39:0]data40;
reg trans_go;
reg [2:0]byte_number;
wire uart_tx;
wire trans_done;
       uart_send_data uart_send_data(clk,
            reset,
            uart_tx,
            data40,
            trans_go,
            trans_done,
            byte_number
                );
       initial clk=0;
       always#10 clk=~clk;
       
       initial begin
       reset=0;
       data40=0;
       trans_go=0;
       byte_number=5;
       #201
       reset=1;
       #200;
       data40=40'h123456789a;
       trans_go=1;
       #20;
       trans_go=0;
       @(posedge trans_done)
       #20000;
       data40=40'ha987654321;
       trans_go=1;
       #20;
       trans_go=0;
       @(posedge trans_done)
       #20000;
       $stop;
       
       end
endmodule

4.仿真结果

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值