串口RS232发送、接收模块的Verilog实现与仿真

TOP模块:

module RS232(
	input wire clk,
	input wire rst_n,
	input wire rx,
	output wire tx
);
parameter UART_BPS = 20'd115200;       //波特率
parameter CLK_FREQ = 26'd50_000_000;  //时钟频率

wire  [7:0] data;
wire  	  flag;

uart_rx 
#(
	.UART_BPS(UART_BPS),
	.CLK_FREQ(CLK_FREQ)
)
uart_rx_inst
(
	.clk(clk),
	.rst_n(rst_n),
	.rx(rx),
	
	.po_data(data),
	.po_flag(flag)
);

uart_tx
#(
	.UART_BPS(UART_BPS),
	.CLK_FREQ(CLK_FREQ)
)
uart_tx_inst
(
	.clk(clk),
	.rst_n(rst_n),
	.pi_data(data),
	.pi_flag(flag),
	
	.tx(tx)
	
);

endmodule

TOP仿真模块:

`timescale 1ns/1ns
module tb_RS232();
reg clk;
reg rst_n;
reg rx;
wire tx;

initial begin
	clk = 1'b1;
	rst_n = 1'b0;
	rx = 1'b1;
	#15;
	rst_n = 1'b1;
end

always #10 clk=~clk;

initial begin
	#200;
	rx_byte(); //调用任务rx_byte
end

task rx_byte();
	integer j;
	for(j=0;j<8;j=j+1)
		rx_bit(j);  //调用8次rx_bit任务,分别发送0-7
endtask

task rx_bit(
	input [7:0] data
);
	integer i;
	for(i=0;i<10;i=i+1)begin
		case(i)
			'd0: rx=1'b0;	//发送起始位
			'd1: rx=data[0];
			'd2: rx=data[1];
			'd3: rx=data[2];
			'd4: rx=data[3];
			'd5: rx=data[4];
			'd6: rx=data[5];
			'd7: rx=data[6];
			'd8: rx=data[7];
			'd9: rx=1'b1;	//发送停止位
			default rx=1'b1;
		endcase
	    #(5208*20);
	end
endtask

RS232 RS232_inst
(
	.clk(clk),
	.rst_n(rst_n),
	.rx(rx),
	
	.tx(tx)
);


endmodule

发送模块:

module  uart_tx	//串口发送模块
#(
    parameter   UART_BPS    =   'd9600,         //串口波特率
    parameter   CLK_FREQ    =   'd50_000_000    //时钟频率
)
(
     input   wire            clk     ,   //系统时钟50MHz
     input   wire            rst_n   ,   //全局复位
     input   wire    [7:0]   pi_data     ,   //模块输入的8bit数据
     input   wire            pi_flag     ,   //并行数据有效标志信号
 
     output  reg             tx              //串转并后的1bit数据
);

reg work_en;
reg bit_flag;

//计数器--baud_cnt
reg [31:0] baud_cnt          ;  //计数器位宽
wire	   add_baud_cnt      ;  //计数器开始条件
wire	   end_baud_cnt      ;  //计数器结束条件
parameter  MAX_1 = CLK_FREQ/UART_BPS    ;  //计数的最大值

//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge clk or negedge rst_n)
        if(rst_n == 1'b0)
            baud_cnt <= 13'b0;
        else    if((baud_cnt == MAX_1 - 1) || (work_en == 1'b0))
            baud_cnt <= 13'b0;
        else    if(work_en == 1'b1)
            baud_cnt <= baud_cnt + 1'b1;

always@(posedge clk or negedge rst_n)begin 
	if(!rst_n)
		bit_flag <= 1'b0;
	else if(baud_cnt=='d1)	
		bit_flag <= 1'b1;	//当baud_cnt计数到一半时产生一个标志位????????
	else
		bit_flag <= 1'b0;
end

//计数器--bit_cnt
reg [3:0] bit_cnt          ;  //计数器位宽
wire	   add_bit_cnt      ;  //计数器开始条件
wire	   end_bit_cnt      ;  //计数器结束条件
parameter  MAX_2 = 'd10    ;  //计数的最大值

always@(posedge clk or negedge rst_n)
    if(rst_n == 1'b0)
        bit_cnt <= 4'b0;
    else    if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
        bit_cnt <= 4'b0;
    else    if((bit_flag == 1'b1) && (work_en == 1'b1))
        bit_cnt <= bit_cnt + 1'b1;

//产生使能信号
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		work_en <= 1'b0;
	else if(pi_flag)
		work_en <= 1'b1;		//输入信号有效时拉高
	else if(bit_flag==1 && bit_cnt=='d9)
		work_en <= 1'b0;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		tx <= 1'b1;	//空闲时为高电平
	else if(bit_flag==1)begin
		case(bit_cnt)
			'd0: tx <= 1'b0;		//起始位
			'd1: tx <= pi_data[0];
			'd2: tx <= pi_data[1];
			'd3: tx <= pi_data[2];
			'd4: tx <= pi_data[3];
			'd5: tx <= pi_data[4];
			'd6: tx <= pi_data[5];
			'd7: tx <= pi_data[6];
			'd8: tx <= pi_data[7];
			'd9: tx <= 1'b1;		//停止位
			default tx<=1'b1;
		endcase
	end	
end

endmodule

发送仿真模块:

`timescale 1ns/1ns
module tb_uart_tx();  //串口发送模块测试代码

reg clk;
reg rst_n;
reg [7:0] pi_data;
reg pi_flag;

wire tx;

initial begin
	clk = 1'b1;
	rst_n = 1'b0;
	#15;
	rst_n = 1'b1;
end

always #10 clk = !clk;

initial begin
	pi_data = 8'b0;
	pi_data = 1'b0;
	#200;
	//发送数据0
	pi_data = 8'd0;
	pi_flag = 1'b1;
	#20;
	pi_flag = 1'b0;
//每发送1bit数据需要5208个时钟周期,一帧数据为10bit
//所以5208*20*10后才发送下一数据
	#(5208*20*10);
	//发送数据1
	pi_data = 8'd1;
	pi_flag = 1'b1;
	#20;
	pi_flag = 1'b0;
	
	#(5208*20*10);
	//发送数据2
	pi_data = 8'd2;
	pi_flag = 1'b1;
	#20;
	pi_flag = 1'b0;
	
	#(5208*20*10);
	//发送数据3
	pi_data = 8'd3;
	pi_flag = 1'b1;
	#20;
	pi_flag = 1'b0;
	
	#(5208*20*10);
	//发送数据4
	pi_data = 8'd4;
	pi_flag = 1'b1;
	#20;
	pi_flag = 1'b0;
	
	#(5208*20*10);
	//发送数据5
	pi_data = 8'd5;
	pi_flag = 1'b1;
	#20;
	pi_flag = 1'b0;
	
	#(5208*20*10);
	//发送数据6
	pi_data = 8'd6;
	pi_flag = 1'b1;
	#20;
	pi_flag = 1'b0;
	
	#(5208*20*10);
	//发送数据7
	pi_data = 8'd7;
	pi_flag = 1'b1;
	#20;
	pi_flag = 1'b0;
	
end
uart_tx  uart_tx_inst(
	.clk(clk),
	.rst_n(rst_n),
	.pi_data(pi_data),
	.pi_flag(pi_flag),
	
	.tx(tx)
);
endmodule

接收模块:

module uart_rx	//串口接收模块
#(
	parameter UART_BPS = 'd9600,		//串口波特率
	parameter CLK_FREQ = 'd50_000_000	//时钟频率
 )
 (
	input wire clk,
	input wire rst_n,
	input wire rx,				//串行输入
	output reg [7:0] po_data,	//并行输出--
	output reg 		 po_flag	//输出有效标志
 );
reg rx_reg1;
reg rx_reg2;
reg rx_reg3;		//输入信号寄存器
reg [7:0] rx_data;
reg start_nedge;	//开始信号标志、1有效
reg rx_flag;
reg work_en;

reg [31:0] cnt_1          ;  //计数器位宽
wire	   add_cnt_1      ;  //计数器开始条件
wire	   end_cnt_1      ;  //计数器结束条件
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ; //波特率计数器
localparam MAX_1 = BAUD_CNT_MAX   ;  //计数的最大值

//计数器--cnt_1
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt_1 <= 0;
	end
	else if(add_cnt_1)begin
		if(end_cnt_1)
			cnt_1 <= 0;
		else
			cnt_1 <= cnt_1 + 1;
	end
	else
		cnt_1 <= cnt_1;
end
assign add_cnt_1 = (work_en==1) ? 1: 0;
assign end_cnt_1 = (add_cnt_1 && (cnt_1==MAX_1-1));

always@(posedge clk or negedge rst_n)begin	//输入信号打第一拍
	if(!rst_n)
		rx_reg1 <= 1'b1;
	else
		rx_reg1 <= rx;
end
always@(posedge clk or negedge rst_n)begin	//输入信号打第二拍
	if(!rst_n)
		rx_reg2 <= 1'b1;
	else
		rx_reg2 <= rx_reg1;
end
always@(posedge clk or negedge rst_n)begin	//输入信号打第三拍
	if(!rst_n)
		rx_reg3 <= 1'b1;
	else
		rx_reg3 <= rx_reg2;
end

always@(posedge clk or negedge rst_n)begin //检测下降沿、也就是起始位
	if(!rst_n)
		start_nedge <= 1'b0;
	else if((!rx_reg2)&&(rx_reg3))
		start_nedge <= 1'b1;
	else
		start_nedge <= 1'b0;
end

//计数器--cnt_2				 //计数到8
reg [3:0] cnt_2          ;  //计数器位宽
wire	   add_cnt_2      ;  //计数器开始条件
wire	   end_cnt_2      ;  //计数器结束条件
parameter  MAX_2 = 'd9    ;  //计数的最大值

always@(posedge clk or negedge rst_n)begin	//当8个数据位接收完成后清零
	if(!rst_n)begin
		cnt_2 <= 0;
	end
	else if(add_cnt_2)begin
		if(end_cnt_2)
			cnt_2 <= 0;
		else
			cnt_2 <= cnt_2 + 1;
	end
	else
		cnt_2 <= cnt_2;
end
assign add_cnt_2 = (end_cnt_1) ? 1 : 0;   //cnt_1计数满时,cnt_2开始计数
assign end_cnt_2 = (add_cnt_2 && (cnt_2==MAX_2-1));

always@(posedge clk or negedge rst_n)begin	//当cnt_1计数到一半时,开始采样
	if(!rst_n)
		rx_data <= 8'd0;
	else if((cnt_1==(MAX_1/2-1)) && (cnt_2>='d1) && (cnt_2<='d8))
		rx_data <= {rx_reg3,rx_data[7:1]}; //移位输入
	/* else
		rx_data <= 8'd0; */
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		work_en <= 1'b0;
	else if(start_nedge)	//开始接收信号时使能信号拉高
		work_en <= 1'b1;
	else if(end_cnt_2)		//当8个数据位接收完成后使能信号拉低
		work_en <= 1'b0;
	/* else 
		work_en <= 1'b0; */
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		rx_flag <= 1'b0;
	else if((cnt_2=='d8) && (end_cnt_1)) //接收完成后拉高一个标志信号
		rx_flag <= 1'b1;
	else
		rx_flag <= 1'b0;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		po_data <= 8'd0;
	else if(rx_flag)
		po_data <= rx_data;//赋给输出
/* 	else
		po_data <= 8'd0; */
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		po_flag <= 0;
	else
		po_flag <= rx_flag;  //接收完成标志位输出
end

endmodule

 接收仿真模块:

`timescale 1ns/1ns
module tb_uart_rx(); //串口接收模块测试文件

reg clk;
reg rst_n;
reg rx;

wire [7:0] po_data;
wire 	   po_flag;

initial begin
	clk = 1;
	rst_n = 0;
	rx = 1;
	#15;
	rst_n = 1;
end
always #10 clk = ~clk;

//模拟发送8次数据,分别为0-7
initial begin
	#200
	rx_bit(8'd0); //调用任务
	rx_bit(8'd1);
	rx_bit(8'd2);
	rx_bit(8'd3);
	rx_bit(8'd4);
	rx_bit(8'd5);
	rx_bit(8'd6);
	rx_bit(8'd7);
end

//定义一个叫rx_bit的任务,每次发送10位数据
task rx_bit(
	input [7:0] data
);
	integer i; 
	for(i=0;i<10;i=i+1)begin
		case(i)
			0:  rx <= 1'b0;
			1:	rx <= data[0];
			2:	rx <= data[1];
			3:	rx <= data[2];
			4:	rx <= data[3];
			5:	rx <= data[4];
			6:	rx <= data[5];
			7:	rx <= data[6];
			8:	rx <= data[7];
			9:	rx <= 1'b1;
		endcase
		#(5208*20);//每发送一位数据延时5208个时钟周期
	end
endtask

uart_rx uart_rx_inst(
	.clk(clk),
	.rst_n(rst_n),
	.rx(rx),
	
	.po_data(po_data),
	.po_flag(po_flag)
);

endmodule

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值