FPGA PID控制风扇

FPGA通过IO 接受风扇FG信号,并输出25MHz PWM信号控制风扇定转速。

参考:

http://t.csdnimg.cn/egL0V

详解FPGA的串口通讯(UART) | FPGA 开发圈 (eetrend.com)

PID控制器模块

输入为目标值、实际测量值(FG信号),输入为控制信号。

module pid_controller (
    input wire clk,
    input wire rst,
    input wire [31:0] setpoint,      // 目标转速
    input wire [31:0] measured,      // 实际转速
    output reg [31:0] control_signal // 控制信号输出 (占空比)
);

    // PID 参数 (定点数表示)
    parameter signed [31:0] Kp = 32'd327680;   // 5.0  (定点数表示:327680 = 5.0 << 16)
    parameter signed [31:0] Ki = 32'd1310;     // 0.02 (定点数表示:1310 = 0.02 << 16)
    parameter signed [31:0] Kd = 32'd6554;     // 0.1  (定点数表示:6554 = 0.1 << 16)

    reg signed [31:0] error;
    reg signed [31:0] integral;
    reg signed [31:0] derivative;
    reg signed [31:0] previous_error;

    always @(posedge clk or posedge rst) begin
        if (rst) begin
            integral <= 32'd0;
            previous_error <= 32'd0;
            control_signal <= 32'd0;
        end else begin
            // 计算误差
            error <= setpoint - measured;

            // 积分项
            integral <= integral + error;

            // 微分项
            derivative <= error - previous_error;

            // PID 输出控制信号
            control_signal <= (Kp * error + Ki * integral + Kd * derivative) >>> 16;

            // 保存当前误差用于下次计算微分项
            previous_error <= error;
        end
    end
endmodule

PMW生成模块

输入为占空比,输出PWM

module pwm_generator (
    input wire clk,
    input wire rst,
    input wire [31:0] duty_cycle, // 占空比 (从 PID 控制器输出)
    output reg pwm_out            // PWM 输出信号
);

    reg [31:0] counter;

    always @(posedge clk or posedge rst) begin
        if (rst) begin
            counter <= 32'd0;
            pwm_out <= 1'b0;
        end else begin
            if (counter < duty_cycle)
                pwm_out <= 1'b1;
            else
                pwm_out <= 1'b0;

            counter <= counter + 1;
            if (counter >= 32'd50000000) // 50 MHz 时钟周期
                counter <= 32'd0;
        end
    end
endmodule

FG信号通过等精度测量法进行频率采样。

输入为经过LM393电压比较器模块处理后的FG信号。输出为采样频率。

module fg_frequency_measure(
    input wire clk,              // 时钟信号
    input wire rst,              // 复位信号
    input wire fg_signal,        // FG 输入信号
    output reg [31:0] frequency  // 测量到的频率
);

    reg [31:0] period_counter = 32'd0;  // 用于测量周期的计数器
    reg [31:0] cycle_count = 32'd0;     // 统计周期数量
    reg [31:0] total_cycles = 32'd100;  // 累积多少个周期进行测量

    reg fg_prev = 1'b0;  // 上一个 FG 信号状态

    always @(posedge clk or posedge rst) begin
        if (rst) begin
            period_counter <= 32'd0;
            cycle_count <= 32'd0;
            frequency <= 32'd0;
        end else begin
            // 检测 FG 信号的上升沿
            if (fg_signal && ~fg_prev) begin
                cycle_count <= cycle_count + 1;
                if (cycle_count >= total_cycles) begin
                    // 计算频率
                    frequency <= (32'd100_000_000 * total_cycles) / period_counter;
                    period_counter <= 32'd0;
                    cycle_count <= 32'd0;
                end
            end
            period_counter <= period_counter + 1;
            fg_prev <= fg_signal;
        end
    end
endmodule

通过串口接受上位机发送的 开始和停止中断命令控制风扇启停,并向上位机返回RPM和Duty。

  • 0x01 表示启动风扇
  • 0x02 表示停止风扇
module uart_receiver (
    input wire clk,
    input wire rst,
    input wire rx,                   // 接收信号
    output reg [31:0] target_rpm,    // 接收到的目标转速
    output reg fan_enable            // 风扇启停信号
);

    reg [7:0] rx_data;
    reg [3:0] rx_bit_count;
    reg [31:0] rx_shift_reg;

    always @(posedge clk or posedge rst) begin
        if (rst) begin
            rx_bit_count <= 4'd0;
            target_rpm <= 32'd0;
            fan_enable <= 1'b0;      // 默认风扇停止
        end else begin
            // UART 接收处理逻辑
            if (/* 接收到新字节 */) begin
                rx_data <= {rx_data[6:0], rx};
                rx_bit_count <= rx_bit_count + 4'd1;
                if (rx_bit_count == 4'd7) begin
                    if (rx_data == 8'h01) begin
                        fan_enable <= 1'b1;  // 启动风扇
                    end else if (rx_data == 8'h02) begin
                        fan_enable <= 1'b0;  // 停止风扇
                    end else begin
                        rx_shift_reg <= {rx_shift_reg[23:0], rx_data};  // 接收目标转速
                        if (rx_bit_count == 4'd31) begin
                            target_rpm <= rx_shift_reg; // 更新目标转速
                        end
                    end
                    rx_bit_count <= 4'd0;
                end
            end
        end
    end
endmodule

 

module uart_transmitter (
    input wire clk,
    input wire rst,
    input wire [31:0] rpm,            // 当前风扇转速
    input wire [15:0] duty_cycle,     // 当前占空比
    output reg tx                     // 发送信号
);

    reg [31:0] tx_shift_reg;
    reg [3:0] tx_bit_count;
    reg sending;
    reg [31:0] timer;                 // 定时器用于定期发送数据

    always @(posedge clk or posedge rst) begin
        if (rst) begin
            tx_bit_count <= 4'd0;
            sending <= 1'b0;
            tx <= 1'b1;                // 默认高电平空闲
            timer <= 32'd0;
        end else begin
            // 每隔0.5秒定期发送
            if (timer >= 32'd25000000) begin
                tx_shift_reg <= {rpm, duty_cycle}; // 拼接发送数据
                sending <= 1'b1;
                timer <= 32'd0;
            end else begin
                timer <= timer + 1;
            end

            // UART 发送处理逻辑
            if (sending) begin
                tx <= tx_shift_reg[31];
                tx_shift_reg <= tx_shift_reg << 1;
                tx_bit_count <= tx_bit_count + 4'd1;
                if (tx_bit_count == 4'd31) begin
                    sending <= 1'b0;
                end
            end
        end
    end
endmodule

RPM计算模块

module rpm_calculator (
    input wire clk,
    input wire rst,
    input wire fg_signal,           // 来自风扇的 FG 信号
    output reg [31:0] rpm           // 计算得到的 RPM
);

    parameter p = 2;                // 风扇的极对数
    reg [31:0] fg_count;
    reg [31:0] clk_count;
    reg [31:0] rpm_calc;

    always @(posedge clk or posedge rst) begin
        if (rst) begin
            fg_count <= 32'd0;
            clk_count <= 32'd0;
            rpm <= 32'd0;
        end else begin
            // 计算 FG 信号脉冲数和时钟周期
            if (fg_signal) begin
                fg_count <= fg_count + 1;
            end
            clk_count <= clk_count + 1;

            // 闸门时间0.5秒
            if (clk_count >= 32'd25000000) begin
                rpm_calc <= (fg_count * 60) / p;
                rpm <= rpm_calc;
                fg_count <= 32'd0;
                clk_count <= 32'd0;
            end
        end
    end
endmodule

 

顶层模块 

module fan_control_system (
    input wire clk,
    input wire rst,
    input wire rx,                   // 来自上位机的接收信号
    output wire tx,                  // 发送给上位机的发送信号
    output wire pwm_out,             // 控制风扇的 PWM 信号
    input wire fg_signal             // 来自风扇的 FG 信号
);

    wire [31:0] target_rpm;
    wire [31:0] current_rpm;
    wire [15:0] duty_cycle;
    wire [31:0] control_signal;
    wire fan_enable;

    // PID 控制器实例化
    pid_controller pid_inst (
        .clk(clk),
        .rst(rst),
        .setpoint(target_rpm),
        .measured(current_rpm),
        .control_signal(control_signal)
    );

    // PWM 生成模块实例化
    pwm_generator pwm_inst (
        .clk(clk),
        .rst(rst),
        .duty_cycle(fan_enable ? control_signal : 32'd0), // 控制信号与风扇启停控制
        .pwm_out(pwm_out)
    );

    // UART 接收模块实例化
    uart_receiver uart_rx_inst (
        .clk(clk),
        .rst(rst),
        .rx(rx),
        .target_rpm(target_rpm),
        .fan_enable(fan_enable)      // UART 中断控制风扇启停
    );

    // UART 发送模块实例化
    uart_transmitter uart_tx_inst (
        .clk(clk),
        .rst(rst),
        .rpm(current_rpm),
        .duty_cycle(duty_cycle),
        .tx(tx)
    );

    // 风扇转速计算模块实例化
    rpm_calculator rpm_inst (
        .clk(clk),
        .rst(rst),
        .fg_signal(fg_signal),
        .rpm(current_rpm)            // 输出转速
    );

endmodule

后续设计:使用QT软件,通过UART串口给FPGA发送目标转速和启动、停止中断命令。FPGA通过串口返回RPM和Duty值,并作图显示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值