FPGA串口接收与发送详解( part 2 )

目录

一、单个数据接收程序

二、单个数据顶层代码


part 1的链接放这里:FPGA串口接收与发送 详解 (part 1 )_居安士的博客-CSDN博客 

part 2来继续详解FPGA的串口

一、单个数据接收程序

串口数据接收程序输入为10位串行数据RX,输出为8位并行数据dout

接收波特率生成程序会给接收波特率使能RX_baud_en,而本程序需要给接收波特率生成程序开始接收数据标志位RX_start

此外,我们还需要设置一个数据输出完成使能信号dout_en,设置10位数据寄存器[9:0] data_save计数10位数据[3:0] data_num

单个数据接收步骤:

(1)开始接收信号rx_start的生成:把RX延时3拍,取RX的下降沿(因为起始位为低电平,从高电平到低电平意味着开始通信)作为开始接收信号时刻rx_start=1,把10位都接收完(data_num=10)作为接收完成的标志rx_start=0。

(2)确定data_num计数的个数:来一个RX_baud_en计数一次

  (3) 接收数据:来一个clk,采样一次,并且存入data_save,拼位data_save

(4)输出8位并行数据:把data_save的1-8位依次存入dout

(5)输出传输完成信号dout_en:把rx_start=0与rx_clk延时两次后=1作为结束信号(确保dout_en 输出是在rx_start=0即接收完成之后)

module data_RX(
input clk_25m,
input reset,
input RX,//10位串行数据
input RX_baud_en,//接收数据波特率
output reg [7:0] dout,//8位并行数据
output reg RX_start,//开始接收数据标志位
output reg dout_en //数据输出完成使能信号
    );
    
    reg [3:0] data_num;//计数10位数据
    reg [9:0] data_save;//10位数据寄存器
    
    /*把RX延时3拍*/
reg RX0;//把串行数据RX信号延时3拍
reg RX1;
reg RX2;

always @(posedge clk_25m)begin 
 if(reset)begin 
  RX0<=1'b1;
  RX1<=1'b1;
  RX2<=1'b1;
 end 
 else begin   
  RX0<=RX;
  RX1<=RX0;
  RX2<=RX1;
 end 
end 

    
/*产生RX_start*/    
    always@(posedge clk_25m)begin
    	if(reset)begin
    		RX_start<=1'd0;
    	end
    	else if(RX2&&!RX1)begin//RX2下降沿开始接收
    		RX_start<=1'd1;
    	end
    	else if(data_num==4'd10)begin//当data_num=10时,停止接收,保证所有数据都接收完成
    		RX_start<=1'd0;
    	end
    	else begin
    		RX_start<=RX_start;
    	end
    end

/*计数data_num*/      
    always@(posedge clk_25m)begin
    	if(reset)begin
    		data_num<=4'd0;
    	end
    	else if(RX_start)begin
    		if(RX_baud_en)begin
    			data_num<=data_num+4'd1;
    		end
    		else begin
    			data_num<=data_num;
    		end
    	end
    	else begin
    		data_num<=4'd0;
    	end
    end
    

/*数据接收,产生data_save*/  
		always@(posedge clk_25m)begin
			if(reset)begin
				data_save<=10'd0;
			end
			else if(RX_start)begin
				if(RX_baud_en)begin
					data_save<={RX2,data_save[9:1]};//把RX2的数据一位一位移位进data_save
				end
				else begin
					data_save<=data_save;//不需要清零,下一次的数据会挤掉上一次的
				end
			end
			else begin
				data_save<=10'd0;
			end
		end   
/*数据接收,产生dout*/ 		
	always @(posedge clk_25m)begin 
 		if(reset)begin 
  		dout<=8'd0;
	 	end  
	 	else begin 
	  	dout<=data_save[8:1];//把1到8位给dout
	 	end    
	end

    
/*输出数据接收完成信号*/ 

reg RX_baud_en_dly;//RX_baud_en打一拍

always@(posedge clk_25m)begin
	if(reset)begin
		RX_baud_en_dly<=1'd0;
	end
	else begin
		RX_baud_en_dly<=RX_baud_en;
	end
end

		always@(posedge clk_25m)begin
			if(reset)begin
				dout_en<=1'd0;
			end
			else if(!RX_start&&RX_baud_en_dly)begin//接收数据完成
				dout_en<=1'd1;
			end
			else begin
				dout_en<=1'd0;
			end
		end   
    
endmodule

二、单个数据顶层代码

 将发送数据波特率生成程序,单个数据发送程序,接收数据波特率生成程序,单个数据接收程序,都例化到顶层文件里

module uart_top(
input clk_25m,
input reset,
input [7:0] din,
input din_en,
input RX,
output [7:0]dout
output dout_en,
output TX
    );



wire TX_start;
wire TX_baud_en;
wire   RX_start;  
wire   RX_baud_en;


  
    TX_baud inst_TX_baud(
      .clk_25m   (clk_25m),
      .reset     (reset),
      .TX_start  (TX_start),//开始发送数据标志位
      .TX_baud_en(TX_baud_en) //发送数据波特率使能
    );
    
     data_TX inst_data_TX(
       .clk_25m   (clk_25m),
       .reset     (reset),
       .TX_baud_en(TX_baud_en),//发送数据波特率使能
       .din       (din),//8位数据
       .din_en    (din_en),//数据使能
       .TX_start  (TX_start),//开始发送数据标志位
       .TX        (TX) //串行数据
    );
    
    RX_baud inst_RX_baud(
      .clk_25m    (clk_25m),
      .reset      (reset),
      .RX_start   (RX_start),//开始接收数据标志位
      .RX_baud_en (RX_baud_en) //接收波特率使能
    );
    
    data_RX inst_data_RX(
      .clk_25m    (clk_25m),
      .reset      (reset),
      .RX         (RX),//10位串行数据
      .RX_baud_en (RX_baud_en),//接收数据波特率
      .dout       (dout),//8位并行数据
      .RX_start   (RX_start),//开始接收数据标志位
      .dout_en    (dout_en) //数据输出完成使能信号
    );
    
endmodule

对顶层文件进行仿真,这里我们可以把TX和RX连接起来,也就是说,将8位数据通过TX变成串行数据,将此串行数据给RX,RX转化成原先发送的8位数据

module TB_uart_top(

    );
reg clk_25m=0;
reg reset;
reg [7:0]din;
reg din_en;
wire [7:0]dout;
wire dout_en;
wire RX;
wire TX ;   

assign RX=TX;

    uart_top inst_uart_top(
      .clk_25m (clk_25m) ,
      .reset   (reset) ,
      .din     (din) ,
      .din_en  (din_en) ,
      .RX      (RX),
      .dout    (dout),
      .dout_en (dout_en),
      .TX      (TX)
    );
    
    initial begin
    	clk_25m=0;
    	reset=1;
    	din_en=0;
    	din=8'h55;
    	
    	#1000;
    	reset=0;
    	din_en=1;
    	#30;
    	din_en=0;
    end
    
    always #20 clk_25m=~clk_25m;
    
endmodule

由于使用了assign语法,所以TX和RX都需要定义为wire型

首先看一下波特率:

RX确实在TX周期的中间采样

再看一下数据发送与接收 :

dout和din是相同的,都是8'd55 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值