这篇笔记主要记录对uart_rx模块的理解:
module uart_rx
#(
parameter CLK_FRE = 50,
parameter BAUD_RATE = 115200
)
(
input clk,
input rst_n,
output reg[7:0] rx_data,
output reg rx_data_valid,
input rx_data_ready,
input rx_pin
);
模块引脚说明:
CLK_FRE表示时钟频率。
BAUD_RATE表示通讯波特率。
Clk表示时钟输入引脚。
rst_n表示复位引脚。
rx_data表示8位输出寄存器。
rx_data_valid表示输出寄存器。
rx_data_ready表示输入,准备接收数据。
rx_pin表示输入脚。
assign rx_negedge = rx_d1 && ~rx_d0;
检测下降沿,当输入为下降沿时rx_negedge为1。
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 0)
begin
rx_d0 <= 1'b0;
rx_d1 <= 1'b0;
end
else
begin
rx_d0 <= rx_pin;
rx_d1 <= rx_d0;
end
end
代码含义:如果复位,rx_d0和rx_d1为0;否则rx_d0接收输入引脚的电平状态,并把接收到的状态赋给rx_d1。
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 0)
state <= S_IDLE;
else
state <= next_state;
end
代码含义:复位后uart_rx模块处于空闲状态,否则更新为next_state状态。
always @(*)
begin
case(state)
S_IDLE:
if(rx_negedge)
next_state <= S_START;
else
next_state <= S_IDLE;
S_START:
if(cycle_cnt == CYCLE -1)
next_state <= S_REC_BYTE;
else
next_state <= S_START;
S_REC_BYTE:
if(cycle_cnt == CYCLE -1 && bit_cnt == 3'd7)
next_state <= S_STOP;
else
next_state <= S_REC_BYTE;
S_STOP:
if(cycle_cnt == CYCLE / 2 -1)
next_state <= S_DATA;
else
next_state <= S_STOP;
S_DATA:
if(rx_data_ready)
next_state <= S_IDLE;
else
next_state <= S_DATA;
default:
next_state <= S_IDLE;
endcase
end
代码含义:
uart_rx模块的接收状态机分为空闲态、开始态、接收态、停止态和数据态。
空闲态:上电处于空闲态,如果检测到低电平,则next_state设置为开始态。
开始态:如果接收1位数据的时间等于波特率设置的数据传输位时间,next_state设置为接收态。
接收态:如果接收时间到并且接收完8位数据,next_state设置为停止态。
数据态:将接收到的数据送到其他模块,完成后next_state进入空闲态。
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
rx_data_valid <= 1'b0;
else if(state == S_STOP && next_state != state)
rx_data_valid <= 1'b1;
else if(state == S_DATA && rx_data_ready)
rx_data_valid <= 1'b0;
end
代码含义:当从停止态转变到下一个状态时表示接收到的串口数据有效并设rx_data_valid设置为高,高电平有效。
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
rx_data <= 8'd0;
else if(state == S_STOP && next_state != state)
rx_data <= rx_bits;
end
代码含义:当从停止态转变到下一个状态时把接收到的数据给到8位数据输出引脚rx_data。
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
bit_cnt <= 3'd0;
end
else if(state == S_REC_BYTE)
if(cycle_cnt == CYCLE -1)
bit_cnt <= bit_cnt + 3'd1;
else
bit_cnt <= bit_cnt;
else
bit_cnt <= 3'd0;
end
代码含义:在接收态时,每当位周期到达时,接收计数值加1。
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
cycle_cnt <= 16'd0;
else if((state == S_REC_BYTE && cycle_cnt == CYCLE -1) || next_state != state)
cycle_cnt <= 16'd0;
else
cycle_cnt <= cycle_cnt + 16'd1;
end
代码含义:复位时cycle_cnt清0,接收态cycle_cnt计数到CYCLE -1(位周期)时清零或状态变化时清零。其他情况时cycle_cnt计数加1。
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
rx_bits <= 8'd0;
else if(state == S_REC_BYTE &&cycle_cnt == CYCLE / 2 - 1)
rx_bits[bit_cnt] <= rx_pin;
else
rx_bits <= rx_bits;
end
代码含义:在接收态,当接收数据到半位周期时候,rx_bits开始记录接收线的状态。为什么在半位周期记录接收线状态呢?这样做是为了满足采样定理,接收数据时每一个数据都在采用周期的时间中点进行采样。