FPGA通过IO 接受风扇FG信号,并输出25MHz PWM信号控制风扇定转速。
参考:
详解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值,并作图显示。