FPGA 学习:verilog语言,串口协议

通用异步收发器 UART(Universal Asynchronous Receiver/Transmitter),常称为串口,是一种串行、异步、全双工的通信协议,将数据逐位传输。只需要3根线:TX,RX,GND。

UART通讯在使用前需要进行设置,常见设置包括数据位,波特率,奇偶校验类型等。

UART_TX发送模块:

module uart_send #(
          parameter  CLK_FREQ = 32'd50_000_000,
		  parameter  UART_BPS = 115200
)(

	input            sys_clk       ,
	input            sys_rst       ,
	
	output reg       uart_tx       ,          
	input            tx_data_vld   ,           
	input [7:0]      tx_data       ,

    output           tx_data_done 	
);
 

localparam BPS_CNT=CLK_FREQ/UART_BPS;  
 

(*mark_debug = "true"*)reg tx_flag;              //开始发送数据标志
(*mark_debug = "true"*)reg [31:0]clk_cnt;        //系统时钟计数器
(*mark_debug = "true"*)reg [3:0]tx_cnt;          //发送数据位数计数
(*mark_debug = "true"*)reg [7:0]tx_data_r;
 

reg    tx_flag_dyl   ;




always@(posedge sys_clk )
  begin
    tx_flag_dyl <=  tx_flag ;
  end

assign   tx_data_done  =  tx_flag_dyl & !tx_flag  ;
 

//数据有效信号到来时,开始进入发送模式
always@(posedge sys_clk or negedge sys_rst)begin
	if(!sys_rst)begin
		tx_flag    <=1'b0;
		tx_data_r  <=8'd0;
		end	
	else begin
		if(tx_data_vld)begin
			tx_flag  <=1'b1;   //进入发送模式
			tx_data_r<=tx_data;
			end
		else if((tx_cnt==4'd9)&&(clk_cnt==BPS_CNT-1))begin//计数到停止位中间
			tx_flag<=1'b0;                                
			tx_data_r<=8'd0;
			end
		else begin
			tx_flag<=tx_flag;
			tx_data_r<=tx_data_r;
		end
	end
end
 
//进入发送过程,启动系统计数和发送数据计数
always@(posedge sys_clk or negedge sys_rst)begin
	if(!sys_rst)begin
		clk_cnt<=32'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<=32'd0;     //波特率时钟记满,发送了一位数据
				tx_cnt<=tx_cnt+1'b1;
				end
			end
		else begin              //非发送数据过程,均为0,不启动计数器。
			clk_cnt<=32'd0;
			tx_cnt<=4'd0;
		end
end
 
//发送数据
always@(posedge sys_clk or negedge sys_rst)begin
	if(!sys_rst)
		uart_tx<=1'b1;
	else if(tx_flag)begin
				case(tx_cnt)
				4'd0:uart_tx<=1'b0;
				4'd1:uart_tx<=tx_data_r[0];  //最低位最先发送
				4'd2:uart_tx<=tx_data_r[1];
				4'd3:uart_tx<=tx_data_r[2];
				4'd4:uart_tx<=tx_data_r[3];
				4'd5:uart_tx<=tx_data_r[4];
				4'd6:uart_tx<=tx_data_r[5];
				4'd7:uart_tx<=tx_data_r[6];
				4'd8:uart_tx<=tx_data_r[7];
				4'd9:uart_tx<=1'b1;          //停止位
				default: uart_tx <= 1'b1;
				endcase
			end
	else
			uart_tx<=1'd1;      //空闲状态下发送高电平
end
 
 
endmodule 

UART_RX接收模块:

module uart_recv#(
          parameter  CLK_FREQ = 32'd50_000_000,
		  parameter  UART_BPS = 115200
)(
	input            sys_clk,
	input            sys_rst,
	
	input            uart_rx,
	output wire      rx_data_vld,
	output reg [7:0] rx_data
);
 
//parameter define


localparam BPS_CNT=CLK_FREQ/UART_BPS;  
 
//reg define
reg uart_rx_r0;
reg uart_rx_r1;
reg rx_flag;              //开始接收数据标志
reg [31:0]clk_cnt;        //系统时钟计数器
reg [3:0]rx_cnt;         //接收数据位数计数
//reg [7:0]rx_data;         //接收数据
 
 
//wire define 
wire      start_flag      ;
reg       rx_flag_dly     ;


assign  rx_data_vld = !rx_flag & rx_flag_dly  ;

always@(posedge sys_clk)
begin
  rx_flag_dly <= rx_flag  ;
end

  
 

 
//捕获接收端口下降沿时钟的到来
assign start_flag=(uart_rx_r1)&(~uart_rx_r0);  //下降沿触发
 
always@(posedge sys_clk or negedge sys_rst)begin
	if(!sys_rst)begin
		uart_rx_r0<=1'b0;
		uart_rx_r1<=1'b0;
		end
	else begin
		uart_rx_r0<=uart_rx;     //分别延迟一个时钟,用于检测下降沿
		uart_rx_r1<=uart_rx_r0;
		end
end
 
//start_flag 脉冲信号到来时,设置开始接收数据标志
always@(posedge sys_clk or negedge sys_rst)begin
	if(!sys_rst)
		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)begin
	if(!sys_rst)begin
		clk_cnt<=32'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<=32'd0;     //波特率时钟记满,接收了一位数据
				rx_cnt<=rx_cnt+1'b1;
				end
			end
		else begin              //非接收数据过程,均为0,不启动计数器。
			clk_cnt<=32'd0;
			rx_cnt<=4'd0;
		end
end
 
//寄存器存放接收数据
always@(posedge sys_clk or negedge sys_rst)begin
	if(!sys_rst)
		rx_data<=8'b0;
	else if(rx_flag)begin
			if(clk_cnt==BPS_CNT/2)begin   //中间时刻采样数据最稳定
				case(rx_cnt)
				4'd1:rx_data[0]<=uart_rx_r1;  //最低位最先接收
				4'd2:rx_data[1]<=uart_rx_r1;
				4'd3:rx_data[2]<=uart_rx_r1;
				4'd4:rx_data[3]<=uart_rx_r1;
				4'd5:rx_data[4]<=uart_rx_r1;
				4'd6:rx_data[5]<=uart_rx_r1;
				4'd7:rx_data[6]<=uart_rx_r1;
				4'd8:rx_data[7]<=uart_rx_r1;
				default:;
				endcase
			end
		    else 
				rx_data<=rx_data;  //不是中间时刻不接收采样数据
		end
		else
			rx_data<=rx_data;
end
 
endmodule

顶层模块:

module uart_top(
	input            sys_clk            ,
	input            sys_rst            ,
    input  [7:0]     tx_data            ,
    input            tx_data_vld        ,
	output           tx_data_done       ,
	output [7:0]     rx_data            ,
	output           rx_data_vld        ,
	input            uart_rx            ,            
	output           uart_tx             
);
 
//parameter define
parameter CLK_FREQ=32'd80_000_000;
parameter UART_BPS=115200;
 
//reg define
 
//wire define
wire uart_r_done;       
wire [7:0]uart_data;   
 
 

uart_recv #(
	.CLK_FREQ(CLK_FREQ),   
	.UART_BPS(UART_BPS)
	)
u_uart_recv(
	.sys_clk        (sys_clk    ),
	.sys_rst        (sys_rst    ),
	.rx_data_vld    (rx_data_vld),    
	.rx_data        (rx_data    ),    
	.uart_rx        (uart_rx    )       
);
 

uart_send #(
	.CLK_FREQ(CLK_FREQ),      
	.UART_BPS(UART_BPS)
	)
u_uart_send(
	.sys_clk       (sys_clk    ),
	.sys_rst       (sys_rst    ),
	.tx_data_vld   (tx_data_vld),
	.tx_data       (tx_data    ),
	.tx_data_done  (tx_data_done),
	.uart_tx       (uart_tx     )       
);
 
endmodule

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值