串行通信原理及实验仿真

1. 处理器与外部设备通信的两种方式:
并行通信和串行通信

并行通信是指数据的各个位用多条数据线同时进行传输
在这里插入图片描述
优点:传输速度快
缺点:占用引脚资源多
串行通信是将数据分成一位一位的形式在一条传输线上逐个传输
在这里插入图片描述
优点:通信线路简单,占用引脚资源少
缺点:传输速度慢
2. 串行通信的通信方式:
同步通信和异步通信

同步通信:带有时钟同步信号的数据传输;发送方和接收方在同一时钟的控制下,同步传输数据。
在这里插入图片描述
异步通信:不同时钟同步信号的数据传输。发送方和接收方使用各自的时钟控制数据的发送和接收过程。
在这里插入图片描述
3. 串行通信的传输方向
单工:数据只能沿一个方向传输
半双工:数据传输可以沿两个方向,但需要分时进行
全双工:数据可以同时进行双向传输
在这里插入图片描述
4. 常见的串行通信接口
在这里插入图片描述
5. UART
是一种采用异步串行通信方式的通用异步收发传输器
功能:
它在发送数据时将并行数据转换成串行数据来输出,在接收数据时将接收到的串行数据转换成并行数据
a. 协议层:通信协议(包括数据格式、数据速率等)
UART串口通信需要两根信号线来实现,一根用于串口发送,另外一根负责串口接收
在这里插入图片描述
串口通信常用的波特率有9600/19200/38400/115200等
b. 物理层:接口类型,电平标准等
针对异步串行通信的接口标准有RS232、RS422、RS485
在这里插入图片描述
接口定义:
在这里插入图片描述
在这里插入图片描述
6. 串口通信实验

module uart_top(
	input	sys_clk,
	input	sys_rst_n,
	input	uart_rxd,
	output	uart_txd
);
	parameter	CLK_FREQ = 50000000;
	parameter	UART_BPS = 115200;
	
	wire		uart_en_w;
	wire [7:0]	uart_data_w;

	uart_recv #(
	.CLK_FREQ	(CLK_FREQ),
	.UART_BPS	(UART_BPS))
	u_uart_recv(
	.sys_clk	(sys_clk),
	.sys_rst_n	(sys_rst_n),
	
	.uart_rxd	(uart_rxd),
	.uart_done	(uart_en_w),
	.uart_data	(uart_data_w)
	);

	uart_send #(
	.CLK_FREQ	(CLK_FREQ),
	.UART_BPS	(UART_BPS))
	u_uart_send(
	.sys_clk	(sys_clk),
	.sys_rst_n	(sys_rst_n),
	
	.uart_en	(uart_en_w),
	.uart_din	(uart_data_w),
	.uart_data	(uart_txd)
	);
endmodule

module uart_recv(
	input				sys_clk,
	input				sys_rst_n,
		
	input				uart_rxd,
	output	reg			uart_done,
	output	reg	[7:0]	uart_data
);

	parameter	CLK_FREQ = 50000000;
	parameter	UART_BPS = 9600;
	localparam	BPS_CNT  = CLK_FREQ/UART_BPS;
	
	reg			uart_rxd_d0;
	reg			uart_rxd_d1;
	reg	[15:0]	clk_cnt;
	reg	[3:0]	rx_cnt;
	reg	[7:0]	rxdata;
	reg			rx_flag;
	
	wire		start_flag;
	
	//捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号
	assign	start_flag = uart_rxd_d1 & (~uart_rxd_d0);
	
	always @(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			uart_rxd_d0 <= 1'b0;
			uart_rxd_d1 <= 1'b0;
		end
		else begin
			uart_rxd_d0 <= uart_rxd;
			uart_rxd_d1 <= uart_rxd_d0;			
		end
	end
	
	always @(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n)
			rx_flag <= 1'b0;
		else begin
			if(start_flag)
				rx_flag <= 1'b1;
			else if((rx_cnt == 4'd9) && (clk_cnt == BPS_CNT/2))//计数到停止位中间时,停止计数,因为连续发送数据的时候,停止位一个周期后就是下降沿,又要进行下一次数据的接收
				rx_flag <= 1'b0;
			else
				rx_flag <= rx_flag;
		end
	end
	
	always @(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			clk_cnt <= 16'd0;
			rx_cnt <= 4'd0;
		end	
		else if(rx_flag) begin
			if(clk_cnt < BPS_CNT -1) begin
				clk_cnt <= clk_cnt + 1'b1;
				rx_cnt <= rx_cnt;
			end
			else begin
				clk_cnt <= 16'd0;
				rx_cnt <= rx_cnt + 1'b1;			
			end
		end
		else begin
				clk_cnt <= 16'd0;
				rx_cnt <= 4'd0;	
		end
	end
	
	//根据接收数据技术来寄存uart接收端口数据
	always @(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n)
			rxdata <= 8'd0;
		else if(rx_flag) begin
			if(clk_cnt == BPS_CNT/2) begin  //计数到中间时数据更加稳定
				case(rx_cnt)
				4'd1:rxdata[0] <= uart_rxd_d1;
				4'd2:rxdata[1] <= uart_rxd_d1;
				4'd3:rxdata[2] <= uart_rxd_d1;
				4'd4:rxdata[3] <= uart_rxd_d1;
				4'd5:rxdata[4] <= uart_rxd_d1;
				4'd6:rxdata[5] <= uart_rxd_d1;
				4'd7:rxdata[6] <= uart_rxd_d1;
				4'd8:rxdata[7] <= uart_rxd_d1;
				default:;
				endcase
			end
			else	
				rxdata <= rxdata;
		end
		else
			rxdata <= 8'd0;
	
	always @(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			uart_data <= 8'd0;
			uart_done <= 1'b0;
		end
		else if(rx_cnt == 4'd9) begin
			uart_data <= rxdata;
			uart_done <= 1'b1;		
		end
		else begin
			uart_data <= 8'd0;
			uart_done <= 1'b0;
		end
	end
endmodule

module uart_send(
	input				sys_clk,
	input				sys_rst_n,
		
	input				uart_en,
	output	reg			uart_txd,
	output	reg	[7:0]	uart_din
);

	parameter	CLK_FREQ = 50000000;
	parameter	UART_BPS = 9600;
	localparam	BPS_CNT  = CLK_FREQ/UART_BPS;
	
	reg			uart_en_d0;
	reg			uart_en_d1;
	reg	[15:0]	clk_cnt;
	reg	[3:0]	tx_cnt;
	reg	[7:0]	tx_data;
	reg			tx_flag;
	
	wire		en_flag;
	
	assign	en_flag = ~uart_en_d1 & uart_en_d0;
	
	always @(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			uart_en_d0 <= 1'b0;
			uart_en_d1 <= 1'b0;
		end
		else begin
			uart_en_d0 <= uart_en;
			uart_en_d1 <= uart_en_d0;			
		end
	end
	
	always @(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			tx_flag <= 1'b0;
			tx_data <= 8'd0;
		end
		else if(en_flag) begin
				tx_flag <= 1'b1;
				tx_data <= uart_din;
			end
			else if((tx_cnt == 4'd9) && (clk_cnt == BPS_CNT/2)) begin
				tx_flag <= 1'b0;
				tx_data <= 8'd0;
			end
			else begin
				tx_flag <= tx_flag;
				tx_data <= tx_data;
			end
	end
	
	always @(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n) begin
			clk_cnt <= 16'd0;
			tx_cnt <= 4'd0;
		end	
		else if(tx_flag) begin
			if(clk_cnt < BPS_CNT -1) begin
				clk_cnt <= clk_cnt + 1'b1;
				tx_cnt <= tx_cnt;
			end
			else begin
				clk_cnt <= 16'd0;
				tx_cnt <= tx_cnt + 1'b1;			
			end
		end
		else begin
				clk_cnt <= 16'd0;
				tx_cnt <= 4'd0;	
		end
	end
	
	always @(posedge sys_clk or negedge sys_rst_n) begin
		if(!sys_rst_n)
			uart_txd <= 1'b1;
		else if(tx_flag) begin
				case(tx_cnt)
					4'd0:uart_txd <= 1'b0;
					4'd1:uart_txd <= tx_data[0];
					4'd2:uart_txd <= tx_data[1];
					4'd3:uart_txd <= tx_data[2];
					4'd4:uart_txd <= tx_data[3];
					4'd5:uart_txd <= tx_data[4];
					4'd6:uart_txd <= tx_data[5];
					4'd7:uart_txd <= tx_data[6];
					4'd8:uart_txd <= tx_data[7];
					4'd9:uart_txd <= 1'b1;
					default:;
				endcase
		end
		else
			rxdata <= 8'd0;
	end
	
endmodule


endmodule

猜你喜欢

转载自blog.csdn.net/gemengxia/article/details/108320356