亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial programming >> VHDL

VHDL 实现 PWM 控制器:设计、仿真与 FPGA 演示

脉宽调制 (PWM) 将数字 FPGA 引脚变为强大的模拟控制器。通过高速切换电源开关,PWM 在从未产生真实模拟电压的情况下,向负载提供所需精确平均电流。

典型 PWM 应用包括扬声器音频输出、LED 调光、控制感应电机转矩,如伺服电机、电脑风扇、水泵、电动汽车无刷直流电机等。

延伸阅读:FPGA 引脚 PWM 实现 RC 舵机控制器

PWM 工作原理

当电源在高频下在 100% 和 0% 间切换,负载看到的时间平均电流与电源导通时间比例成正比。下图说明原理:

VHDL 实现 PWM 控制器:设计、仿真与 FPGA 演示

占空比

占空比定义 PWM 输出每个周期保持高电平的时长。以百分比表示,由二进制计数器值计算:

VHDL 实现 PWM 控制器:设计、仿真与 FPGA 演示

VHDL 实现中将占空比视为无符号整数,获得 PWM 计数器全分辨率。0% 占空比永久关断输出,100% 占空比持续导通。可达分辨率由计数器位宽决定。

将二进制占空比值转百分比,用:

\mathit{duty\_cycle\_percentage} = \frac{\mathit{commanded\_duty\_cycle} * 100}{2^\mathit{pwm\_bits} - 1}

PWM 频率

PWM 频率为周期倒数:

\mathit{pwm\_freq} = \frac{1}{\mathit{pwm\_period}}

选择合适频率取决于目标设备。LED 几百赫兹足避免可见闪烁。无刷直流电机通常工作在数十千赫兹;频率过低产生机械振动,过高浪费功率。

VHDL 实现 PWM 控制器:设计、仿真与 FPGA 演示

因 MOSFET 开关比 FPGA 逻辑慢,PWM 过快会导致晶体管在部分导通态停留,产生额外热量。

PWM 发生器模块

下面是通用 VHDL PWM 控制器实现,可用任意计数器位宽和时钟分频因子实例化。

实体声明

 entity pwm is generic ( pwm_bits : integer; clk_cnt_len : positive := 1 ); port ( clk : in std_logic; rst : in std_logic; duty_cycle : in unsigned(pwm_bits - 1 downto 0); pwm_out : out std_logic ); end pwm; 

clk 和 rst 提供同步控制。duty_cycle 输入宽度由 pwm_bits 定义,计数器分辨率直接可配。pwm_out 信号路由到驱动 MOSFET 栅极的 FPGA 引脚。

内部信号

 signal pwm_cnt : unsigned(pwm_bits - 1 downto 0); signal clk_cnt : integer range 0 to clk_cnt_len - 1; 

pwm_cnt 计数器镜像占空比宽度。clk_cnt 计数器实现可选时钟分频;clk_cnt_len 设为 1 禁用分频并移除相关逻辑。

时钟分频进程

 CLK_CNT_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then clk_cnt <= 0; else if clk_cnt < clk_cnt_len - 1 then clk_cnt <= clk_cnt + 1; else clk_cnt <= 0; end if; end if; end if; end process; 

默认 clk_cnt_len = 1 时,综合工具自动消除此进程。

PWM 输出进程

 PWM_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then pwm_cnt <= (others => '0'); pwm_out <= '0'; else if clk_cnt_len = 1 or clk_cnt = 0 then pwm_cnt <= pwm_cnt + 1; pwm_out <= '0'; if pwm_cnt = unsigned(to_signed(-2, pwm_cnt'length)) then pwm_cnt <= (others => '0'); end if; if pwm_cnt < duty_cycle then pwm_out <= '1'; end if; end if; end if; end if; end process; 

计数器仅在 clk_cnt 为零时递增,有效节流 PWM 频率。在次高值复位 pwm_cnt 的条件保证 100% 占空比可达。

\mathit{pwm\_hz} = \frac{\mathit{clk\_hz}}{(2^\mathit{pwm\_bits} - 1) * \mathit{clk\_cnt\_len}}

顶层设计

为演示 PWM 控制器,设计驱动 Lattice iCEstick FPGA 上的电源指示 LED。板载 12 MHz 振荡器馈送计数器,以锯齿模式驱动 LED 强度。

VHDL 实现 PWM 控制器:设计、仿真与 FPGA 演示

实体声明

 entity pwm_led is generic ( pwm_bits : integer := 8; cnt_bits : integer := 25; clk_cnt_len : positive := 47 ); port ( clk : in std_logic; rst_n : in std_logic; led_1 : out std_logic; led_2 : out std_logic; led_3 : out std_logic; led_4 : out std_logic; led_5 : out std_logic ); end pwm_led; 

12 MHz 时钟和所选泛型产生约 1 kHz PWM 频率:
\frac{12e6}{(2^8 - 1) * 47} \approx 1 \text{ kHz}

cnt_bits 泛型驱动 25 位锯齿计数器控制 LED 占空比。其周期约 2.8 Hz:

\frac{2^{\mathit{cnt\_bits}}}{\mathit{clk\_hz}} = \frac{2^{25}}{12e6} \approx 2.8 \text{ Hz}

仅用 LED 5;其他 LED 拉低避免杂光。

内部信号与连线

 architecture str of pwm_led is signal rst : std_logic; signal cnt : unsigned(cnt_bits - 1 downto 0); signal pwm_out : std_logic; alias duty_cycle is cnt(cnt'high downto cnt'length - pwm_bits); begin led_1 <= '0'; led_2 <= '0'; led_3 <= '0'; led_4 <= '0'; led_5 <= pwm_out; 

rst 为外部复位同步后的非反转版本。别名 duty_cycle 将 cnt 最高位映射到 PWM 控制器。

模块实例化

 RESET : entity work.reset(rtl) port map ( clk => clk, rst_n => rst_n, rst => rst ); PWM : entity work.pwm(rtl) generic map ( pwm_bits => pwm_bits, clk_cnt_len => clk_cnt_len ) port map ( clk => clk, rst => rst, duty_cycle => duty_cycle, pwm_out => pwm_out ); COUNTER : entity work.counter(rtl) generic map ( counter_bits => cnt'length ) port map ( clk => clk, rst => rst, count_enable => '1', counter => cnt ); 

仿真

泛型让仿真加速变易。减小 cnt_bits 和 clk_cnt_len 可在几微秒内观察完整 PWM 周期,而非数秒。

测试平台实例化:

 DUT : entity work.pwm_led(str) generic map ( pwm_bits => 8, cnt_bits => 16, clk_cnt_len => 1 ); 

ModelSim 波形显示锯齿计数器驱动 LED 亮度。占空比达最大值时每周期尖端出现短暂「导通」脉冲。

VHDL 实现 PWM 控制器:设计、仿真与 FPGA 演示

FPGA 实现

iCEcube2 综合后,设计仅消耗 ice40hx1ktq144 器件 64 个 LUT 的 5%:

 Resource Usage Report for pwm_led Mapping to part: ice40hx1ktq144 Cell usage: GND 3 uses SB_CARRY 31 uses SB_DFF 5 uses SB_DFFSR 39 uses SB_GB 1 use VCC 3 uses SB_LUT4 64 uses I/O ports: 7 I/O primitives: 7 SB_GB_IO 1 use SB_IO 6 uses I/O Register bits: 0 Register bits not including I/Os: 44 (3%) Total load per clock: pwm_led|clk: 1 @S |Mapping Summary: Total LUTs: 64 (5%) 

用 Diamond 独立编程器通过 USB 编程 FPGA 很顺利。LED 动画显示平滑亮度渐变后短暂变暗,循环重复。

VHDL 实现 PWM 控制器:设计、仿真与 FPGA 演示

正弦波占空比的呼吸 LED

用正弦波查找表替代锯齿计数器,产生自然「呼吸」效果,常见于通知指示灯。

VHDL 实现 PWM 控制器:设计、仿真与 FPGA 演示

后续文章将展示如何用块 RAM 构建正弦波发生器并集成到 pwm_led 设计中。

阅读下一篇:如何用块 RAM 存储正弦波创建呼吸 LED 效果

延伸阅读:FPGA 引脚 PWM 实现 RC 舵机控制器

VHDL

  1. PWM功率控制器:构建脉宽调制灯驱动器
  2. 电容器充电全攻略:安全高效分步操作指南
  3. VHDL 字符串列表创建:最佳实践与示例
  4. 基于 Tcl 驱动的 VHDL 密码锁模块测试平台
  5. 优雅结束 VHDL 测试平台仿真
  6. VHDL 生成随机数:从均匀分布到 OSVVM
  7. 在块RAM中设计健壮的VHDL环形缓冲区FIFO
  8. 构建VHDL自检测试平台实战指南
  9. 用VHDL受保护类型和访问指针实现动态链表
  10. 利用进程内过程简化VHDL状态机设计
  11. 使用VHDL不纯函数提升FSM可读性与可维护性
  12. 掌握VHDL函数:高效设计实战指南