基于状态机的串口收发模块的实现
前言
作为一个FPGA的初学者,实现一个完美的串口收发功能一直是心中的一个小小愿望。之前看过其他许多实现串口功能的Verilog代码,感觉它们都有或大或小的缺陷,例如有的代码看起来十分不严谨、结构混乱,有些代码可读性差,想要把它们读懂做一些修改十分困难。自己动手完成了一个较为满意的串口接收、发送模块,并在黑金的AX309试验板上进行了测试,接收到一帧数据后能够完整地将数据发回,数据帧长度达到256字节未出现任何错误。代码结构清晰,相信对串口协议较为了解的伙伴们会很容易读懂。
串口发送
进行串口调试,首先应实现的串口发送模块。为了提高程序可读性,使用状态机进行编程。闲话不多说,直接看源代码:
module uart_tx
#(
parameter CLK_FREQ = 50 ,//时钟频率(Mhz)
parameter BAUD_RATE = 9600 //波特率(bps)
)
(
input clk ,
input rst_n ,
output reg tx_txd ,//发送端口
input tx_trig ,//启动发送,高电平有效
input [7:0] tx_data ,//发送字节,tx_trig高电平输入
output reg tx_idle //空闲标志位,1:空闲态,0:忙碌态
);
localparam BAUD_NUM = (CLK_FREQ*1000_000) / BAUD_RATE - 1 ;//波特率对应计数值
reg [20:0] baud_cnt ;//波特率计数器
reg [ 7:0] tx_data_r ;//tx_data缓存
//状态机参数
localparam S_IDLE = 0;
localparam S_START = 1;
localparam S_BIT0 = 2;
localparam S_BIT1 = 3;
localparam S_BIT2 = 4;
localparam S_BIT3 = 5;
localparam S_BIT4 = 6;
localparam S_BIT5 = 7;
localparam S_BIT6 = 8;
localparam S_BIT7 = 9;
localparam S_STOP = 10;
reg [4:0] state;//状态机
//tx_data_r, 输入tx_data
always @(posedge clk) begin
if(tx_trig && tx_idle)
tx_data_r = S_START)
baud_cnt = S_START)
baud_cnt |