设计一个uart项目,包括接收模块和发送模块,其中接收模块和发送模块中存在FIFO模块和状态机
时间: 2023-08-20 16:07:30 浏览: 94
以下是一个包括接收模块和发送模块的UART项目,其中接收模块和发送模块都有FIFO模块和状态机:
接收模块:
```verilog
module uart_rx (
input clk,
input rst,
input rx,
output reg [7:0] data_out,
output reg rx_done,
output reg [3:0] err
);
parameter CLK_FREQ = 50000000;
parameter BAUD_RATE = 9600;
localparam IDLE = 2'b00;
localparam START = 2'b01;
localparam DATA = 2'b10;
localparam STOP = 2'b11;
reg [7:0] fifo [0:15];
reg [3:0] wr_ptr = 0;
reg [3:0] rd_ptr = 0;
wire [3:0] count = wr_ptr - rd_ptr;
reg [1:0] state = IDLE;
reg [3:0] bit_cnt = 0;
reg [7:0] data = 0;
reg rx_busy = 0;
reg [3:0] rx_err = 0;
// calculate the baud rate divisor
reg [15:0] divisor = CLK_FREQ / BAUD_RATE;
always @ (posedge clk or posedge rst) begin
if (rst) begin
wr_ptr <= 0;
rd_ptr <= 0;
state <= IDLE;
bit_cnt <= 0;
data <= 0;
rx_done <= 0;
rx_busy <= 0;
rx_err <= 0;
err <= 0;
data_out <= 0;
end else begin
// check for errors
if (rx == 0 && state != START && state != STOP && rx_busy == 0) begin
rx_err <= rx_err + 1;
err <= 1;
end
// receive data
case (state)
IDLE: begin
if (rx == 0) begin
state <= START;
bit_cnt <= 0;
data <= 0;
rx_busy <= 1;
end
end
START: begin
if (bit_cnt == 0) begin
if (rx == 1) begin
state <= IDLE;
rx_busy <= 0;
rx_err <= 0;
err <= 0;
end else begin
bit_cnt <= bit_cnt + 1;
end
end else if (bit_cnt > 0 && bit_cnt < 9) begin
data[bit_cnt - 1] <= rx;
bit_cnt <= bit_cnt + 1;
end else if (bit_cnt == 9) begin
if (rx == 1) begin
state <= STOP;
bit_cnt <= 0;
end else begin
rx_err <= rx_err + 1;
state <= IDLE;
rx_busy <= 0;
err <= 1;
end
end
end
DATA: begin
if (bit_cnt < 8) begin
data[bit_cnt] <= rx;
bit_cnt <= bit_cnt + 1;
end else if (bit_cnt == 8) begin
if (rx == 1) begin
state <= STOP;
bit_cnt <= 0;
end else begin
rx_err <= rx_err + 1;
state <= IDLE;
rx_busy <= 0;
err <= 1;
end
end
end
STOP: begin
if (rx == 1) begin
fifo[wr_ptr] <= data;
wr_ptr <= wr_ptr + 1;
rx_done <= 1;
end else begin
rx_err <= rx_err + 1;
state <= IDLE;
rx_busy <= 0;
err <= 1;
end
end
endcase
end
end
assign data_out = fifo[rd_ptr];
assign count = wr_ptr - rd_ptr;
assign rd_ptr = (rx_done) ? rd_ptr + 1 : rd_ptr;
endmodule
```
该接收模块包含一个状态机,用于解析接收到的数据。当探测到起始位时,状态机将进入“START”状态,并根据数据位的数量接收数据。在数据位之后,状态机将检查停止位是否正确,并将数据存储在FIFO中。如果发现错误,状态机将返回“IDLE”状态并丢弃数据。该接收模块还包括一个计数器,用于跟踪FIFO中的数据量,并具有一个输出信号,用于指示FIFO是否为空或已满。
发送模块:
```verilog
module uart_tx (
input clk,
input rst,
output reg tx,
input [7:0] data_in,
input wr_en,
input rd_en,
output reg full,
output reg empty
);
parameter CLK_FREQ = 50000000;
parameter BAUD_RATE = 9600;
localparam IDLE = 2'b00;
localparam START = 2'b01;
localparam DATA = 2'b10;
localparam STOP = 2'b11;
reg [7:0] fifo [0:15];
reg [3:0] wr_ptr = 0;
reg [3:0] rd_ptr = 0;
wire [3:0] count = wr_ptr - rd_ptr;
reg [1:0] state = IDLE;
reg [3:0] bit_cnt = 0;
reg [7:0] data_out = 0;
reg tx_busy = 0;
// calculate the baud rate divisor
reg [15:0] divisor = CLK_FREQ / BAUD_RATE;
always @ (posedge clk or posedge rst) begin
if (rst) begin
wr_ptr <= 0;
rd_ptr <= 0;
state <= IDLE;
bit_cnt <= 0;
data_out <= 0;
tx <= 1;
tx_busy <= 0;
full <= 0;
empty <= 1;
end else begin
// check if there is data in the FIFO to transmit
if (tx_busy == 0 && count > 0) begin
data_out <= fifo[rd_ptr];
rd_ptr <= rd_ptr + 1;
tx_busy <= 1;
end
// transmit data
case (state)
IDLE: begin
if (tx_busy == 1) begin
state <= START;
bit_cnt <= 0;
tx <= 0;
end
end
START: begin
if (bit_cnt == 0) begin
tx <= 0;
bit_cnt <= bit_cnt + 1;
end else if (bit_cnt < 9) begin
tx <= data_out[bit_cnt - 1];
bit_cnt <= bit_cnt + 1;
end else if (bit_cnt == 9) begin
tx <= 1;
bit_cnt <= bit_cnt + 1;
end else if (bit_cnt == 10) begin
tx_busy <= 0;
bit_cnt <= 0;
state <= IDLE;
end
end
endcase
// write data to FIFO
if (wr_en && count < 16) begin
fifo[wr_ptr] <= data_in;
wr_ptr <= wr_ptr + 1;
empty <= 0;
end
// update status signals
full <= (count == 16);
end
end
endmodule
```
该发送模块也包含一个状态机,用于发送FIFO中的数据。当FIFO中有数据时,状态机将进入“START”状态,并在每个位时间发送数据。当数据被完全发送后,状态机将返回“IDLE”状态。该发送模块还包括一个计数器,用于跟踪FIFO中的数据量,并具有输出信号,用于指示FIFO是否为空或已满。
阅读全文