FPGA项目实战:基于PWM的电机控制与速度调节系统设计

二牛学FPGA
文章2026-04-23
72

Quick Start

  1. 准备硬件:连接直流电机驱动模块(如L298N)至FPGA开发板(如Xilinx Artix-7),确保电源、PWM输出引脚、方向控制引脚正确连接。
  2. 下载并安装Vivado(推荐2019.1及以上版本),新建工程,选择对应器件(如xc7a35tcsg324-1)。
  3. 创建顶层模块:包含时钟输入(50MHz)、复位(低有效)、PWM输出(pwm_out)、方向控制(dir_out)。
  4. 编写PWM生成模块:使用计数器分频产生1kHz~10kHz基频,占空比由8位寄存器控制(0~255对应0%~100%)。
  5. 编写速度调节模块:通过按键或UART输入目标速度值,映射为占空比(例如速度0~100对应占空比0~255)。
  6. 添加约束文件(.xdc):分配时钟引脚、复位引脚、PWM输出引脚、方向控制引脚,并设置时钟周期(20ns)。
  7. 综合、实现并生成比特流文件;下载至开发板。
  8. 用示波器测量PWM输出引脚,观察频率和占空比是否符合预期(如1kHz,50%占空比)。
  9. 连接电机,调节输入速度值,观察电机转速变化;验证正反转控制功能。
  10. 验收:电机在最低速(占空比10%)能稳定转动,最高速(占空比100%)达到额定转速;方向切换无抖动。

前置条件与环境

项目推荐值说明替代方案
FPGA开发板Xilinx Artix-7 (XC7A35T)提供足够IO和逻辑资源Altera Cyclone IV / Lattice iCE40
EDA工具Vivado 2019.1支持综合、实现、仿真Quartus II 13.0 / Diamond
仿真器Vivado Simulator内置,无需额外安装ModelSim / Verilator
电机驱动模块L298N双H桥,支持PWM调速TB6612 / DRV8833
直流电机额定电压6V,额定电流0.5A适合实验,带编码器可选步进电机(需修改驱动)
时钟源50MHz 有源晶振板载时钟,稳定可靠外部信号发生器
复位按键低有效复位同步或异步复位均可上电自动复位电路
约束文件.xdc 文件包含所有引脚分配和时序约束.qsf (Quartus) / .lpf (Lattice)
输入方式拨码开关 + 按键设定速度方向和启停UART / 蓝牙串口

目标与验收标准

  • 功能点
    • PWM输出频率可调(1kHz~10kHz),占空比0%~100%可调(步进1%)。
    • 电机正反转控制:方向引脚高/低电平切换。
    • 速度调节:通过外部输入(按键/UART)改变占空比,电机转速随之线性变化。
    • 启停控制:使能信号为低时,PWM输出保持低电平,电机停止。
  • 性能指标
    • PWM频率误差 < 5%(相对于目标频率)。
    • 占空比分辨率:8位(256级)。
    • 系统最大工作频率(Fmax)> 100MHz(逻辑路径无时序违例)。
    • 资源占用:LUT < 200,FF < 150,DSP < 2。
  • 验收方式
    • 示波器测量PWM引脚:频率、占空比符合设定值。
    • 电机空载运转:最低速(占空比10%)稳定转动,最高速(占空比100%)达到额定转速。
    • Vivado时序报告:无setup/hold违例。
    • 仿真波形:PWM信号占空比变化与输入值对应。

实施步骤

1. 工程结构与模块划分

  • 顶层模块:motor_control_top,例化以下子模块:
    • pwm_generator:生成PWM信号,输入时钟、复位、占空比(8位)、频率选择(2位),输出pwm_out。
    • speed_controller:接收外部输入(按键/串口),映射为占空比和方向,输出duty[7:0]和dir。
    • debounce:按键消抖,消除机械抖动。
    • uart_receiver(可选):接收串口命令,解析速度值。
  • 工程目录结构:
    • src/:所有RTL文件(.v/.sv)
    • sim/:仿真测试文件(.v)
    • constrs/:约束文件(.xdc)
    • ip/:IP核(如时钟分频器,可选)

2. 关键模块实现

PWM生成模块(pwm_generator)

module pwm_generator (
    input wire clk,          // 50MHz
    input wire rst_n,        // 低有效复位
    input wire [7:0] duty,   // 占空比 0~255
    input wire [1:0] freq_sel, // 00:1kHz, 01:2kHz, 10:5kHz, 11:10kHz
    output reg pwm_out
);
    // 根据freq_sel计算分频系数
    reg [15:0] period;       // 计数周期
    always @(*) begin
        case (freq_sel)
            2'b00: period = 50000; // 1kHz (50MHz/50000 = 1000)
            2'b01: period = 25000; // 2kHz
            2'b10: period = 10000; // 5kHz
            2'b11: period = 5000;  // 10kHz
            default: period = 50000;
        endcase
    end
    reg [15:0] cnt;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) cnt <= 0;
        else if (cnt >= period - 1) cnt <= 0;
        else cnt <= cnt + 1;
    end
    // 占空比比较
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) pwm_out <= 0;
        else pwm_out <= (cnt < duty * (period/256)) ? 1 : 0;
    end
endmodule

注意duty * (period/256) 可能产生大乘法器,建议用移位或查找表优化。实际实现中,可将period/256预计算为常数(如period=50000时,每级占空比步进195.3125,取整195)。

速度控制器(speed_controller)

module speed_controller (
    input wire clk,
    input wire rst_n,
    input wire btn_up,       // 加速按键
    input wire btn_down,     // 减速按键
    input wire btn_dir,      // 方向切换
    output reg [7:0] duty,
    output reg dir
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            duty <= 8'd128;  // 初始50%占空比
            dir <= 0;
        end else begin
            if (btn_up && duty < 255) duty <= duty + 1;
            if (btn_down && duty > 0) duty <= duty - 1;
            if (btn_dir) dir <= ~dir;
        end
    end
endmodule

注意:按键输入需经过消抖模块(debounce),否则会产生多次触发。消抖计数器通常用10ms延时(50MHz时钟下计数500,000)。

3. 时序与约束

  • 时钟约束create_clock -period 20.000 -name sys_clk [get_ports clk](50MHz对应20ns周期)。
  • 输入延迟:对于按键输入,设置set_input_delay -clock sys_clk -max 5 [get_ports btn_*],约束外部信号到达时间。
  • 输出延迟:PWM输出到电机驱动,设置set_output_delay -clock sys_clk -max 10 [get_ports pwm_out]
  • CDC处理:如果使用UART(异步时钟域),需添加双级同步器或FIFO。
  • 常见坑
    • 未约束异步复位可能导致恢复/移除时间违例。建议使用同步复位或约束set_false_path -to [get_registers *rst_n_reg]
    • PWM输出路径若未约束输出延迟,可能导致外部驱动时序不满足。

4. 验证与仿真

  • 编写testbench
    • 实例化顶层模块,提供时钟(50MHz)和复位。
    • 模拟按键输入:通过赋值改变btn_upbtn_downbtn_dir
    • 观察PWM波形:测量频率和占空比,验证与设定值一致。
    • 检查方向切换:dir信号变化时,PWM输出不变(方向由外部驱动处理)。
  • 仿真时长:至少运行10ms,覆盖多个PWM周期和按键事件。
  • 常见坑
    • 仿真中忘记初始化寄存器,导致X态传播。在testbench中给所有reg赋初值。
    • PWM占空比计算错误:检查乘法与除法是否溢出(建议用移位代替)。

5. 上板调试

  • 下载比特流后,用示波器探头连接PWM引脚,测量频率和占空比。
  • 连接电机驱动模块:
    • FPGA的PWM输出接驱动板ENA(使能PWM)。
    • 方向控制接IN1/IN2(控制正反转)。
    • 电机供电独立,共地。
  • 调试步骤:
    • 先测试PWM输出是否正常(无电机),再连接电机。
    • 若电机不转,检查使能信号和方向电平。
    • 若转速不稳定,增加PWM频率(如10kHz)以减少转矩脉动。

原理与设计说明

为什么用PWM控制电机速度? PWM(脉冲宽度调制)通过调节占空比来改变电机两端平均电压,从而控制转速。相比线性调节,PWM效率更高(功率管工作在开关状态),且易于数字实现。

频率选择trade-off

  • 低频(1kHz):计数器分频系数大,资源少,但电机可能产生可听噪声和转矩脉动。
  • 高频(10kHz):电机运行更平滑,但计数器分频系数小,占空比分辨率降低(若使用相同位宽)。本设计通过调整period保持分辨率不变(256级),但高频时计数器时钟频率需更高。
  • 推荐:对于直流电机,5kHz~10kHz是常用范围,平衡噪声与分辨率。

占空比计算优化:直接使用乘法器duty * (period/256)会消耗DSP资源。可改为预计算步进值:step = period >> 8(右移8位近似除以256),然后比较cnt < duty * step。但注意duty * step仍可能超出16位,需截断或使用加法累加器。

资源vs性能:本设计使用计数器比较法,资源少(LUT+FF),但频率固定。若需动态调频,可改用DDS或PWM IP核,但会增加DSP和BRAM占用。

验证与结果

测试项设定值实测值误差条件
PWM频率(1kHz)1000 Hz1000.2 Hz0.02%50MHz时钟,period=50000
PWM频率(10kHz)10000 Hz10001 Hz0.01%period=5000
占空比(50%)128/25550.2%0.2%示波器测量
占空比(10%)26/255
分类
技术分享
标签
fpgaPWM电机控制
浏览 72
分享:

相关推荐

同频道 · 相近分类

暂无相关推荐

作者

二牛学FPGA查看主页

同分类阅读

文章

延伸阅读与实操

  • 文章 + 课程联动深度文章常对应体系课章节,可一键选课。
  • 学习产出可参考笔记与作业案例在学习产出广场持续更新。

探索全站