《基于FPGA的便携式PWM方波信号发生器》论文分析(三)——数码管稳定显示与系统调试
一、论文概述
基于FPGA的便携式PWM方波信号发生器是一篇由任青颖、庹忠曜、黄洵桢、李智禺和张贤宇 等人发表的一篇期刊论文。该论文主要研究了一种新型的信号发生器,旨在解决传统PWM信号发生器在移动设备信号调控中存在的精准度低和便携性差的问题 。其基于现场可编程门阵列(FPGA)技术,设计了一款便携式PWM信号发生器。该设备能够实现占空比以1%的步长可调,频率通过四个按键分别控制实现100 Hz、1 kHz、10 kHz、100 kHz的四个频率脉宽可调的方波信号发生器。系统能够以10 μs的最小分辨率在数码管上进行显示 。对于电子工程和信号处理领域的专业人士提供了一种新的解决方案,有助于提高信号发生器的性能和便携性 。
二、数码管稳定显示
由于脉宽测量过程中所测量的为所在时刻时的测量脉冲个数,其属于始终变化的动态值,若将其直接显示,数码管的数据会以时钟信号的频率进行跳变。为确保数据的稳定与准确,需保证所显示的数据为输出信号下降沿那一刻时的测量信号个数,即需要对测量数据进行稳定处理,其数码管稳定显示电路图如图6所示:
由于FD4CE仅在输入上升沿时工作,将输出信号F进行翻转得到FEI,原有的F下降沿即成了FEI的上升沿,此时的Q0、Q1、Q2、Q3被置为输出信号高电平截止时的测量信号个数,将OUT19至OUT0按照从高位到低位的顺序排序即可实现在数码管上的稳定输出。
四、系统性能调试
依照上述原理搭建可控门电路,对信号产生功能与信号检测功能进行调试检测:先通过占空比按键将占空比调制至所需数据,观察数码管显示;再调制信号频率开关,观察数码管显示;最终调节多信号转换开关,用示波器观察其产生信号,其中50%占空比下脉宽测量实物图如图7所示:
在四种不同频率的情况下,信号发生器的数码管显示均稳定无误。但在实际的加减调控测试过程中,偶尔存在波动一次开关,同时进行多次加减的情况,根据多次测试我们发现:该情况与按键波动速率存在一定关联,拨动速率越快,该情况出现的概率与跳动的幅度越小,反之则越大。
五、问题分析与改善
对便携式信号发生器的所有元器件进行逐一检测,发现占空比跳动的根源在于按键开关自身闭合的不灵敏。当其从低电平置为高电平(即按键操作一次)时,应该仅有一次上升沿,其如图8a所示;但因技术以及操作失误等原因,按键开关在实际操作时存在抖动现象,即在短时间内产生多次上升沿,其如图8b所示:
依照上述设计,可控门电路每捕获一次占空比按键的上升沿,其自身即进行一次相应功能。其中置数功能默认调整至50%,故而在实际操作并无明显变化,而当捕获到多次加减上升沿时,占空比即一次进行多次跳动,即出现了4.1所述之问题。
为尽可能减少此类因硬件自身缺陷,而对便携式信号发生器性能的影响,特对按键信号进行消抖处理,将按键输入的电平信号置于时钟信号之后,保证系统所读取的仅为已稳定后的加减值,其电路设计如图9所示:
FDC作为D型触发器,其与加减信号和置数信号相连,将其延迟一个输入周期信号的周期时间,使模100可逆置数模块无法读取抖动部分的信号电平,从而实现对数控模块的消抖。
六、实际信号检测
将修改后的便捷式信号发生器接入示波器,针对其加减数控开关进行信号测试,将四个频率下的占空比分别调节至30%、50%、70%,其示波器PWM波检测图像如图10所示:
每进行一次“+”“-”按键调控,占空比分别增加或减少1%,上述问题得到完美解决,并由示波器检测数据可知,该便携式PWM信号发生器的输出信号稳定且精准,并没有出现明显失真,且实际性能满足系统电气指标所需,该便携式信号发生器性能良好。
围绕FPGA进行相关电路设计,并根据实物情况进行相关改进,可通过频率按键开关组实现PWM波,并可通过“+”“-”按键与一键置位开关,对占空比进行相关调控。同时,它能够测量自身所产生的信号以及外界输入信号的频率与占空比,并在数码管上的最小分辨率进行显示。经过标准示波器的信号检测可知该便携式PWM信号发生器的输出信号稳定且精准,并没有出现明显失真,具有精度高、便携性好、性能稳定的优点。
七、代码示例分析
此处提供一个基于FPGA的便携式PWM方波信号发生器的示例代码的大致框架和分析。这个示例代码将使用Verilog HDL编写,这是FPGA设计中常用的硬件描述语言。
module PWM_Generator(
input clk, // 时钟信号
input rst_n, // 复位信号,低电平有效
input [15:0] freq, // 频率控制输入
input [15:0] duty, // 占空比控制输入
output reg pwm_out // PWM输出
);
// 定义参数
parameter CLOCK_FREQ = 50_000_000; // FPGA时钟频率
parameter MAX_COUNT = CLOCK_FREQ / 100; // 最大计数器值
// 计数器变量
reg [31:0] counter = 0;
reg [31:0] period = 0;
reg [31:0] high_time = 0;
// 计算周期和高电平时间
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
counter <= 0;
pwm_out <= 0;
end else begin
counter <= counter + 1;
if (counter >= period) begin
counter <= 0;
pwm_out <= ~pwm_out; // 切换输出状态
end
end
end
// 根据频率和占空比更新周期和高电平时间
always @(posedge clk) begin
if (counter == 0) begin
period <= (CLOCK_FREQ / (freq + 1)) - 1; // 计算周期
high_time <= (period * duty) / 100; // 计算高电平时间
end
end
endmodule
为了使基于FPGA的PWM方波信号发生器更加复杂和功能丰富,我们可以考虑添加以下功能:
- 可配置的频率和占空比:允许通过外部输入动态调整频率和占空比。
- 多位频率和占空比控制:使用更多的位数来控制频率和占空比,以提高分辨率。
- 多位输出:生成多个PWM通道,每个通道可以独立控制。
- 同步和异步复位:提供同步和异步复位选项,以提高系统的灵活性和可靠性。
- 死区时间控制:在PWM波形中添加死区时间,以防止短路和电磁干扰。
- 中断和事件标志:在特定的PWM事件(如周期结束)时生成中断或事件标志。
- 可编程输出极性:允许用户选择PWM输出的高电平或低电平为活动电平。
- 动态调整和实时更新:在运行时动态调整频率和占空比,而不需要复位。
以下是一个扩展的示例代码,实现了上述部分功能:
module PWM_Generator_Advanced(
input clk, // 时钟信号
input rst_n, // 复位信号,低电平有效
input sync_rst_n, // 同步复位信号,低电平有效
input [15:0] freq, // 频率控制输入
input [15:0] duty, // 占空比控制输入
input [7:0] channel_enable, // 通道使能控制
output reg [7:0] pwm_out // 多位PWM输出
);
// 定义参数
parameter CLOCK_FREQ = 50_000_000; // FPGA时钟频率
parameter MAX_COUNT = CLOCK_FREQ / 100; // 最大计数器值
// 计数器变量
reg [31:0] counter = 0;
reg [31:0] period = 0;
reg [31:0] high_time = 0;
reg [7:0] high_time_array = 0;
// 动态调整频率和占空比
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
counter <= 0;
pwm_out <= 0;
end else if (!sync_rst_n) begin
counter <= 0;
pwm_out <= 0;
end else begin
counter <= counter + 1;
if (counter >= period) begin
counter <= 0;
pwm_out <= pwm_out << 1; // 左移一位,为下一个通道腾出空间
if (channel_enable & (1 << 0)) pwm_out[0] <= ~pwm_out[0]; // 通道0
if (channel_enable & (1 << 1)) pwm_out[1] <= ~pwm_out[1]; // 通道1
// 继续为其他通道添加逻辑
end
end
end
// 根据频率和占空比更新周期和高电平时间
always @(posedge clk) begin
if (counter == 0) begin
period <= (CLOCK_FREQ / (freq + 1)) - 1; // 计算周期
high_time <= (period * duty) / 100; // 计算高电平时间
high_time_array <= high_time; // 更新高电平时间数组
end
end
// 动态调整频率和占空比
always @(posedge clk) begin
if (counter == 0) begin
period <= (CLOCK_FREQ / (freq + 1)) - 1;
high_time <= (period * duty) / 100;
for (int i = 0; i < 8; i++) begin
if (channel_enable & (1 << i)) begin
high_time_array[i] <= (period * duty) / 100;
end
end
end
end
endmodule
这个扩展的示例代码提供了一个更复杂的PWM信号发生器,支持多位输出和动态调整频率和占空比。在实际应用中,可以根据具体需求进一步扩展和优化。
module Advanced_PWM_Generator(
input wire clk, // 主时钟
input wire rst_n, // 异步复位
input wire sync_rst_n, // 同步复位
input wire [15:0] freq, // 频率控制输入
input wire [15:0] duty, // 占空比控制输入
input wire [15:0] phase, // 相位控制输入
input wire [15:0] dead_time, // 死区时间控制输入
input wire [7:0] channel_enable, // 通道使能控制
output reg [7:0] pwm_out // 多位PWM输出
);
// 定义参数
parameter CLOCK_FREQ = 50_000_000; // FPGA时钟频率
parameter MAX_COUNT = CLOCK_FREQ / 100; // 最大计数器值
// 内部变量
reg [31:0] counter = 0;
reg [31:0] period = 0;
reg [31:0] high_time = 0;
reg [31:0] low_time = 0;
reg [31:0] dead_count = 0;
reg [31:0] ramp_up = 0;
reg [31:0] ramp_down = 0;
reg [7:0] pwm_state = 0;
// 计算周期、高电平时间和低电平时间
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
counter <= 0;
pwm_out <= 0;
pwm_state <= 0;
end else if (!sync_rst_n) begin
counter <= 0;
pwm_state <= 0;
end else begin
counter <= counter + 1;
case (pwm_state)
0: begin // 斜坡上升
if (counter < ramp_up) pwm_out <= pwm_out | (1 << pwm_state);
else begin
pwm_state <= pwm_state + 1;
counter <= 0;
end
end
1: begin // 高电平
if (counter < high_time) ;
else begin
pwm_state <= pwm_state + 1;
counter <= 0;
end
end
2: begin // 死区时间
if (counter < dead_time) ;
else begin
pwm_state <= pwm_state + 1;
counter <= 0;
end
end
3: begin // 低电平
if (counter < low_time) ;
else begin
pwm_state <= pwm_state + 1;
counter <= 0;
end
end
4: begin // 斜坡下降
if (counter < ramp_down) pwm_out <= pwm_out & ~(1 << (pwm_state - 1));
else begin
pwm_state <= 0;
counter <= 0;
end
end
default: pwm_state <= 0;
endcase
end
end
// 根据频率、占空比、相位和死区时间更新周期、高电平时间和低电平时间
always @(posedge clk) begin
if (counter == 0) begin
period <= (CLOCK_FREQ / (freq + 1)) - 1;
high_time <= (period * duty) / 100;
low_time <= period - high_time - dead_time;
ramp_up <= (high_time * phase) / 100;
ramp_down <= (low_time * phase) / 100;
dead_count <= dead_time;
end
end
endmodule
这个示例代码提供了一个高度复杂的PWM信号发生器,支持多位输出、相位控制、死区时间和斜坡控制。