基于bi站正点原子讲解视频:
系统框图(基于串口的数据回环)如下:
以下,是串口接收端的波形图,系统时钟和波特率时钟不同,为异步时钟,,需要先延时两拍,将时钟同步过来,取到start_flag信号,由start_flag信号结合clk_cnt、bps_cnt两个计数器取到rx_flag信号,随后在rx_flag高电平时计算clk_cnt以及bps_cnt两个信号。最后两个信号uart_done、uart_data则在串口发送模块有所体现。
实际上,uart_done在串口发送模块中也就是uart_en信号,而uart_data也就是发送模块中的uart_din信号。
`timescale 1ns / 1ps
// Create Date: 2025/01/06 09:38:08
// Design Name:
// Module Name: uart_recv
module uart_recv(
input sys_clk , //50Mhz系统时钟
input sys_rst_n ,
input uart_rxd , //接收到的数据
output reg [7:0] uart_data , //输出的并行数据
output reg uart_done //一帧信号接收完成
);
parameter sys_freq = 50_000_000;
parameter uart_bps = 115_200;
parameter bps_cnt = sys_freq/uart_bps - 1;//从0开始计算
reg uart_rxd_d0;
reg uart_rxd_d1;
wire start_flag;
reg rx_flag;
reg [15:0] clk_cnt;
reg [3:0] rx_cnt;
reg [7:0] rx_data;//中间变量存储提取到的每个位的数据来实现串口端的串并转换
//由高电平向低电平的跳变(下降沿),相当于d1延时2个时钟周期;d0延时1个时钟周期
//因此判断d1是否为高且d0是否为低即可。
assign start_flag = uart_rxd_d1 & (~uart_rxd_d0);
//异步时钟同步化处理
always@(posedge sys_clk or negedge sys_rst_n)
begin
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
//rx_flag
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
rx_flag <= 1'b0;
else if(start_flag == 1'b1)
rx_flag <= 1'b1;
else if((rx_cnt == 4'd9) && (clk_cnt == bps_cnt/2 - 1'b1))
//为监测到下一帧数据的起始位留半个周期的时间
rx_flag <= 1'b0;
else
rx_flag <= 1'b1;
end
//clk_cnt
always@(posedge sys_clk or negedge sys_rst_n)
begin
if(!sys_rst_n)
clk_cnt <= 16'd0;
else if(rx_flag == 1'b1)
// begin //效果相同否?
// if(clk_cnt == uart_bps)
// clk_cnt <= 16'd0;
// else
// clk_cnt <= clk_cnt + 16'd1;
// end
begin
if(clk_cnt < uart_bps - 16'd1)
clk_cnt <= clk_cnt + 16'd1;
else
clk_cnt <= 16'd0;