串口接收数据:
`timescale 1ns / 1ns
module MyUart(
input clk,
input rst,
input rx,
output led,
output start_,
output [3:0] bitcnt_,
output reg2_,
output wire [9:0] buffer_
);
reg reg1;
reg reg2;
reg start;
reg [15:0] baudcnt;
reg [3:0] bitcnt;
reg [9:0] buffer;
always @(posedge clk or negedge rst) begin
if(!rst) begin
reg1 <= 1'b1;
reg2 <= 1'b1; //空闲态
end
else begin
reg1 <= rx;
reg2 <= reg1;
end
end
always @(posedge clk or negedge rst) begin
if(!rst)
start <= 0;
else if((reg2 == 1'b1) && (reg1 == 1'b0))
start <= 1'b1; //检测到下降沿,标志着开始计数
//如果结束条件一时半会儿不知道怎么写就先放着,先把其他的信号完善好
else if((bitcnt == 10) && (baudcnt == 5207)) //接收10个bit
start <= 0;
else start <= start; //防止latch
end
//波特率计数
always @(posedge clk or negedge rst) begin
if(!rst) begin
baudcnt <= 0;
end
else if(start) begin //start信号有效时
if(baudcnt < 5207)
baudcnt <= baudcnt + 1;
else
baudcnt <= 0; //溢出清零
end
else baudcnt <= 0; //start无效时直接清零
end
//比特计数
always@(posedge clk or negedge rst) begin
if(!rst)
bitcnt <= 0;
else if(start) begin
if(baudcnt == 5208/2 - 1) //判断条件不能写等于0,否则会少接收一位bit
bitcnt <= bitcnt + 1;
else bitcnt <= bitcnt;
end
else bitcnt <= 0;
end
//接收数据
always @(posedge clk or negedge rst) begin
if(!rst)
buffer <= 0;
else if(start) begin
if(baudcnt == 5208 / 2 - 1) begin //如果start有效并且波特率计数到中间位置时
case(bitcnt)
0: buffer[0] <= reg2;
1: buffer[1] <= reg2;
2: buffer[2] <= reg2;
3: buffer[3] <= reg2;
4: buffer[4] <= reg2;
5: buffer[5] <= reg2;
6: buffer[6] <= reg2;
7: buffer[7] <= reg2;
8: buffer[8] <= reg2;
9: buffer[9] <= reg2;
endcase
end
end
end
assign led = buffer[1] && buffer[8];
assign start_ = start;
assign bitcnt_ = bitcnt;
assign reg2_ = reg2;
assign buffer_ = buffer;
endmodule
modelsim:
`timescale 1ns / 1ns
module MyUart_tb;
// Inputs
reg clk;
reg rst;
reg rx;
// Outputs
wire led;
wire start_;
wire [3:0] bitcnt_;
wire reg2_;
wire [9:0] buffer_;
// Instantiate the Unit Under Test (UUT)
MyUart uut (
.clk(clk),
.rst(rst),
.rx(rx),
.led(led),
.start_(start_),
.bitcnt_(bitcnt_),
.reg2_(reg2_),
.buffer_(buffer_)
);
initial begin
// Initialize Inputs
clk = 0;
rst = 0;
rx = 1;
// Wait 100 ns for global reset to finish
#100;
rst = 1;
#500000;
rx = 0; //起始位
#(5208*20*2);
rx = 1;
#(5208*20*2);
rx = 1;
#(5208*20*2);
rx = 1;
#(5208*20*2);
rx = 0;
#(5208*20*2);
rx = 1;
#(5208*20*2);
rx = 0;
#(5208*20*2);
rx = 1;
#(5208*20*2);
rx = 1;
#(5208*20*2);
rx = 1; //停止位
#(5208*20*2);
// Add stimulus here
#15_000000; //15ms
$stop;
end
always #20 clk<=~clk;
endmodule
modelsim:
接收的基本思路就是:
在数据来的时候检测下降沿,并且拉高start信号,再进行波特率计数,溢出时累加接收到的比特数,在计数到波特率中间位置时去读取rx的值(也就是reg2),将包括起始位、停止位的字节数据存放到buffer里面去。
串口发送:
`timescale 1ns / 1ns
module TX(
input clk ,
input rst ,
output reg tx ,
output wire start_ ,
output wire [3:0] bitcnt_
);
reg [31:0] cnt;
reg start;
reg [15:0] baudcnt;
reg [3:0] bitcnt;
reg [9:0] buffer = 10'b1_0000_1100_0; //0x0c
assign start_ = start;
assign bitcnt_ = bitcnt;
//1s倒计时
always @(posedge clk or negedge rst) begin
if(!rst) begin
cnt <= 1'b0;
end
else if(cnt < 50_000_000)
cnt <= cnt + 1;
else if(cnt == 50_000_000) begin
cnt <= 0;
end
end
//延时
always @(posedge clk or negedge rst) begin
if(!rst)
start <= 1'b0;
else if(cnt == 5207*10)
start <= 1'b0;
else if(!cnt)
start <= 1'b1;
end
//波特率计数
always@(posedge clk or negedge rst) begin
if(!rst)
baudcnt <= 0;
else if(start) begin
if(baudcnt < 5207)
baudcnt <= baudcnt + 1;
else if(baudcnt == 5207) begin
baudcnt <= 0;
bitcnt <= bitcnt + 1;
end
else if(bitcnt == 10)
bitcnt <= 0;
end
else begin
baudcnt <= 0;
bitcnt <= 0;
end
end
always @(posedge clk or negedge rst) begin
if(!rst)
buffer <= buffer;
else if(start) begin
if((baudcnt == 0) || (baudcnt == 1)) begin
case(bitcnt)
0: tx <= buffer[0];
1: tx <= buffer[1];
2: tx <= buffer[2];
3: tx <= buffer[3];
4: tx <= buffer[4];
5: tx <= buffer[5];
6: tx <= buffer[6];
7: tx <= buffer[7];
8: tx <= buffer[8];
9: tx <= buffer[9];
endcase
end
end
end
endmodule
完整串口回环测试工程:https://download.csdn.net/download/qq_45955402/87859087