自学内容网 自学内容网

FPGA 串口&adc学习笔记

目录

1.在FPGA中实现串口(UART)发送和接收数据通常涉及以下步骤:

2.在FPGA中采集ADC(模数转换器)的数据通常涉及以下步骤:


仿真只会仿top文件,所以需要仿真哪个文件就将该文件设置为top文件

隐式状态机的思想:

我们的整个数据的一个整个系统的完成过程并没有那么明显的一个状态机的跳转

一些信号控制者另一些信号,让他进行一个有规律的一个运行的过程

在这一个时间点的时候给他消隐,在最后的时间点又恢复我们的数据

ADC采集可以被称为二进制数模转换器,也即将模拟信号转换成数字信号。ADC采集电路中的电压,将电压波形通过二进制的方式表现出来 

input信号:

从外界传递到fpga内部的信号

例子:一个按钮的开关状态、温度传感器的读数、来自另一个设备的控制信号等

output信号

从fpga内部传递到外部的信号

[2:0]数据:直接去加总线的数据,若大于等于4,则最高位为1,若小于4,则最高位为0;

100 101 110 111 >= 4

000 001 010 011 < 4

在Verilog中,表达式 `wait_rxd <= {wait_rxd[0], rxd};` 表示将 `wait_rxd[0]` 和 `rxd` 这两个信号进行位拼接(bit concatenation),并将结果赋值给 `wait_rxd`。

这里的 `{}` 是位拼接操作符,它将括号内的信号或值按顺序拼接成一个更宽的位向量。具体来说:

- `wait_rxd[0]` 是一个比特信号,可能是一个寄存器或线网(wire)的一个比特。
- `rxd` 是另一个信号,其位宽可能与 `wait_rxd[0]` 不同。

这个赋值操作会将 `wait_rxd[0]` 放在结果位向量的高位(如果 `wait_rxd` 是单比特信号的话),然后将 `rxd` 的位按顺序放在低位。这样,`wait_rxd` 就变成了一个包含 `wait_rxd[0]` 和 `rxd` 所有位的新信号。

例如,如果 `wait_rxd[0]` 是 `1`,而 `rxd` 是一个8位的信号,比如 `8'b01010101`,那么赋值后的 `wait_rxd` 将是一个9位的信号,值为 `9'b1_01010101`。

这种操作通常用于创建一个包含多个信号的新信号,或者在发送数据时将控制位和数据位组合起来。在这个特定的例子中,可能是为了在数据传输过程中添加一个特定的控制位。

高阻态就是没连信号

添加约束文件之后才能进行下板验证

1.在FPGA中实现串口(UART)发送和接收数据通常涉及以下步骤:

### 串口发送(UART Transmitter)

1. **初始化**:设置串口的波特率、数据位、停止位和奇偶校验位等参数。

2. **数据发送**:
   - 将待发送的数据放入发送数据寄存器。
   - 启动发送状态机,通常是一个状态机,用于控制数据位的发送时序。

3. **波特率生成**:
   - 使用分频器从FPGA的主时钟生成符合所需波特率的串口时钟。

4. **数据位发送**:
   - 按顺序发送数据位,通常从最高位(MSB)开始。

5. **停止位和奇偶校验**:
   - 发送完所有的数据位后,根据配置发送一个或两个停止位。
   - 如果启用了奇偶校验,发送相应的校验位。

6. **发送完成**:
   - 发送完成后,设置一个发送完成标志,以便主控逻辑知道数据已发送完毕。

### 串口接收(UART Receiver)

1. **初始化**:与发送方相同的串口参数设置。

2. **接收准备**:
   - 使能接收器,准备接收数据。

3. **波特率同步**:
   - 使用与发送方相同的波特率时钟来同步接收器。

4. **起始位检测**:
   - 检测到起始位(通常为0)的到来,表示数据即将开始。

5. **数据位接收**:
   - 按顺序接收数据位,通常从最低位(LSB)开始。

6. **奇偶校验和停止位**:
   - 根据配置检查奇偶校验位。
   - 确认停止位的正确性,通常为1。

7. **数据接收完成**:
   - 接收完成后,将接收到的数据存储在接收数据寄存器中。
   - 设置一个接收完成标志,以便主控逻辑可以读取数据。

8. **错误处理**:
   - 如果在接收过程中检测到错误(如奇偶校验错误、帧错误等),设置错误标志。

// 串口发送模块
module uart_tx(
    input wire clk,            // FPGA系统时钟
    input wire rst_n,          // 复位信号
    input wire [7:0] data_in,  // 待发送的数据
    input wire start_tx,       // 发送开始信号
    output wire tx,            // 串口发送线
    output wire tx_done        // 发送完成信号
);
    // 波特率生成和状态机代码...
endmodule

// 串口接收模块
module uart_rx(
    input wire clk,          // FPGA系统时钟
    input wire rst_n,        // 复位信号
    input wire rx,           // 串口接收线
    output reg [7:0] data_out, // 接收到的数据
    output reg rx_done        // 接收完成信号
);
    // 波特率同步和状态机代码...
endmodule

在实际应用中,这些模块需要根据具体的波特率和其他串口参数进行配置,并且可能需要额外的逻辑来处理流控制、缓冲区管理等。此外,还需要编写测试代码来验证串口发送和接收功能的正确性。
 

2.在FPGA中采集ADC(模数转换器)的数据通常涉及以下步骤:

1. **配置ADC接口**:根据ADC的规格和接口协议,使用FPGA的GPIO(通用输入输出引脚)或外设接口模块对ADC进行初始化和配置。这可能包括设置通信协议(如SPI、I2C、并行接口等)的参数,如时钟频率、数据宽度、通信模式等。

2. **设置采样参数**:确定采样率和分辨率等参数,并将其配置到ADC中。这些参数将直接影响到采样的准确性和精度。采样率决定了转换过程中对模拟信号的采样频率,而分辨率则表示了ADC能够表示的不同离散级别的数量。

3. **触发ADC转换**:通过FPGA产生控制信号,如片选(CS)、时钟(SCLK)和数据输入(DIN),以启动ADC的转换过程。在转换过程中,FPGA需要根据ADC的时序要求,正确地产生控制信号。

4. **读取ADC数据**:ADC完成转换后,会将数字信号通过串行或并行接口输出。FPGA需要正确地读取这些数据。如果是串行数据,FPGA可能需要通过一个移位寄存器来逐位读取数据。

5. **数据处理**:采集到的数据可以被FPGA进一步处理,例如进行数字滤波、格式转换或缓存等。

6. **数据传输**:处理后的数据可以通过FPGA的其他接口,如UART、Ethernet等,传输给其他系统或设备。

7. **状态机控制**:在FPGA中,通常使用状态机来控制ADC采集的整个流程,包括初始化、等待转换完成、读取数据等步骤。

FPGA采集ADC数据的流程可能包括使用FIFO缓存来存储采集到的数据,并通过UART发送这些数据。此外,还可能涉及到对ADC芯片的配置,如通道选择、转换使能信号等。在设计时,还需要考虑采样率与分辨率的选择、触发机制的实现以及数据传输的效率。

创建一个完整的Verilog模块来表示FPGA采集ADC数据的过程涉及到多个组件和接口。以下是一个简化的例子,它包括了ADC接口配置、触发ADC转换、读取数据和状态机控制的基本框架。请注意,这只是一个示例,实际应用中可能需要根据具体的ADC芯片和FPGA板进行调整。

```verilog
// ADC采集模块
module adc采集
#(
    parameter DATA_WIDTH = 12, // ADC数据宽度
    parameter CLK_FREQ = 50000000 // FPGA时钟频率,例如50MHz
)
(
    input wire clk,              // FPGA系统时钟
    input wire rst_n,            // 复位信号
    output wire adc_cs_n,        // ADC片选信号
    output wire adc_sclk,        // ADC时钟信号
    output wire [2:0] adc_din,   // ADC数据输入(如果是并行接口)
    input wire [DATA_WIDTH-1:0] adc_dout, // ADC数据输出
    output reg [DATA_WIDTH-1:0] data_out, // 采集到的数据输出
    output reg conv_done         // 转换完成标志
);

// 状态机状态定义
localparam IDLE = 0,
           SAMPLE = 1,
           READ = 2;

reg [1:0] state = IDLE;
reg [31:0] clk_div_counter = 0; // 时钟分频计数器
wire adc_clk; // ADC时钟分频后得到的

// 时钟分频,生成ADC时钟
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clk_div_counter <= 0;
    end else begin
        clk_div_counter <= clk_div_counter + 1;
    end
end
assign adc_clk = (clk_div_counter == (CLK_FREQ/2)); // 假设ADC采样率为FPGA时钟的一半

// ADC片选信号生成
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        adc_cs_n <= 1;
    end else begin
        case (state)
            IDLE: adc_cs_n <= 1;
            SAMPLE: adc_cs_n <= 0;
            default: adc_cs_n <= 1;
        endcase
    end
end

// ADC时钟信号生成
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        adc_sclk <= 0;
    end else begin
        adc_sclk <= adc_clk;
    end
end

// 状态机控制ADC采集流程
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        state <= IDLE;
        conv_done <= 0;
    end else begin
        case (state)
            IDLE: begin
                if (/* 触发条件 */) begin
                    state <= SAMPLE;
                end
            end
            SAMPLE: begin
                // 触发ADC转换
                // ...
                state <= READ;
            end
            READ: begin
                // 读取ADC数据
                data_out <= adc_dout;
                conv_done <= 1; // 设置转换完成标志
                state <= IDLE;
            end
            default: state <= IDLE;
        endcase
    end
end

endmodule
```

请注意,这个代码只是一个框架,它没有包含所有的细节。例如,触发条件、ADC转换触发的具体实现、数据的读取方式(串行或并行)、数据缓存等都需要根据具体的ADC芯片和系统要求来实现。此外,如果ADC是串行接口,还需要实现串行数据的读取和移位逻辑。在实际应用中,可能还需要考虑错误处理、动态配置采样率和分辨率等功能。


原文地址:https://blog.csdn.net/confront66/article/details/142499853

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!