代码如下:
发送模块uart_wr:
module UART_WR(
input clk,
input rst_n,
input wr_en,
input[7:0] data_wr,
output reg uart_tx,
output reg rdy
);
parameter CLK_FREQ = 32'd50_000_000; // 输入时钟为50MHz
parameter BAUDRATE = 32'd115200; // 波特率为115200
localparam TICK = CLK_FREQ / BAUDRATE;
localparam STAT_IDLE = 4'b0001; // 空闲
localparam STAT_START = 4'b0010; // 起始位
localparam STAT_DATA = 4'b0100; // 数据位
localparam STAT_STOP = 4'b1000; // 停止位
reg[23:0] cnt;
reg[2:0] bit_cnt;
reg[7:0] data_r;
reg[3:0] cstate, nstate;
reg flg;
wire add_cnt, end_cnt;
wire add_bit_cnt, end_bit_cnt;
wire idle2start, start2data, data2stop, stop2idle; // 状态转换条件
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cstate <= STAT_IDLE;
else
cstate <= nstate;
end
always @(*) begin
case(cstate)
STAT_IDLE:
if(idle2start)
nstate <= STAT_START;
else
nstate <= cstate;
STAT_START:
if(start2data)
nstate <= STAT_DATA;
else
nstate <= cstate;
STAT_DATA:
if(data2stop)
nstate <= STAT_STOP;
else
nstate <= cstate;
STAT_STOP:
if(stop2idle)
nstate <= STAT_IDLE;
else
nstate <= cstate;
default:
nstate <= STAT_IDLE;
endcase
end
assign idle2start = (cstate == STAT_IDLE) && (wr_en == 1'b1);
assign start2data = (cstate == STAT_START) && end_cnt;
assign data2stop = (cstate == STAT_DATA) && end_bit_cnt;
assign stop2idle = (cstate == STAT_STOP) && end_cnt;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 24'd0;
else if(add_cnt)
if(end_cnt)
cnt <= 24'd0;
else
cnt <= cnt + 24'd1;
else
cnt <= cnt;
end
assign add_cnt = (cstate != STAT_IDLE);
assign end_cnt = add_cnt && (cnt == TICK - 32'd1);
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
bit_cnt <= 3'd0;
else if(add_bit_cnt)
if(end_bit_cnt)
bit_cnt <= 3'd0;
else
bit_cnt <= bit_cnt + 3'd1;
else
bit_cnt <= bit_cnt;
end
assign add_bit_cnt = (cstate == STAT_DATA) && end_cnt;
assign end_bit_cnt = add_bit_cnt && (bit_cnt == 4'd8 - 4'd1);
// 对输入数据进行缓存
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
data_r <= 8'd0;
else if(idle2start)
data_r <= data_wr;
else
data_r <= data_r;
end
// 生成uart_tx信号
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
uart_tx <= 1'b1;
else if(cstate == STAT_START)
uart_tx <= 1'b0;
else if(cstate == STAT_DATA)
uart_tx <= data_r[bit_cnt];
else
uart_tx <= 1'b1;
end
// 生成rdy信号
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
flg <= 1'b0;
else if(wr_en)
flg <= 1'b1;
else if(stop2idle)
flg <= 1'b0;
else
flg <= flg;
end
always @(*) begin
if(wr_en || flg) // 当wr_en为高时,rdy同时拉低;当flg为高时,rdy也为低
rdy = 1'b0;
else
rdy = 1'b1;
end
endmodule
顶层模块uart,做一个回环测试,即电脑发什么,FPGA就往回发什么:
module UART(
input sys_clk_50m,
input sys_rst_n,
input uart_rx,
output uart_tx,
);
wire rd_vld, rdy;
wire[7:0] data;
UART_WR #(
.CLK_FREQ(32'd50_000_000),
.BAUDRATE(32'd115200)
) u_uart_wr(
.clk(sys_clk_50m),
.rst_n(sys_rst_n),
.wr_en(rd_vld),
.data_wr(data),
.uart_tx(uart_tx),
.rdy(rdy)
);
UART_RD #(
.CLK_FREQ(32'd50_000_000),
.BAUDRATE(32'd115200)
) u_uart_rd(
.clk(sys_clk_50m),
.rst_n(sys_rst_n),
.uart_rx(uart_rx),
.rd_vld(rd_vld),
.data_rd(data)
);
endmodule
打三拍采样RX脚的接收模块uart_rx:
module UART_RD(
input clk,
input rst_n,
input uart_rx,
output reg rd_vld,
output reg[7:0] data_rd
);
parameter CLK_FREQ = 32'd50_000_000; // 输入时钟为50MHz
parameter BAUDRATE = 32'd115200; // 波特率为115200
localparam TICK = CLK_FREQ / BAUDRATE;
localparam STAT_IDLE = 4'b0001; // 空闲
localparam STAT_START = 4'b0010; // 起始位
localparam STAT_DATA = 4'b0100; // 数据位
localparam STAT_STOP = 4'b1000; // 停止位
reg[23:0] cnt;
reg[2:0] bit_cnt;
reg[3:0] cstate, nstate;
reg[2:0] uart_rx_ff;
wire add_cnt, end_cnt;
wire add_bit_cnt, end_bit_cnt;
wire idle2start, start2data, data2stop, stop2idle; // 状态转换条件
wire uart_rx_fall;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cstate <= STAT_IDLE;
else
cstate <= nstate;
end
always @(*) begin
case(cstate)
STAT_IDLE:
if(idle2start)
nstate <= STAT_START;
else
nstate <= cstate;
STAT_START:
if(start2data)
nstate <= STAT_DATA;
else
nstate <= cstate;
STAT_DATA:
if(data2stop)
nstate <= STAT_STOP;
else
nstate <= cstate;
STAT_STOP:
if(stop2idle)
nstate <= STAT_IDLE;
else
nstate <= cstate;
default:
nstate <= STAT_IDLE;
endcase
end
assign idle2start = (cstate == STAT_IDLE) && uart_rx_fall;
//assign idle2start = (cstate == STAT_IDLE) && (uart_rx == 1'b0);
assign start2data = (cstate == STAT_START) && end_cnt;
assign data2stop = (cstate == STAT_DATA) && end_bit_cnt;
assign stop2idle = (cstate == STAT_STOP) && end_cnt;
// 打三拍检测uart_rx的下降沿
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
uart_rx_ff <= 3'b1;
else
uart_rx_ff <= {uart_rx_ff[1], uart_rx_ff[0], uart_rx};
end
assign uart_rx_fall = (uart_rx_ff[2] == 1'b1) && (uart_rx_ff[1] == 1'b0); // 读取RX脚电平时用的是uart_rx_ff[2]
// 对每个比特的时间长度进行计数
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 24'd0;
else if(add_cnt)
if(end_cnt)
cnt <= 24'd0;
else
cnt <= cnt + 24'd1;
else
cnt <= cnt;
end
assign add_cnt = (cstate != STAT_IDLE);
assign end_cnt = add_cnt && (cnt == TICK - 32'd1);
// 对数据位的比特个数进行计数
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
bit_cnt <= 3'd0;
else if(add_bit_cnt)
if(end_bit_cnt)
bit_cnt <= 3'd0;
else
bit_cnt <= bit_cnt + 3'd1;
else
bit_cnt <= bit_cnt;
end
assign add_bit_cnt = (cstate == STAT_DATA) && end_cnt;
assign end_bit_cnt = add_bit_cnt && (bit_cnt == 4'd8 - 4'd1);
// 读取数据
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
data_rd <= 8'd0;
else if(cstate == STAT_DATA && add_cnt && cnt == (TICK / 32'd2) - 32'd1)
data_rd[bit_cnt] <= uart_rx_ff[2];
else
data_rd <= data_rd;
end
// 生成数据有效信号
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
rd_vld <= 1'b0;
else if(stop2idle)
rd_vld <= 1'b1;
else
rd_vld <= 1'b0;
end
endmodule
下面是不打拍直接检测电平的接收模块uart_rx,可以正常运行:
module UART_RD(
input clk,
input rst_n,
input uart_rx,
output reg rd_vld,
output reg[7:0] data_rd
);
parameter CLK_FREQ = 32'd50_000_000; // 输入时钟为50MHz
parameter BAUDRATE = 32'd115200; // 波特率为115200
localparam TICK = CLK_FREQ / BAUDRATE;
localparam STAT_IDLE = 4'b0001; // 空闲
localparam STAT_START = 4'b0010; // 起始位
localparam STAT_DATA = 4'b0100; // 数据位
localparam STAT_STOP = 4'b1000; // 停止位
reg[23:0] cnt;
reg[2:0] bit_cnt;
reg[3:0] cstate, nstate;
reg[2:0] uart_rx_ff;
wire add_cnt, end_cnt;
wire add_bit_cnt, end_bit_cnt;
wire idle2start, start2data, data2stop, stop2idle; // 状态转换条件
wire uart_rx_fall;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cstate <= STAT_IDLE;
else
cstate <= nstate;
end
always @(*) begin
case(cstate)
STAT_IDLE:
if(idle2start)
nstate <= STAT_START;
else
nstate <= cstate;
STAT_START:
if(start2data)
nstate <= STAT_DATA;
else
nstate <= cstate;
STAT_DATA:
if(data2stop)
nstate <= STAT_STOP;
else
nstate <= cstate;
STAT_STOP:
if(stop2idle)
nstate <= STAT_IDLE;
else
nstate <= cstate;
default:
nstate <= STAT_IDLE;
endcase
end
assign idle2start = (cstate == STAT_IDLE) && (uart_rx == 1'b0);
assign start2data = (cstate == STAT_START) && end_cnt;
assign data2stop = (cstate == STAT_DATA) && end_bit_cnt;
assign stop2idle = (cstate == STAT_STOP) && end_cnt;
// 对每个比特的时间长度进行计数
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 24'd0;
else if(add_cnt)
if(end_cnt)
cnt <= 24'd0;
else
cnt <= cnt + 24'd1;
else
cnt <= cnt;
end
assign add_cnt = (cstate != STAT_IDLE);
assign end_cnt = add_cnt && (cnt == TICK - 32'd1);
// 对数据位的比特个数进行计数
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
bit_cnt <= 3'd0;
else if(add_bit_cnt)
if(end_bit_cnt)
bit_cnt <= 3'd0;
else
bit_cnt <= bit_cnt + 3'd1;
else
bit_cnt <= bit_cnt;
end
assign add_bit_cnt = (cstate == STAT_DATA) && end_cnt;
assign end_bit_cnt = add_bit_cnt && (bit_cnt == 4'd8 - 4'd1);
// 读取数据
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
data_rd <= 8'd0;
else if(cstate == STAT_DATA && add_cnt && cnt == (TICK / 32'd2) - 32'd1)
data_rd[bit_cnt] <= uart_rx;
else
data_rd <= data_rd;
end
// 生成数据有效信号
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
rd_vld <= 1'b0;
else if(stop2idle)
rd_vld <= 1'b1;
else
rd_vld <= 1'b0;
end
endmodule