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