超过飞飞系列-ZYNQ之FPGA学习3.6.2串口接收过程(基于正点原子ZYNQ)

一、基础知识
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 首先uart_rxd有高电平到低电平(一个下降沿)变化时,start_flag则拉高一个周期
  2. 把异步数据同步到系统时钟下是因为,如果是异步数据库,不做同步处理,则会产生亚稳态,会对系统功能产生影响
  3. 5000000/115200=434(约等于) 0001 1011 0010 (此时位宽为9)若波特率低,则需要位宽更大,则把位宽定义为[15:0]。例如5000000/9600=520 (0010 0000 1000)
  4. rx_cnt到9时只有一半,没等停止位结束,提前把rx_flag拉低,检测下一位起始位留出时间
    二、程序
module uart_recv()
	input			sys_clk,
	input			sys_rst_n,

	input			uart_rxd,
	output reg[7:0]	uart_data,
	output reg		uart_done
	);

parameter CLK_FREQ = 50_000_000;
parameter UART_BPS = 115200;
parameter BPS_CNT = CLK_FREQ/UART_BPS;

reg uart_rxd_d0;	//定义两个寄存器
reg uart_rxd_d1;
reg rx_flag;
reg [3:0]rx_cnt;
reg	[15:0]clk_cnt;		//上3
reg [7:0]rx_data;

wire start_flag;

assign start_flag = uart_rxd_d1 & (~uart_rxd_d0);

always @(posedge clk or negedge rst_n)begin	//把异步数据同步到系统时钟上2
	if(!sys_rst_n)begin		//复位
		uart_rxd_d0 <=1'b1;
		uart_rxd_d1 <=1'b1;
	end
	else begin			
		uart_rxd_d0 <= uart_rxd;			
		uart_rxd_d1 <= uart_rxd_d0;
	end
end


always @(posedge clk or negedge rst_n)begin		//通过start_flag看rx_flag
	if(!sys_rst_n)
		rx_flag <= 1'b0;
	else if(stat_flag)
		rx_flag <= 1'b1;
	else if(rx_cnt == 4'd9) && (clk_cnt == BPS_CNT/2-1'b1)//上4
		rx_flag <= 1'b0;

end
endmodule

always @(posedge clk or negedge rst_n)begin		//通过rx_flag看clk_cnt
	if(!sys_rst_n)
			clk_cnt <= 16'd0;
	else if(rx_flag)begin
			if(clk_cnt < BPS_CNT-1'b1)
			clk_cnt <= clk_cnt + 1'b1;
		else
			clk_cnt <=16'd0;
	end 
	else
		clk_cnt <=16'd0;

end
endmodule

always @(posedge clk or negedge rst_n)begin		//通过rx_flag看rx_cnt
	if(!sys_rst_n)
			rx_cnt <= 4'd0;
	else if(rx_flag)begin
			if(clk_cnt == BPS_CNT -1'b1)
				rx_cnt  <= rx_cnt +1'b1;
			else
				rx_cnt  <= rx_cnt ;
	end 
	else
		rx_cnt <= 4'd0;
end
endmodule

always @(posedge clk or negedge rst_n)begin		//通过rx_flag和rx_cnt判断rx_data
	if(!sys_rst_n)
		rx_data <=8'd0;				//寄存串行数据
	else if(rx_flag && (clk_cnt == BPS_CNT/2))begin			//在1/2时钟周期值比较稳定
		case(rx_cnt)					//数据串转并
		4‘d1 : rx_data[0] <= uart_rxd_d1;
		4‘d2 : rx_data[1] <= uart_rxd_d1;
		4‘d3 : rx_data[2] <= uart_rxd_d1;
		4‘d4 : rx_data[3] <= uart_rxd_d1;
		4‘d5 : rx_data[4] <= uart_rxd_d1;
		4‘d6 : rx_data[5] <= uart_rxd_d1;
		4‘d7 : rx_data[6] <= uart_rxd_d1;
		4‘d8 : rx_data[7] <= uart_rxd_d1;
		endcase
	end
end

endmodule


always @(posedge clk or negedge rst_n)begin		//最后对uart_done和uart_data赋值
	if(!sys_rst_n)begin
		uart_done <= 1'b0;
		uart_data <= 8'd0;
	end
	else if(rx_cnt == 4'd9)begin
		uart_done <= 1'b1;
		uart_data  <= rx_data;
	else begin				//rx_cnt不等于9位低电平
		uart_done <= 1'b0;
		uart_data <= 8'd0;
	end
end

endmodule
原创文章 26 获赞 4 访问量 798

猜你喜欢

转载自blog.csdn.net/qq_42280105/article/details/105851225