串口接收
串口帧
设计文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/01/12 23:11:28
// Design Name:
// Module Name: UART_Byte_Rx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module UART_Byte_Rx
#(
parameter BaudRate = 115200,//波特率
parameter ClockRate = 50_000_000//系统时钟
)
(
Clk,
Rst_n,
Rx,
Rx_Data,
Rx_Done
);
input Clk;
input Rst_n;
input Rx;
output reg [7:0] Rx_Data;
output Rx_Done;
//设置波特率 将一bit时间分成16份,在每一份的中间进行采样
localparam Buad_Num = ClockRate/BaudRate/16;
//检测下降沿
reg [2:0] neg_edge_r;
wire neg_edge_flag;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
neg_edge_r<=3'b0;
else
neg_edge_r<={neg_edge_r[1:0],Rx};
end
assign neg_edge_flag=neg_edge_r[2:1]==2'b10;
//接收使能信号
reg rx_en;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
rx_en<=0;
else if(neg_edge_flag)
rx_en<=1'd1;
else if(Rx_Done)
rx_en<=1'd0;
else
rx_en<=rx_en;
end
//波特率计数
reg [12:0] buad_cnt;
wire add_buad_cnt;
wire end_buad_cnt;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
buad_cnt<=0;
else if(add_buad_cnt)begin
if(end_buad_cnt)
buad_cnt<=0;
else
buad_cnt<=buad_cnt+1'b1;
end
else
buad_cnt<=0;
end
assign add_buad_cnt=rx_en;
assign end_buad_cnt=buad_cnt>=(Buad_Num-1'd1);
//采样点
wire buad_cnt_middle=buad_cnt==(Buad_Num/2);
//计数采样次数 16*10
reg [7:0] sampling_cnt;
wire add_sampling_cnt;
wire end_sampling_cnt;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
sampling_cnt<=0;
else if(rx_en)begin
if(add_sampling_cnt)begin
if(end_sampling_cnt)
sampling_cnt<=0;
else
sampling_cnt<=sampling_cnt+1'b1;
end
end
else
sampling_cnt<=0;
end
assign add_sampling_cnt=buad_cnt_middle;
assign end_sampling_cnt=add_sampling_cnt && sampling_cnt>=159;
//设置存储数据的寄存器
//8个寄存器,每个寄存器的位宽是3(原因是:16次采集,我们选择中间的7次采集,进行相加,结果大于4[100]的,认为是高电平)
reg [2:0]rx_data_r[7:0];
reg [2:0]sta_bit;//起始位
reg [2:0]sto_bit;//停止位
//0 【0】 1 【1】 2 【2】 3 【3】 4 【4】 5 【5】 6 【6】 7 【7】 8 【8】 9 【9】 10 【10】
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
rx_data_r[0]<=0;
rx_data_r[1]<=0;
rx_data_r[2]<=0;
rx_data_r[3]<=0;
rx_data_r[4]<=0;
rx_data_r[5]<=0;
rx_data_r[6]<=0;
rx_data_r[7]<=0;
sta_bit<=0;
sto_bit<=0;
end
else if(buad_cnt_middle)begin
case(sampling_cnt)
0:begin//清0所有寄存器
rx_data_r[0]<=0;
rx_data_r[1]<=0;
rx_data_r[2]<=0;
rx_data_r[3]<=0;
rx_data_r[4]<=0;
rx_data_r[5]<=0;
rx_data_r[6]<=0;
rx_data_r[7]<=0;
sta_bit<=0;
sto_bit<=0;
end
5,6,7,8,9,10,11: sta_bit <= sta_bit + Rx;
21,22,23,24,25,26,27: rx_data_r[0] <= rx_data_r[0] + Rx;
37,38,39,40,41,42,43: rx_data_r[1] <= rx_data_r[1] + Rx;
53,54,55,56,57,58,59: rx_data_r[2] <= rx_data_r[2] + Rx;
69,70,71,72,73,74,75: rx_data_r[3] <= rx_data_r[3] + Rx;
85,86,87,88,89,90,91: rx_data_r[4] <= rx_data_r[4] + Rx;
101,102,103,104,105,106,107: rx_data_r[5] <= rx_data_r[5] + Rx;
117,118,119,120,121,122,123: rx_data_r[6] <= rx_data_r[6] + Rx;
133,134,135,136,137,138,139: rx_data_r[7] <= rx_data_r[7] + Rx;
149,150,151,152,153,154,155: sto_bit <= sto_bit + Rx;
default:;
endcase
end
end
//将读取的数据反馈回来 4=3'b100
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
Rx_Data<=0;
else if(sampling_cnt==159)begin
Rx_Data[0]<=(rx_data_r[0][2]);
Rx_Data[1]<=(rx_data_r[1][2]);
Rx_Data[2]<=(rx_data_r[2][2]);
Rx_Data[3]<=(rx_data_r[3][2]);
Rx_Data[4]<=(rx_data_r[4][2]);
Rx_Data[5]<=(rx_data_r[5][2]);
Rx_Data[6]<=(rx_data_r[6][2]);
Rx_Data[7]<=(rx_data_r[7][2]);
end
end
assign Rx_Done=end_sampling_cnt;
endmodule
仿真验证
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/01/12 23:13:05
// Design Name:
// Module Name: UART_Byte_Rx_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module UART_Byte_Rx_tb();
reg Clk;
reg Rst_n;
reg Rx;
wire [7:0] Rx_Data;
wire Rx_Done;
UART_Byte_Rx UART_Byte_Rx
(
Clk,
Rst_n,
Rx,
Rx_Data,
Rx_Done
);
initial Clk=1;
always #10 Clk=~Clk;
initial begin
Rst_n=0;
Rx=1;
#201
Rst_n=1;
#200;
uart_tx_byte(8'h5a);
#9000;
uart_tx_byte(8'h88);
#9000;
uart_tx_byte(8'h11);
#9000;
$stop;
end
task uart_tx_byte;
input [7:0]tx_data;
begin
Rx=1;
#20;
Rx=0;
#8680;
Rx=tx_data[0];
#8680;
Rx=tx_data[1];
#8680;
Rx=tx_data[2];
#8680;
Rx=tx_data[3];
#8680;
Rx=tx_data[4];
#8680;
Rx=tx_data[5];
#8680;
Rx=tx_data[6];
#8680;
Rx=tx_data[7];
#8680;
Rx=1;
#8680;
end
endtask
endmodule
串口发送
**注意:**电平信号的传输线中有一个参考电平线(一般是GND),然后信号线上的信号值是由信号线电平和参考电平线的电压差决定。所以我们一定要养成模块之间共地的好习惯。
串口帧
模块设计
设计文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/01/06 11:30:58
// Design Name:
// Module Name: UART_Byte_Tx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module UART_Byte_Tx
#(
parameter BaudRate = 115200,//波特率
parameter ClockRate = 50_000_000//系统时钟
)
(
Clk,
Rst_n,
Send_En,
data_byte,
Tx_Data,
Tx_Done,
uart_state
);
input Clk;
input Rst_n;
input Send_En;
input [7:0] data_byte;
output reg Tx_Data;
output reg Tx_Done;
output reg uart_state;
//设置使能
reg tx_en;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
tx_en<=0;
else if(Send_En)
tx_en<=1'd1;
else if(Tx_Done)
tx_en<=1'd0;
else
tx_en<=tx_en;
end
//设置波特率
localparam Buad_Num = ClockRate/BaudRate;
//设置计数器
reg [12:0] buad_cnt;
wire add_buad_cnt;
wire end_buad_cnt;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
buad_cnt<=0;
else if(add_buad_cnt)begin
if(end_buad_cnt)
buad_cnt<=0;
else
buad_cnt<=buad_cnt+1'b1;
end
else
buad_cnt<=0;
end
assign add_buad_cnt=tx_en;
assign end_buad_cnt=buad_cnt>=(Buad_Num-1'd1);
//设置发送bit计数
reg [3:0] bit_cnt;
wire add_bit_cnt;
wire end_bit_cnt;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
bit_cnt<=0;
else if(add_bit_cnt)
bit_cnt<=bit_cnt+1'd1;
else if(end_bit_cnt)
bit_cnt<=0;
else
bit_cnt<=bit_cnt;
end
assign add_bit_cnt=buad_cnt==1;
assign end_bit_cnt=(bit_cnt==4'd10 && add_bit_cnt) || !tx_en;
//发送数据
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
Tx_Data<=1;
else begin
case(bit_cnt)
4'd1:Tx_Data<=0;
4'd2:Tx_Data<=data_byte[0];
4'd3:Tx_Data<=data_byte[1];
4'd4:Tx_Data<=data_byte[2];
4'd5:Tx_Data<=data_byte[3];
4'd6:Tx_Data<=data_byte[4];
4'd7:Tx_Data<=data_byte[5];
4'd8:Tx_Data<=data_byte[6];
4'd9:Tx_Data<=data_byte[7];
4'd10:Tx_Data<=1;
default:Tx_Data<=1;
endcase
end
end
//发送结束
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
Tx_Done<=0;
else if(bit_cnt==4'd10 && add_bit_cnt)
Tx_Done<=1;
else
Tx_Done<=0;
end
//发送状态(有效数据)
wire En_uart_state;
wire Nen_uart_state;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
uart_state<=0;
else if(En_uart_state)
uart_state<=1;
else if(Nen_uart_state)
uart_state<=0;
end
assign En_uart_state=bit_cnt==4'd1 && add_bit_cnt;
assign Nen_uart_state=bit_cnt==4'd9 && add_bit_cnt;
endmodule
仿真验证
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/01/06 11:31:09
// Design Name:
// Module Name: UART_Byte_Tx_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module UART_Byte_Tx_tb();
reg Clk;
reg Rst_n;
reg Send_En;
reg [7:0]data_byte;
wire Tx_Data;
wire Tx_Done;
wire uart_state;
initial Clk=1;
always #10 Clk=~Clk;
initial begin
Rst_n=0;
Send_En=0;
data_byte=0;
#201;
Rst_n=1;
data_byte=8'b1001_0110;
Send_En=1;
#20;
Send_En=0;
#100000;
data_byte=8'b0111_0110;
Send_En=1;
#20;
Send_En=0;
#100000;
$stop;
end
UART_Byte_Tx UART_Byte_Tx(
.Clk(Clk),
.Rst_n(Rst_n),
.Send_En(Send_En),
.data_byte(data_byte),
.Tx_Data(Tx_Data),
.Tx_Done(Tx_Done),
.uart_state(uart_state)
);
endmodule
串口接收-串口发送
基于串口的数据收、发模块,使用收、发模块,完成串口数据回环实验。
RTL视图
设计文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/01/12 23:49:51
// Design Name:
// Module Name: UART_Data_Loopback_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module UART_Data_Loopback_top(
Clk,
Rst_n,
Rx,
Tx_Data
);
input Clk;
input Rst_n;
input Rx;
output Tx_Data;
//串口接收
wire [7:0] Rx_Data;
wire Rx_Done;
UART_Byte_Rx
#(
115200,
50_000_000
)
UART_Byte_Rx
(
.Clk(Clk),
.Rst_n(Rst_n),
.Rx(Rx),
.Rx_Data(Rx_Data),
.Rx_Done(Rx_Done)
);
//串口发送
wire Tx_Done;
wire uart_state;
UART_Byte_Tx
#(
115200,
50_000_000
)
UART_Byte_Tx(
.Clk(Clk),
.Rst_n(Rst_n),
.Send_En(Rx_Done),
.data_byte(Rx_Data),
.Tx_Data(Tx_Data),
.Tx_Done(Tx_Done),
.uart_state(uart_state)
);
endmodule
约束文件
set_property PACKAGE_PIN Y18 [get_ports Clk]
set_property PACKAGE_PIN A21 [get_ports Rst_n]
set_property PACKAGE_PIN M15 [get_ports Tx_Data]
set_property IOSTANDARD LVCMOS33 [get_ports Clk]
set_property IOSTANDARD LVCMOS33 [get_ports Rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports Tx_Data]
set_property PACKAGE_PIN J21 [get_ports Rx]
set_property IOSTANDARD LVCMOS33 [get_ports Rx]
板级验证
任意字节发送
设计文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/01/13 10:16:15
// Design Name:
// Module Name: UART_Bytes_Tx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module UART_Bytes_Tx
#(
parameter BaudRate = 115200,//波特率
parameter ClockRate = 50_000_000,//系统时钟
parameter BytesNum=5//发送字节个数
)
(
Clk,
Rst_n,
Trans_Go,
data_bytes,
Tx_Data,
Trans_Done,
uart_state
);
localparam Bit_Wide = BytesNum * 8;
input Clk;
input Rst_n;
input Trans_Go;
input [Bit_Wide-1:0] data_bytes;
output Tx_Data;
output reg Trans_Done;
output uart_state;
//发送使能
reg Trans_en;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
Trans_en<=0;
else if(Trans_Go)
Trans_en<=1;
else if(Trans_Done)
Trans_en<=0;
else
Trans_en<=Trans_en;
end
//计数已经发送的字节数
reg [5:0] send_byte_num;//最多可发送63字节,想要发送更多字节,需要调大位宽
wire add_send_byte_num;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
send_byte_num<=0;
else if(Trans_en) begin
if(add_send_byte_num)
send_byte_num<=send_byte_num+1'b1;
else
send_byte_num<=send_byte_num;
end
else
send_byte_num<=0;
end
assign add_send_byte_num=Tx_Done;
//将传输的值寄存到寄存器中,每发送一个字节进行移位
reg [Bit_Wide-1:0] data_bytes_r;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
data_bytes_r<=0;
else if(Trans_Go)
data_bytes_r<=data_bytes;
else if(Tx_Done)
data_bytes_r<=data_bytes_r>>8;
else
data_bytes_r<=data_bytes_r;
end
//将多字节数据分成一字节发送,使用发送结束标志位来启动下一次发送
reg [7:0] data_byte_temp;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
data_byte_temp<=0;
else
data_byte_temp<=data_bytes_r;
end
//串口单字节发送
wire Tx_Done;
wire uart_state;
reg Send_En;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
Send_En<=0;
else if( ( Trans_Go || Tx_Done ) && !(send_byte_num>=BytesNum-1 && add_send_byte_num) )
Send_En<=1;
else
Send_En<=0;
end
UART_Byte_Tx
#(
115200,
50_000_000
)
UART_Byte_Tx(
.Clk(Clk),
.Rst_n(Rst_n),
.Send_En(Send_En),
.data_byte(data_byte_temp),
.Tx_Data(Tx_Data),
.Tx_Done(Tx_Done),
.uart_state(uart_state)
);
//全部字节发送标志位
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
Trans_Done<=0;
else if(send_byte_num>=BytesNum-1 && add_send_byte_num)
Trans_Done<=1;
else
Trans_Done<=0;
end
endmodule
仿真验证
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/01/13 10:24:58
// Design Name:
// Module Name: UART_Bytes_Tx_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module UART_Bytes_Tx_tb();
reg Clk;
reg Rst_n;
reg Trans_Go;
reg [39:0]data_bytes;
wire Tx_Data;
wire Trans_Done;
wire uart_state;
initial Clk=1;
always #10 Clk=~Clk;
initial begin
Rst_n=0;
Trans_Go=0;
data_bytes=0;
#201;
Rst_n=1;
data_bytes=40'h123456789a;
Trans_Go=1;
#20;
Trans_Go=0;
@(posedge Trans_Done);
#200000
data_bytes=40'ha987654321;
Trans_Go=1;
#20;
Trans_Go=0;
@(posedge Trans_Done);
#200000
data_bytes=40'habcdef4321;
Trans_Go=1;
#20;
Trans_Go=0;
@(posedge Trans_Done);
#200000
$stop;
end
UART_Bytes_Tx
#(
.BytesNum(5)
)
UART_Bytes_Tx(
.Clk(Clk),
.Rst_n(Rst_n),
.Trans_Go(Trans_Go),
.data_bytes(data_bytes),
.Tx_Data(Tx_Data),
.Trans_Done(Trans_Done),
.uart_state(uart_state)
);
endmodule
按键发送多字节
发送AMH\r\n
RTL视图
设计文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/01/13 15:09:15
// Design Name:
// Module Name: UART_Bytes_Tx_test
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module UART_Bytes_Tx_test(
Clk,
Rst_n,
Key_in,
Tx_Data
);
input Clk;
input Rst_n;
input Key_in;
output Tx_Data;
//按键输入
wire Key_flag;
wire Key_State;
key_filter key_filter(
.Clk(Clk),
.Rst_n(Rst_n),
.Key_in(Key_in),
.Key_flag(Key_flag), //按键按下标志位
.Key_State(Key_State) //高电平,按键按下
);
//任意字节发送
wire [39:0] data_bytes;
assign data_bytes=40'h0A0D484D41;// AMH/r/n
wire Trans_Done;
wire uart_state;
UART_Bytes_Tx
#(
.BytesNum(5)
)
UART_Bytes_Tx(
.Clk(Clk),
.Rst_n(Rst_n),
.Trans_Go(Key_flag),
.data_bytes(data_bytes),
.Tx_Data(Tx_Data),
.Trans_Done(Trans_Done),
.uart_state(uart_state)
);
endmodule
约束文件
set_property PACKAGE_PIN Y18 [get_ports Clk]
set_property PACKAGE_PIN A21 [get_ports Rst_n]
set_property PACKAGE_PIN M15 [get_ports Tx_Data]
set_property IOSTANDARD LVCMOS33 [get_ports Clk]
set_property IOSTANDARD LVCMOS33 [get_ports Rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports Tx_Data]
set_property PACKAGE_PIN B21 [get_ports Key_in]
set_property IOSTANDARD LVCMOS33 [get_ports Key_in]