实用指南:8-verilog-串口接收与发送模块

verilog-串口接收与发送模块

1.串口接收

module uart_recv_parity(
input sys_clk, // 系统时钟
input sys_rst_n, // 系统复位,低电平有效
input uart_rxd, // UART接收端口
output reg uart_done, // 接收一帧数据完成标志信号
output reg frame_error, // 帧错误(停止位不为1)
output reg parity_error, // 奇偶校验错误
output reg [7:0] uart_data // 接收的数据
);
// 参数定义
parameter CLK_FREQ = 50000000;
// 系统时钟频率
parameter UART_BPS = 9600;
// 串口波特率
parameter PARITY = "ODD";
// 校验类型:"NONE", "ODD", "EVEN"
localparam BPS_CNT = CLK_FREQ/UART_BPS;
// 每个波特率周期的时钟数
localparam BPS_CNT_HALF = BPS_CNT/2;
// 半位周期时钟数
// 寄存器定义
reg [1:0] uart_rxd_sync;
// 同步寄存器
reg [15:0] clk_cnt;
// 波特率时钟计数器
reg [3:0] rx_cnt;
// 接收位计数器
reg rx_flag;
// 接收过程标志
reg [7:0] rxdata;
// 接收数据寄存器
reg parity_bit;
// 计算的奇偶校验位
reg received_parity;
// 接收到的校验位
// 检测起始位下降沿
wire start_flag = (uart_rxd_sync == 2'b10);
// 同步输入信号,防止亚稳态
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
uart_rxd_sync <= 2'b11;
else
uart_rxd_sync <= {uart_rxd_sync[0], uart_rxd
};
end
// 接收过程控制
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
rx_flag <= 1'b0;
else if(start_flag) // 检测到起始位
rx_flag <= 1'b1;
// 开始接收
else if((rx_cnt == 4'd9 && PARITY == "NONE") ||
(rx_cnt == 4'd10 && PARITY != "NONE"))
if(clk_cnt == BPS_CNT_HALF)
rx_flag <= 1'b0;
// 接收完成
end
// 波特率时钟计数器和接收位计数器
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
clk_cnt <= 16'd0;
rx_cnt <= 4'd0;
end
else if(rx_flag) begin // 接收过程中
if(clk_cnt < BPS_CNT - 1)
clk_cnt <= clk_cnt + 1'b1;
else begin
clk_cnt <= 16'd0;
rx_cnt <= rx_cnt + 1'b1;
end
end
else begin // 非接收过程
clk_cnt <= 16'd0;
rx_cnt <= 4'd0;
end
end
// 计算奇偶校验位
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
parity_bit <= 1'b0;
end
else if (rx_flag &&
(rx_cnt == 4'd8) &&
(clk_cnt == BPS_CNT_HALF)) begin
if (PARITY == "ODD")
parity_bit <= ^rxdata;
// 奇校验
else if (PARITY == "EVEN")
parity_bit <= ~^rxdata;
// 偶校验
end
end
// 接收校验位
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
received_parity <= 1'b0;
end
else if (rx_flag &&
(rx_cnt == 4'd9) &&
(clk_cnt == BPS_CNT_HALF) begin
received_parity <= uart_rxd_sync[1];
end
end
// 数据位采样
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
rxdata <= 8'd0;
else if(rx_flag &&
(clk_cnt == BPS_CNT_HALF)) begin
case(rx_cnt)
4'd1: rxdata[0] <= uart_rxd_sync[1];
4'd2: rxdata[1] <= uart_rxd_sync[1];
4'd3: rxdata[2] <= uart_rxd_sync[1];
4'd4: rxdata[3] <= uart_rxd_sync[1];
4'd5: rxdata[4] <= uart_rxd_sync[1];
4'd6: rxdata[5] <= uart_rxd_sync[1];
4'd7: rxdata[6] <= uart_rxd_sync[1];
4'd8: rxdata[7] <= uart_rxd_sync[1];
default: rxdata <= rxdata;
endcase
end
end
// 输出数据和状态
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
uart_data <= 8'd0;
uart_done <= 1'b0;
frame_error <= 1'b0;
parity_error <= 1'b0;
end
else if(((rx_cnt == 4'd9) &&
(PARITY == "NONE")) ||
((rx_cnt == 4'd10) &&
(PARITY != "NONE"))) begin
if(clk_cnt == BPS_CNT_HALF) begin
uart_data <= rxdata;
// 输出接收数据
uart_done <= 1'b1;
// 接收完成信号
// 检查停止位(总是第9/10位,取决于是否有校验)
if(PARITY == "NONE")
frame_error <= ~uart_rxd_sync[1];
// 检查停止位是否为1
else
frame_error <= ~uart_rxd_sync[1];
// 检查停止位是否为1
// 检查校验位
if(PARITY != "NONE")
parity_error <= (received_parity != parity_bit);
else
parity_error <= 1'b0;
end
end
else begin
uart_done <= 1'b0;
// 完成信号只持续一个周期
end
end
endmodule

2.串口发送

在这里插入代码片
posted @ 2025-08-15 09:31  yjbjingcha  阅读(55)  评论(0)    收藏  举报