系列文章目录
FPGA Verilog 串口发送
使用modelsim进行Verilog仿真(包含testbench编写)
前言
前面的文章实现了简单的串口发送,本来设计是继续进行串口接收的学习的,但是FPGA串口接收的学习不方便观察现象,所以采用串口收发的形式,将上位机发送的byte再返回回去。
PS:在写代码的过程中明显感觉到在逻辑电路中我失去了逻辑,调试过程十分痛苦,整个实现历时估摸着得有个两三天吧。最后测试每330个字符有一个误码。
串口条件:
- 波特率:115200;
- 无校验位;
- 数据位8位;
- 停止位;
一、串口收发
串口收发的时序倒比较简单,采用状态机的方式实现。
1.串口发送
这个在前面已经有做过了,上面目录里面有。发送总共有4个状态,分别为空闲状态(记作S_IDLE)、起始状态(S_START)、发送状态(S_SEND_BYTE) 以及结束状态(S_STOP)。发送的状态机代码如下。我们初学时主要关注状态机之间的状态转换:
首先,在默认状态下为S_IDLE,当有信号要发送时,即tx_data_valid为高电平时,进入S_STRAT状态。注意,在S_IDLE状态时,对时序没有要求,但是从S_START时,就必须对时钟严格要求了,本文从进入S_START后进行计数(记作cnt_bit),每计434个数作为一个串口传输bit。同时进入S_START时,输出信号线需要有一个下降沿,并在此状态下保持低电平。当cnt_bit计满434后,进入到S_SEND_BYTE状态,从此刻开始每434个cnt_bit的时间发送一个bit,发8个bit后,进入到S_STOP,计434个cnt_bit后转入S_IDLE,此时意味着结束。大概可以意思如下图所示。
module uart_tx
#(
parameter CLK_FRE = 50, //clock frequency(Mhz)
parameter BAUD_RATE = 115200 //serial baud rate
)
(
input clk, //clock input
input rst_n, //asynchronous reset input, low active
input[7:0] tx_data, //data to send
input tx_data_valid, //data to be sent is valid
output reg tx_data_ready, //send ready
output tx_pin //serial data output
);
//calculates the clock cycle for baud rate
localparam CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
//state machine code
localparam S_IDLE = 0;
localparam S_START = 1;//start bit
localparam S_SEND_BYTE = 2;//data bits
localparam S_STOP = 3;//stop bit
//reg [7:0] tx_data;
reg[2:0] state;
reg[15:0] cycle_cnt; //baud counter
reg[2:0] bit_cnt;//bit counter
reg[7:0] tx_data_latch; //latch data to send
reg tx_reg; //serial data output
assign tx_pin = tx_reg;
initial
begin
tx_reg<=1;
// tx_data<=8'ha5;
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
state <= S_IDLE;
else
case(state)
S_IDLE:
if(tx_data_valid == 1'b1)//触发状态