以下代码可实现基于UART串口通信协议的数据收发,包含top模块,UART_RX,UART_TX三个模块。具体的功能实现请查看代码注释
TOP模块:输入输出端口包含基本的时钟信号与复位信号,以及用于UART的RXD与TXD,收发信号有LED灯展现
module top
(
input wire clk ,
input wire rst ,
output wire tx ,
input wire rx ,
output reg [7:0] led
);
wire [7:0] tx_data ;//发送的数据
wire done ;//使能信号
//UART_TX主要包含三个变量:tx_data发送的数据;ready:完成标志;tx_data_vld:使能信号
uart_tx inst_tx(
.clk (clk) ,
.rst (rst) ,
.tx_data (tx_data) ,
.tx_data_vld (done) ,
.ready (1'b1) ,
.tx (tx)
);
//UART_RX主要包含两个变量:rx_data接收的数据;tx_data_vld:完成标志
uart_rx inst_rx(
.clk (clk) ,
.rst (rst) ,
.rx (rx) ,
.rx_data_vld (done) ,
.rx_data (tx_data)
);
always @(posedge clk or posedge rst) begin
if(rst) begin
led <= 8'b1111_1111;
end else begin
if(done)
led <= tx_data;
else
led <= led;
end
end
endmodule
UART_RX模块:用于接收数据
module uart_rx(
input clk,
input rst,
input rx,
output rx_data_vld,
output [7:0] rx_data
);
parameter MAX_BPS = 115200;
parameter CLOCK = 50_000_000;
parameter MAX_1bit = CLOCK/MAX_BPS;
parameter CHECK_BIT = "None";//无校验位
//定义状态机
localparam IDLE = 'b0001,
START = 'b0010,
DATA = 'b0100,
CHECK = 'b1000;
reg [3:0] cstate ;
reg [3:0] nstate ;
//状态转换标志
wire IDLE_START;
wire START_DATA;
wire DATA_IDLE;
wire DATA_CHECK;
wire CHECK_IDLE;
//波特率计数器
reg [8:0] cnt_baud ;
wire add_cnt_baud ;
wire end_cnt_baud ;
//比特位计数器
reg [2:0] cnt_bit ;
wire add_cnt_bit ;
wire end_cnt_bit ;
reg [3:0] bit_max;
reg [7:0] rx_temp;
reg rx_check;
wire check_val;
//打两拍
reg rx_r1;
reg rx_r2;
wire rx_nege;
//下降沿检测
always @(posedge clk or posedge rst) begin
if (rst) begin
rx_r1 <= 1;
rx_r2 <= 1;
end
else begin
rx_r1 <= rx;
rx_r2 <= rx_r1;
end
end
assign rx_nege = ~rx_r1 && rx_r2;
//
always @(posedge clk or posedge rst)begin
if(rst)begin
cnt_baud <= 'd0;
end
else if(add_cnt_baud)begin
if(end_cnt_baud)begin
cnt_baud <= 'd0;
end
else begin
cnt_baud <= cnt_baud + 1'd1;
end
end
end
assign add_cnt_baud = cstate != IDLE;
assign end_cnt_baud = add_cnt_baud && cnt_baud == MAX_1bit - 1'd1;
//
always @(posedge clk or posedge rst)begin
if(rst)begin
cnt_bit <= 'd0;
end
else if(add_cnt_bit)begin
if(end_cnt_bit)begin
cnt_bit <= 'd0;
end
else begin
cnt_bit <= cnt_bit + 1'd1;
end
end
end
assign add_cnt_bit = end_cnt_baud;
assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max -1'd1;
//定义每个状态字节数,根据UART串口通信协议
always @(*)begin
case (cstate)
IDLE :bit_max = 'd0;
START:bit_max = 'd1;
DATA :bit_max = 'd8;
CHECK:bit_max = 'd1;
default: bit_max = 'd0;
endcase
end
//定义状态转换标志
assign IDLE_START = (cstate == IDLE) && rx_nege;
assign START_DATA = (cstate == START) && end_cnt_bit;
assign DATA_IDLE = (cstate == DATA) && end_cnt_bit && CHECK_BIT == "None";
assign DATA_CHECK = (cstate == DATA) && end_cnt_bit;
assign CHECK_IDLE = (cstate == CHECK) && end_cnt_bit;
//
always @(posedge clk or posedge rst)begin
if(rst)begin
cstate <= IDLE;
end
else begin
cstate <= nstate;
end
end
//
always @(*) begin
case(cstate)
IDLE :begin
if (IDLE_START) begin
nstate = START;
end
else begin
nstate = cstate;
end
end
START :begin
if (START_DATA) begin
nstate = DATA;
end
else begin
nstate = cstate;
end
end
DATA :begin
if (DATA_IDLE) begin
nstate = IDLE;
end
else if (DATA_CHECK) begin
nstate = CHECK;
end
else begin
nstate = cstate;
end
end
CHECK:begin
if (CHECK_IDLE) begin
nstate = IDLE;
end
else begin
nstate = cstate;
end
end
default : nstate = IDLE;
endcase
end
//校验位处理
always @(posedge clk or posedge rst) begin
if (rst) begin
rx_check <= 0;
end
else if (cstate == CHECK && cnt_baud == MAX_1bit >>1) begin
rx_check <= rx_r1;
end
end
assign check_val = (CHECK_BIT == "Odd") ? ~^rx_temp : ^rx_temp;
//数据储存
always @(posedge clk or posedge rst) begin
if (rst) begin
rx_temp <= 0;
end
else if (cstate == DATA && cnt_baud == MAX_1bit >> 1) begin
rx_temp[cnt_bit] <= rx_r1;
end else begin
rx_temp <= rx_temp;
end
end
assign rx_data = rx_temp;
assign rx_data_vld = (CHECK_BIT == "None") ? DATA_IDLE
:(CHECK_IDLE && (check_val == rx_check)) ? 1
: 0;
endmodule
module uart_tx(
input clk ,
input rst ,
input [7:0] tx_data ,
input tx_data_vld ,
output wire ready ,
output reg tx
);
parameter MAX_BPS = 115200;//波特率
parameter CLOCK = 50_000_000;//时钟频率
parameter MAX_1bit = CLOCK/MAX_BPS;// 计算每一位传输所需的时钟周期数
parameter CHECK_BIT = "None";//校验位mode
//定义状态机
localparam IDLE = 'b00001,
START = 'b00010,
DATA = 'b00100,
CHECK = 'b01000,
STOP = 'b10000;
reg [4:0] cstate ;
reg [4:0] nstate ;
//状态机跳转标志
wire IDLE_START;
wire START_DATA;
wire DATA_CHECK;
wire CHECK_STOP;
wire STOP_IDLE;
reg [8:0] cnt_baud ;
wire add_cnt_baud ;
wire end_cnt_baud ;
reg [2:0] cnt_bit ;
wire add_cnt_bit ;
wire end_cnt_bit ;
reg [3:0] bit_max ;
reg [7:0] tx_data_r ;
wire check_val ;
//波特率计数器
always @(posedge clk or posedge rst)begin
if(rst)begin
cnt_baud <= 'd0;
end
else if(add_cnt_baud)begin
if(end_cnt_baud)begin
cnt_baud <= 'd0;
end
else begin
cnt_baud <= cnt_baud + 1'd1;
end
end
end
assign add_cnt_baud = cstate != IDLE;
assign end_cnt_baud = add_cnt_baud && cnt_baud == MAX_1bit - 1'd1;
//数据位计数器
always @(posedge clk or posedge rst)begin
if(rst)begin
cnt_bit <= 'd0;
end
else if(add_cnt_bit)begin
if(end_cnt_bit)begin
cnt_bit <= 'd0;
end
else begin
cnt_bit <= cnt_bit + 1'd1;
end
end
end
assign add_cnt_bit = end_cnt_baud;
assign end_cnt_bit = add_cnt_bit && cnt_bit == bit_max -1'd1;
//数据位定义
always @(*)begin
case (cstate)
IDLE :bit_max = 'd0;
START:bit_max = 'd1;
DATA :bit_max = 'd8;
CHECK:bit_max = 'd1;
STOP :bit_max = 'd1;
default: bit_max = 'd0;
endcase
end
//状态跳转条件
assign IDLE_START = (cstate == IDLE) && tx_data_vld;
assign START_DATA = (cstate == START) && end_cnt_bit;
assign DATA_STOP = (cstate == DATA) && end_cnt_bit && CHECK_BIT == "None";
assign DATA_CHECK = (cstate == DATA) && end_cnt_bit;
assign CHECK_STOP = (cstate ==CHECK) && end_cnt_bit;
assign STOP_IDLE = (cstate == STOP) && end_cnt_bit;
//状态机转换
always @(posedge clk or posedge rst)begin
if(rst)begin
cstate <= IDLE;
end
else begin
cstate <= nstate;
end
end
//FSM
always @(*) begin
case(cstate)
IDLE :begin
if (IDLE_START) begin
nstate = START;
end
else begin
nstate = cstate;
end
end
START :begin
if (START_DATA) begin
nstate = DATA;
end
else begin
nstate = cstate;
end
end
DATA :begin
if (DATA_CHECK) begin
nstate = CHECK;
end
else if (DATA_STOP) begin
nstate = STOP;
end
else begin
nstate = cstate;
end
end
CHECK :begin
if (CHECK_STOP) begin
nstate = STOP;
end
else begin
nstate = cstate;
end
end
STOP :begin
if (STOP_IDLE) begin
nstate = IDLE;
end
else begin
nstate = cstate;
end
end
default : nstate = cstate;
endcase
end
//数据位寄存
always @(posedge clk or posedge rst) begin
if (rst) begin
tx_data_r <= 'd0;
end
else if (tx_data_vld) begin
tx_data_r <= tx_data;
end
else begin
tx_data_r <= tx_data_r;
end
end
//校验位奇偶校验
assign check_val = (CHECK_BIT == "Odd") ? ~^tx_data_r : ^tx_data_r;
//发送数据
always @(*)begin
case (cstate)
IDLE : tx = 1'b1;
START: tx = 1'b0;
DATA : tx = tx_data_r[cnt_bit];
CHECK: tx = check_val;
STOP : tx = 1'b1;
default: tx = 1'b1;
endcase
end
//空闲状态
assign ready = cstate == IDLE;
endmodule
TIPS:波特率为115200,数据收发过程中需要用到串口助手。
UART协议基本介绍: