一、基础知识
- 首先uart_rxd有高电平到低电平(一个下降沿)变化时,start_flag则拉高一个周期
- 把异步数据同步到系统时钟下是因为,如果是异步数据库,不做同步处理,则会产生亚稳态,会对系统功能产生影响
- 5000000/115200=434(约等于) 0001 1011 0010 (此时位宽为9)若波特率低,则需要位宽更大,则把位宽定义为[15:0]。例如5000000/9600=520 (0010 0000 1000)
- rx_cnt到9时只有一半,没等停止位结束,提前把rx_flag拉低,检测下一位起始位留出时间
二、程序
module uart_recv()
input sys_clk,
input sys_rst_n,
input uart_rxd,
output reg[7:0] uart_data,
output reg uart_done
);
parameter CLK_FREQ = 50_000_000;
parameter UART_BPS = 115200;
parameter BPS_CNT = CLK_FREQ/UART_BPS;
reg uart_rxd_d0; //定义两个寄存器
reg uart_rxd_d1;
reg rx_flag;
reg [3:0]rx_cnt;
reg [15:0]clk_cnt; //上3
reg [7:0]rx_data;
wire start_flag;
assign start_flag = uart_rxd_d1 & (~uart_rxd_d0);
always @(posedge clk or negedge rst_n)begin //把异步数据同步到系统时钟上2
if(!sys_rst_n)begin //复位
uart_rxd_d0 <=1'b1;
uart_rxd_d1 <=1'b1;
end
else begin
uart_rxd_d0 <= uart_rxd;
uart_rxd_d1 <= uart_rxd_d0;
end
end
always @(posedge clk or negedge rst_n)begin //通过start_flag看rx_flag
if(!sys_rst_n)
rx_flag <= 1'b0;
else if(stat_flag)
rx_flag <= 1'b1;
else if(rx_cnt == 4'd9) && (clk_cnt == BPS_CNT/2-1'b1)//上4
rx_flag <= 1'b0;
end
endmodule
always @(posedge clk or negedge rst_n)begin //通过rx_flag看clk_cnt
if(!sys_rst_n)
clk_cnt <= 16'd0;
else if(rx_flag)begin
if(clk_cnt < BPS_CNT-1'b1)
clk_cnt <= clk_cnt + 1'b1;
else
clk_cnt <=16'd0;
end
else
clk_cnt <=16'd0;
end
endmodule
always @(posedge clk or negedge rst_n)begin //通过rx_flag看rx_cnt
if(!sys_rst_n)
rx_cnt <= 4'd0;
else if(rx_flag)begin
if(clk_cnt == BPS_CNT -1'b1)
rx_cnt <= rx_cnt +1'b1;
else
rx_cnt <= rx_cnt ;
end
else
rx_cnt <= 4'd0;
end
endmodule
always @(posedge clk or negedge rst_n)begin //通过rx_flag和rx_cnt判断rx_data
if(!sys_rst_n)
rx_data <=8'd0; //寄存串行数据
else if(rx_flag && (clk_cnt == BPS_CNT/2))begin //在1/2时钟周期值比较稳定
case(rx_cnt) //数据串转并
4‘d1 : rx_data[0] <= uart_rxd_d1;
4‘d2 : rx_data[1] <= uart_rxd_d1;
4‘d3 : rx_data[2] <= uart_rxd_d1;
4‘d4 : rx_data[3] <= uart_rxd_d1;
4‘d5 : rx_data[4] <= uart_rxd_d1;
4‘d6 : rx_data[5] <= uart_rxd_d1;
4‘d7 : rx_data[6] <= uart_rxd_d1;
4‘d8 : rx_data[7] <= uart_rxd_d1;
endcase
end
end
endmodule
always @(posedge clk or negedge rst_n)begin //最后对uart_done和uart_data赋值
if(!sys_rst_n)begin
uart_done <= 1'b0;
uart_data <= 8'd0;
end
else if(rx_cnt == 4'd9)begin
uart_done <= 1'b1;
uart_data <= rx_data;
else begin //rx_cnt不等于9位低电平
uart_done <= 1'b0;
uart_data <= 8'd0;
end
end
endmodule