FPGA 串口收发

系列文章目录

FPGA Verilog 串口发送
使用modelsim进行Verilog仿真(包含testbench编写)


前言

前面的文章实现了简单的串口发送,本来设计是继续进行串口接收的学习的,但是FPGA串口接收的学习不方便观察现象,所以采用串口收发的形式,将上位机发送的byte再返回回去。
PS:在写代码的过程中明显感觉到在逻辑电路中我失去了逻辑,调试过程十分痛苦,整个实现历时估摸着得有个两三天吧。最后测试每330个字符有一个误码。
串口条件:

  1. 波特率:115200;
  2. 无校验位;
  3. 数据位8位;
  4. 停止位;

一、串口收发

串口收发的时序倒比较简单,采用状态机的方式实现。

1.串口发送

这个在前面已经有做过了,上面目录里面有。发送总共有4个状态,分别为空闲状态(记作S_IDLE)、起始状态(S_START)、发送状态(S_SEND_BYTE) 以及结束状态(S_STOP)。发送的状态机代码如下。我们初学时主要关注状态机之间的状态转换:
首先,在默认状态下为S_IDLE,当有信号要发送时,即tx_data_valid为高电平时,进入S_STRAT状态。注意,在S_IDLE状态时,对时序没有要求,但是从S_START时,就必须对时钟严格要求了,本文从进入S_START后进行计数(记作cnt_bit),每计434个数作为一个串口传输bit。同时进入S_START时,输出信号线需要有一个下降沿,并在此状态下保持低电平。当cnt_bit计满434后,进入到S_SEND_BYTE状态,从此刻开始每434个cnt_bit的时间发送一个bit,发8个bit后,进入到S_STOP,计434个cnt_bit后转入S_IDLE,此时意味着结束。大概可以意思如下图所示。
在这里插入图片描述

module uart_tx
#(
	parameter CLK_FRE = 50,      //clock frequency(Mhz)
	parameter BAUD_RATE = 115200 //serial baud rate
)
(
	input                        clk,              //clock input
	input                        rst_n,            //asynchronous reset input, low active 
	input[7:0]                   tx_data,          //data to send
	input                        tx_data_valid,    //data to be sent is valid
	output reg                   tx_data_ready,    //send ready
	output                       tx_pin           //serial data output

);
//calculates the clock cycle for baud rate 
localparam                       CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
//state machine code
localparam                       S_IDLE       = 0;
localparam                       S_START      = 1;//start bit
localparam                       S_SEND_BYTE  = 2;//data bits
localparam                       S_STOP       = 3;//stop bit
//reg [7:0] tx_data;
reg[2:0]                         state;
reg[15:0]                        cycle_cnt; //baud counter
reg[2:0]                         bit_cnt;//bit counter
reg[7:0]                         tx_data_latch; //latch data to send
reg                              tx_reg; //serial data output
assign tx_pin = tx_reg;

initial
begin
	tx_reg<=1;
//	tx_data<=8'ha5;
end

always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
		state <= S_IDLE;
	else
	case(state)
		S_IDLE:
			if(tx_data_valid == 1'b1)//触发状态
			
### FPGA串口接收实现方法 #### 1. 系统概述 FPGA中的串口接收功能通常用于将外部设备传输过来的串行数据转换为并行数据以便进一步处理。整个过程涉及多个阶段,包括检测起始位、采样数据位、识别停止位等[^1]。 #### 2. 接收模块设计 ##### (a) 起始位检测 当串口通信开始时,发送方会先发出一个低电平作为起始位。接收端通过监测输入信号的变化来捕获这个起始位。为了提高可靠性,可以采用双级触发器结构消除亚稳态问题[^1]。 ```verilog always @(posedge clk or negedge reset_n) begin if (!reset_n) begin start_bit_detected <= 0; data_reg <= {DATA_WIDTH{1'b1}}; end else begin // 双沿锁存机制 meta_data <= input_signal; sync_data <= meta_data; if (~sync_data && prev_sync_data) begin start_bit_detected <= 1; // 检测到下降沿 end else begin start_bit_detected <= 0; end prev_sync_data <= sync_data; end end ``` ##### (b) 数据位采样 一旦确认了起始位的存在,则按照波特率定时器设定的时间间隔依次采集后续的数据位。一般情况下,会在每位中间时刻进行采样以获得更精确的结果[^1]。 ```verilog // 假设每比特持续时间为N个系统时钟周期 integer bit_count; reg [7:0] received_byte; always @(posedge clk or negedge reset_n) begin if (!reset_n) begin bit_count <= 0; receiving_flag <= 0; received_byte <= 8'hFF; end else if(start_bit_detected) begin receiving_flag <= 1; bit_count <= 0; end else if(receiving_flag && count == BIT_PERIOD/2) begin case(bit_count) 0 : received_byte[0] <= sync_data; 1 : received_byte[1] <= sync_data; ... default : ; endcase bit_count <= bit_count + 1; if(bit_count >= DATA_BITS-1) begin receiving_flag <= 0; end end end ``` ##### (c) 停止位校验 最后一步是对结束标志进行核查。正常状况下,最后一个传送的是高电平状态;如果不匹配则表明出现了错误情况[^1]。 ```verilog wire stop_bit_error = |(received_stop_bits & ~expected_stop_value); assign rx_done_pulse = !receiving_flag && previous_receiving_state; previous_receiving_state <= receiving_flag; ``` #### 3. 测试与验证 开发完成后需构建TestBench来进行功能性测试,并利用实际硬件平台执行最终部署前的最后一轮检验工作。 ```verilog initial begin $dumpfile("uart_rx.vcd"); $dumpvars(0, uart_rx_tb); rstn = 0; #CLK_PER rstn = 1; repeat(10) @(posedge clk); tx_in = 1'b0; // Start Bit @(posedge clk); for(int i=0;i<8;i++)begin @(posedge clk); tx_in = test_pattern[i]; end @(posedge clk); tx_in = 1'b1; // Stop Bit #CLK_PER*BIT_TIME $finish; end ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值