Verilog | UART 串口接收程序设计及仿真
本文从程序设计角度讲解 Verilog 串口 接收 程序设计思路以及相应仿真,串口原理及协议不是本文重点、协议本身也很简单,有兴趣的请参阅其它资料。
1、串口参数
如果你用过串口通讯,那么对于 波特率、数据位、停止位和校验 应该并不陌生,因为在通讯之前,必须先设置这些参数。不过在程序设计中,还需要知道时钟频率,用来产生波特率。校验比较鸡肋,食之无味、弃之可惜,考虑到程序完整性,只给它留个位,并无作用。
module UARTRecv #(parameter
CLK_FREQ = 50_000_000, // 时钟频率
BAUD_RATE = 115200, // 波特率
WORD_LENGTH = 8, // 数据位
STOP_BITS = 2, // 停止位
// 2 仅用于发送,多发一个,防止接收端漏帧
PARITY = "NONE" // ODD, EVEN 鸡肋,弃之
)
这里有必要思考个问题:为什么需要这些参数呢?简而言之,参数规定了数据的格式,这样收发双方才知道如何发送和接收数据。比如波特率,它规定了一个数据位的持续时间,这样发送方在发送的时候,就知道一个位需要保持多长时间,接收方在接收的时候,也能根据时间推断出这是第几位数据。
2、起始信号
串口通讯属于异步传输,接收方根本不知道何时开始传输数据,这就需要发送方在要发送数据的时候,先通知接收方 ——“我要发送数据了,请做好接收准备”。具体怎么通知呢? 在空闲状态,线路保持高电平。发送方发送一位 “0” 作为起始位,标识数据传输开始。 因此接收方需要检测线路从 “1” 到 “0” 的跳变,即为起始信号。
/* 捕获接收起始信号:下降沿 */
wire recvStart; // 起始标志
reg [3:0] rxBuf; // 用于判断下降沿
always @(posedge CLK or negedge RST_N) begin
if (!RST_N)
rxBuf <= 4'b1111;
else
rxBuf <= {rxBuf[2:0],RX};
end
assign recvStart = rxBuf[3] & rxBuf[2] & ~rxBuf[1] & ~rxBuf[0];
程序中通过移位寄存器缓存四位数据,若前两位为 “1”,后两位为 “0”,则表示从 “1” 到 “0” 的跳变,得到起始信号。
3、采样点
接收方在采样点采样数据,以确定该位是 “0” 还是 “1”。最