UART异步串口通信收发模块的verilog实现

本文详细介绍了UART(通用异步收发传输器)的工作原理,包括异步串行通信方式、数据格式(如起始位、数据位、奇偶校验和停止位)、波特率以及串口模块在Cortex-M微控制器中的具体实现,涉及顶层模块、接收模块和发送模块的代码示例。
摘要由CSDN通过智能技术生成

1.UART简介

         UART是一种采用异步串行通信方式的通用异步收发传输器(universal asynchronous receiver-transmitter),它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。

        UART串口通信需要两根信号线来实现,一根TX用于串口发送,一根RX负责串口接收。

起始位:空闲时为“1”,当检测到“0”,认为数据传输开始
数据位:传输开始后传递的需要接收和发送的数据值
奇偶校验位:奇偶校验,通过来校验传输数据中“1”的个数为奇数个(奇校验)或偶数个(偶校验)来指示传输数据是否正确
停止位:数据传输结束,传输线恢复常“1”状态
此外,还需关注数据传输波特率,波特率表示一秒内传输了多少个码元数量,一般波特率为300,1200,2400,9600,19200,38400,115200等。例如9600 Baud表示一秒内传输了9600个码元信息,当一个码元只含1 bit信息时,波特率=比特率

2.模块框图

        串口协议用于与其他模块之间的信息交互,包含接收模块发送模块,信号传输线上根据波特率完成码元的接收与发送,因而接收模块主要完成并串转换,串并转换是接收和发送模块必备的基本功能,发送模块完成并串转换,接收模块完成串并转换。

3.代码

3.1顶层模块

​
module	uart_top(
	input			sys_clk,
	input			sys_rst_n,
	input			uart_rxd,	
	output			uart_txd
);
 
parameter			FREQ	=	50000000;
parameter			BPS		=	9600;
 
wire				en;
wire		[7:0]	uart_data;
 
uart_recv	 #(                          //串口接收模块
    .FREQ       	(FREQ),       //设置系统时钟频率
    .BPS       		(BPS))
u_uart_recv(
	.sys_clk        (sys_clk),
	.sys_rst_n      (sys_rst_n),
	.uart_rxd       (uart_rxd),
	
	
	.uart_txd		(uart_data),
	.rx_done		(en)
);
 
uart_send	 #(                          //串口发送模块
    .FREQ       	(FREQ),       //设置系统时钟频率
    .BPS       		(BPS))
u_uart_send(
	.sys_clk        (sys_clk),
	.sys_rst_n      (sys_rst_n),
	.uart_din		(uart_data),
	.tx_en			(en),
	.uart_txd		(uart_txd)
);
 
endmodule 

​

3.2接收模块

module	uart_recv(
	input			sys_clk,
	input			sys_rst_n,
	input			uart_rxd,
	
	output	reg[7:0]	uart_txd,
	output	reg		rx_done
);
parameter			BPS		=		9600;
parameter			FREQ	=		50000000;
localparam			BPS_CNT	=		FREQ / BPS;
 
wire				start_flag;		//对uart_rxd下降沿进行检测
 
reg					uart_rxd_d0;
reg					uart_rxd_d1;
reg					rx_flag;		//接收数据标志信号
reg		[3:0]		rx_cnt;			//对接收数据计数	
reg		[15:0]		bps_cnt;		//对时钟的计数
reg		[7:0]		tx_data;		//对接收数据进行寄存
 
assign	start_flag	=	uart_rxd_d1	&	(~uart_rxd_d0);		//下降沿检测电路
 
//对uart_rxd延迟两个时钟单位
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
 
//当start_flag来临时,开始接收数据
always@(posedge	sys_clk	or	negedge	sys_rst_n)begin
	if(!sys_rst_n)
		rx_flag			<=		1'b0;
	else	
		if(start_flag)
			rx_flag		<=		1'b1;
		else if((bps_cnt == BPS_CNT/2)  &&	(rx_cnt	== 4'd9))  //接收了8个bit后,接收状态关闭
			rx_flag		<=		1'b0;
		else
			rx_flag		<=		rx_flag;
end
 
//进入接收过程后,启动系统时钟计数器与接收数据计数器
always@(posedge	sys_clk	or	negedge	sys_rst_n)begin
	if(!sys_rst_n)begin
		bps_cnt			<=		16'd0;
		rx_cnt			<=		4'd0;
		end
	else if(rx_flag)
		if(bps_cnt	<	BPS_CNT -1'b1)begin
			bps_cnt		<=		bps_cnt	+	1'b1;
			rx_cnt		<=		rx_cnt;
			end
		else	begin
			bps_cnt		<=		16'd0;
			rx_cnt		<=		rx_cnt	+	1'b1;
			end
	else	begin
		bps_cnt			<=		16'd0;
		rx_cnt			<=		4'd0;
		end
end
 
//通过计数器来寄存接收到的数据,tx_data
always@(posedge	sys_clk	or	negedge	sys_rst_n)begin
	if(!sys_rst_n)
		tx_data			<=		8'd0;
	else	if(rx_flag)		
			if(bps_cnt ==	BPS_CNT/2)begin
				case(rx_cnt)
					4'd1	:	tx_data[0]	<=	uart_rxd_d1;
					4'd2	:	tx_data[1]	<=	uart_rxd_d1;
					4'd3	:	tx_data[2]	<=	uart_rxd_d1;
					4'd4	:	tx_data[3]	<=	uart_rxd_d1;
					4'd5	:	tx_data[4]	<=	uart_rxd_d1;
					4'd6	:	tx_data[5]	<=	uart_rxd_d1;
					4'd7	:	tx_data[6]	<=	uart_rxd_d1;
					4'd8	:	tx_data[7]	<=	uart_rxd_d1;
					default	:	;
				endcase
				end
			else
				tx_data		<=		tx_data;
	else
		tx_data		<=		8'd0;
end
	
//接收数据寄存到uart_txd,并输出接收完成标志位
always@(posedge	sys_clk	or	negedge	sys_rst_n)begin
	if(!sys_rst_n)begin
		rx_done		<=		1'b0;
		uart_txd	<=		8'd0;
		end
	else	if(rx_cnt == 4'd9)begin
				rx_done		<=		1'b1;
				uart_txd	<=		tx_data;
			end
	else	begin
			rx_done		<=		1'b0;
			uart_txd	<=		8'd0;
			end
end
 
endmodule

3.3发送模块

module	uart_send(
	input			sys_clk,
	input			sys_rst_n,
	input	[7:0]	uart_din,
	input			tx_en,
	
	output	reg		uart_txd
);
 
parameter			BPS		=		9600;
parameter			FREQ	=		50000000;
localparam			BPS_CNT	=		FREQ / BPS;
 
wire				start_flag;
	
reg					tx_en_d0;	
reg					tx_en_d1;
reg					tx_flag;		//发送过程标志
reg		[15:0]		bps_cnt;
reg		[3:0]		tx_cnt;
reg		[7:0]		tx_data;
 
assign		start_flag	=		tx_en	&&	(~tx_en_d1);
 
always@(posedge	sys_clk	or	negedge	sys_rst_n)begin
	if(!sys_rst_n)begin
		tx_en_d0		<=		1'b0;
		tx_en_d1		<=		1'b0;
		end
	else	begin
		tx_en_d0		<=		tx_en;
		tx_en_d1		<=		tx_en_d0;
		end
end
 
always@(posedge	sys_clk	or	negedge	sys_rst_n)begin
	if(!sys_rst_n)begin
		bps_cnt			<=		16'd0;
		tx_cnt			<=		4'd0;
		end
	else	if(bps_cnt	<	BPS_CNT-1)begin
			bps_cnt			<=		bps_cnt+1'b1;
			tx_cnt			<=		tx_cnt;
			end
	else	begin
		bps_cnt			<=		16'd0;
		tx_cnt			<=		tx_cnt+1'b1;
		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(start_flag)begin
			tx_flag		<=		1'b1;
			tx_data		<=		uart_din;
			end
	else if((tx_cnt==4'd9)&&(bps_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)
		uart_txd		<=		1'b1;		//空闲状态,发送端为高电平
	else if(tx_flag)
			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	:	uart_txd	<=	1'b1;
				endcase
		else
			uart_txd	<=	1'b1;
end
				
endmodule

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值