二、16【FPGA】时序逻辑电路设计——有限状态机(FS)

这篇博客详细介绍了使用FPGA进行状态机设计的理论与实战应用,包括可乐机模拟设计案例。内容涵盖状态机的类型、编码方式、设计方法以及代码实现,通过两种不同场景的可乐机模拟,阐述了一段式、二段式和三段式状态机的优缺点,并提供了详细的Verilog代码示例和逻辑仿真相册。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

学习说明此文档为本人的学习笔记,注重实践,关于理论部分会给出相应的学习链接。

学习视频:是根据野火FPGA视频教程——第十九讲
https://www.bilibili.com/video/BV1nQ4y1Z7zN?p=3

理论学习

关于理论学习请参考《数字电子技术基础》相关笔记:

《数字电子技术基础》6.4 时序逻辑电路——设计方法(FSM)有限状态机_追逐者-桥的博客-优快云博客时序逻辑电路设计——有限状态机(FSM)https://blog.youkuaiyun.com/ARM_qiao/article/details/124461906状态机(FSM),也称为同步有限状态机,Mealy型、Moore型状态机(输出与输入无关)

实战演练一

一、设计规划

1.1 实验目标

可乐机每次只能投入1枚1元硬币,且每瓶可乐卖3元钱,投入3个硬币就可以让可乐机出一瓶可乐,如果投币不够3元放弃投币需要按复位键,否则之前的投币不能退回。

二、程序设计

2.1 波形图绘制 

X表示输入:1投入1元硬币,0不投入硬币

Y表示输出:1出可乐,0不出可乐

S0、S1、S2状态:投入0元(初始状态)、投入1元、投入2元、投入3元。

2.2 代码编写 

状态编码定义方式:

在低速系统中

  • 状态机个数 <4个,二进制码
  • 状态机个数 4—24个,独热码
  • 状态机个数 >4个,格雷码

在高速系统中,无论个数均推荐使用独热码。

状态机代码写法有一段式、二段式、三段式:
一段式指的是在一段状态机中使用时序逻辑既描述状态的转移,也描述数据的输出;
二段式指在第一段状态机中使用时序逻辑描述状态转移,在第二段状态机中使用组合逻辑描述数据的输出;
三段式指在第一段状态机中采用时序逻辑描述状态转移,在第二段在状态机中采用组合逻辑判断状态转移条件描述状态转移规律,在第三段状态机中描述状态输出,可以用组合电路输出,也可以时序电路输出。

老的一段式、二段式、三段式各有优缺点,其中一段式在描述大型状态机时会比较困难,会使整个系统显得十分臃肿,不够清晰;二段式状态机的好处是其结构和理想的理论模型完全吻合,即不会有附加的结构存在,比较精简,但是由于二段状态机的第二段是组合逻辑描述数据的输出,所以有一些情况是无法描述的,比如输出时需要类似计数的累加情况,这种情况在组合逻辑中会产生自迭代,自迭代在组合逻辑电路中是严格禁止的,而且第二段状态机主要是描述数据的输出,输出时使用组合逻辑往往会产生更多的毛刺,所以并不推荐。所以衍生出三段式状态机,三段状态机的输出就可是时序逻辑了,但是其结构并不是最精简的了。三段式状态机的第一段状态机是用时序逻辑描述当前状态,第二段 状态机是用组合逻辑描述下一状态,如果把这两个部分进行合并而第三段状态机保持不变,就是我们现在最新的二段式状态机了。这种新的写法在现在不同综合器中都可以被识别出来,这样既消除了组合逻辑可能产生的毛刺,又减小了代码量,还更加容易上手,不必再去关心理论模型是怎样的,仅仅根据状态转移图就非常容易实现。
所以我们习惯性的使用两个均采用时序逻辑的 always 块,第一个 always 块描述状态的转移为第一段状态机,第二个 always 块描述数据的输出为第二段状态机(如果我们遵循一个 always 块只描述一个变量的原则,如果有多个输出时第二段状态机就可以分为多个always 块来表达,但理论上仍属于新二段状态机,所以几段式状态机并不是由 always 块的数量简单决定的)。
module simple_fsm(
    input wire sys_clk,
    input wire sys_rst_n,
    input wire pi_money,
    output reg po_cola
    );
//状态定义,独热码,其他二进制码、格雷码编码(只有一位发生变化,减少毛刺)
    parameter IDLE = 3'b001,
              ONE  = 3'b010,
              TWO  = 3'b100;   
    reg [2:0] state;
//状态机跳转变化
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            state <= IDLE;
        else case(state)
                IDLE: if(pi_money == 1'b1)
                        state <= ONE;
                      else    
                        state <= IDLE;
                ONE: if(pi_money == 1'b1)
                        state <= TWO;
                     else    
                        state <= ONE;      
                TWO: if(pi_money == 1'b1)
                        state <= IDLE;
                    else    
                        state <= TWO; 
                default: state <= IDLE;
            endcase
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            po_cola <= 1'b0;
        else if((state == TWO) && (pi_money == 1'b1))
            po_cola <= 1'b1;
        else 
            po_cola <= 1'b0;    
endmodule

三、逻辑仿真

3.1 仿真代码

`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////
// Company: 追逐者——桥的小作坊
// Create Date: 2022/05/16 15:42:33
// Design Name: 有限状态机
// Module Name: tb_simple_fsm
///////////////////////////////////////////////////////////////////
module tb_simple_fsm();
    reg sys_clk;
    reg sys_rst_n;
    reg pi_money;
    wire po_cola;
    initial begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        #20 
        sys_rst_n <= 1'b1;
    end 
    always #10 sys_clk = ~sys_clk;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            pi_money <= 1'b0;
        else 
            pi_money <= {$random} % 2;
    wire [2:0] state = simple_fsm_inst.state;
    
    initial begin 
        $timeformat(-9, 0, "ns", 6);
        $monitor("@time %t:pi_money=%b, state=%b, po_cola=%b",$time, pi_money, state, po_cola);
    end
    
    simple_fsm simple_fsm_inst(
    .sys_clk  (sys_clk  ),
    .sys_rst_n(sys_rst_n),
    .pi_money (pi_money ),
    .po_cola  (po_cola  )
    );
endmodule

3.2 波形图对比


实战演练二

一、设计规划

1.1 实验目标

可乐机定价为2.5元一瓶,可投入0.5元、1元硬币,投币不够2.5元需要按复位键退回钱款,投币超过2.5元找零。

二、程序设计

2.1 波形图绘制

输入:不投硬币,投入0.5硬币,投入1元硬币

输出:不出可乐/不找零,出可乐/不找零,出可乐/找零

状态:投入0元(初始状态)、投入0.5元、投入1元、投入1.5元、投入2元、投入2.5元、投入3元。

抽象编码:

输入:00,01,10

输出:00,10,11

2.2 代码编写

module complex_fsm(
    input wire sys_clk  ,
    input wire sys_rst_n,
    input wire pi_money_half,
    input wire pi_money_one,
    output reg po_cola,
    output reg po_money
    );
    parameter IDLE  = 5'b00001,
              HALF  = 5'b00010,
              ONE   = 5'b00100,
              ONE_H = 5'b01000,
              TWO   = 5'b10000;
    wire [1:0] pi_money;           //用assign连续赋值语句
    reg  [4:0] state;
    assign pi_money = {pi_money_one, pi_money_half};
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            state <= IDLE;
        else case(state)
                IDLE :  if(pi_money == 2'b01)
                            state <= HALF;
                        else if(pi_money == 2'b10)
                            state <= ONE;
                        else
                            state <= IDLE;
                HALF :  if(pi_money == 2'b01)
                            state <= ONE;
                        else if(pi_money == 2'b10)
                            state <= ONE_H;
                        else
                            state <= HALF; 
                ONE  :  if(pi_money == 2'b01)
                            state <= ONE_H;
                        else if(pi_money == 2'b10)
                            state <= TWO;
                        else
                            state <= ONE; 
                ONE_H:  if(pi_money == 2'b01)
                            state <= TWO;
                        else if(pi_money == 2'b10)
                            state <= IDLE;
                        else
                            state <= ONE_H;
                TWO  :  if((pi_money == 2'b01) || (pi_money == 2'b10))
                            state <= IDLE;
                        else
                            state <= TWO;
                default:  state <= IDLE;
            endcase  
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            po_cola <= 1'b0;  
        else if((stat == ONE_H && pi_money == 2'b10)
              ||(stat == TWO   && pi_money == 2'b01)
              ||(stat == TWO   && pi_money == 2'b10))
            po_cola <= 1'b1;
        else 
            po_cola <= 1'b0;
    always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            po_money <= 1'b0;
        else if((stat == TWO) && (pi_money == 2'b10))
            po_money <= 1'b1;
        else 
            po_money <= 1'b0;            
endmodule

三、逻辑仿真

3.1 仿真代码

`timescale 1ns / 1ns
//////////////////////////////////////////////////////////
// Company: 追逐者——桥的小作坊
// Create Date: 2022/05/16 18:39:18
// Design Name: 复杂可乐鸡
// Module Name: tb_comple_fsm
///////////////////////////////////////////////////////////
module tb_comple_fsm();
    reg sys_clk;
    reg sys_rst_n;
    reg pi_money_half;
    reg pi_money_one;
    wire po_cola;
    wire po_money;

    reg random_data_gen;
    initial begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        #20 
        sys_rst_n <= 1'b1;
    end
    always #10 sys_clk = ~sys_clk;
//由于不能同时投0.5和1元,因此随机数需要统一
    always @(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            random_data_gen <= 1'b0;
        else 
            random_data_gen <= {$random} % 2;
//模拟投币
    always @(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            pi_money_half <= 1'b0;
        else 
            pi_money_half <= random_data_gen;
    always @(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            pi_money_one <= 1'b0;
        else if((({$random}%2)==1'b1) && (pi_money_half==1'b0))
            pi_money_one <= 1'b1;    
        else 
            pi_money_one <= ~random_data_gen; 
            
    wire [4:0] state = complex_fsm_inst.state;
    wire [1:0] pi_money = complex_fsm_inst.pi_money;
    initial begin 
        $timeformat(-9, 0, "ns", 6);
        $monitor("@time %t:pi_money_half=%b, pi_money_one =%b, state=%b, pi_money=%b, po_cola=%b, po_money=%b",$time, 
                    pi_money_half, pi_money_one, state, pi_money, po_cola, po_money);
    end
                
complex_fsm  complex_fsm_inst(
    .sys_clk      (sys_clk      ),
    .sys_rst_n    (sys_rst_n    ),
    .pi_money_half(pi_money_half),
    .pi_money_one (pi_money_one ),
    .po_cola      (po_cola      ),
    .po_money     (po_money     )
    );            
        
endmodule

3.2 波形图对比

 五、总结

一般掌握
1 、学会将 RTL 模块中的内部信号引入到 Testbench 模块中的方法
知识点总结
1 、知道状态机是什么,以及适合它的应用场景;
2 、了解 Moore 型状态机和 Mealy 型状态机的主要区别,以及状态转移图中的差别;
3 、学会根据实际问题抽象出我们设计状态机所必要的输入、输出和状态;
4 、能够根据分析绘制状态转移图,不要遗漏状态,并会化简、合并状态;
5 、能够根据状态转移图画出编写 RTL 代码,编写代码时也要注意一些细节问题,如:如
何进行状态的编码、每种状态编码的特点、我们编写代码的格式、每一段都是做的什么工
作;
6 、学会根据综合器综合的状态转移图和使用 ModelSim 仿真来验证我们状态机的设计;
7 、记住整个状态机的设计流程、方法、技巧,并能够在以后的设计中熟练运用。
<think>嗯,用户让我介绍一下基于FPGA的数字功率源设计。首先,我需要明确用户的需求是什么。他们可能是电子工程专业的学生或者从事相关领域的工程师,想要了解如何利用FPGA来实现数字功率源。可能他们需要知道设计的基本原理、关键模块以及FPGA在其中的优势。 首先,我应该从数字功率源的基本概念开始解释,说明它和传统模拟功率源的区别,比如数字控制带来的灵活性和精确性。然后,FPGA作为核心控制器,它的并行处理能力和可编程性肯定是一个重点。需要提到FPGA在实时性方面的优势,比如PWM信号的生成和反馈控制的高效处理。 接下来,设计架构可能需要分模块讲解。比如主控模块、PWM生成、ADC/DAC接口、通信模块等。每个模块的功能和实现方式需要简要说明,特别是FPGA如何协调这些模块的工作。这里可能需要提到状态或者并行处理的结构,说明FPGA如何同时处理多个任务。 关键技术点方面,PWM调制技术是核心,比如SPWM、SVPWM等,需要解释它们在FPGA中的实现方法。数字闭环控制涉及到PID算法,要说明FPGA如何快速执行这些算法。保护制也是用户关心的,比如过流、过压的保护策略和硬件实现。 然后,设计流程部分需要分步骤,从需求分析到硬件实现,再到验证测试。这里需要强调FPGA开发工具的使用,比如VHDLVerilog编写,仿真测试的重要性,以及如何与实际硬件结合调试。 优势部分,FPGA的高速、灵活、可重构等特点需要突,比较其他方案如DSP或MCU的不足。应用场景可以举一些实际的例子,比如新能源、工业电源等,让用户了解其实际用途。 可能用户没有明确问但需要涵盖的点包括FPGA选型、资源分配、时序控制、电磁兼容等问题。这些在实际设计中会遇到,所以需要简要提及,帮助用户全面了解可能遇到的挑战。 最后,确保整个回答结构清晰,分点明确,语言通俗易懂,避免过于专业的术语堆砌,同时保持技术准确性。需要检查LaTeX格式是否正确,尤其是数学公式的$符号使用,确保符合用户的格式要求。</think>好的,我将分步骤介绍基于FPGA的数字功率源设计,重点说明其核心原理、设计架构和关键技术。 ### 一、基本概念 $$ P_{out} = \frac{V_{rms}^2}{R_{load}} $$ 数字功率源是通过数字信号控制输的可编程电源,相较于传统模拟电源具有以下特点: 1. 采用FPGA实现高速数字信号处理 2. 支持PWM、SPWM等数字调制技术 3. 具备实时反馈调节能力 ### 、系统架构设计 典型系统包含5个核心模块: ``` [输入滤波] → [整流电路] → [FPGA控制器] → [功率逆变] → [输滤波] ↑ ↓ [电压/电流采样] ← [反馈网络] ``` #### 关键模块说明 1. **FPGA主控模块** - 实现PWM波形生成(例:$D = \frac{t_{on}}{T}$ 占空比控制) - 执行数字PID算法:$$ u(k) = K_p e(k) + K_i \sum_{i=0}^k e(i) + K_d [e(k)-e(k-1)] $$ - 管理ADC/DAC接口通信 2. **功率逆变模块** - 常用拓扑:全桥/H桥结构 - 开关频率范围:20kHz-200kHz - 使用IGBT或MOSFET作为开关器件 ### 三、关键技术 1. **PWM调制技术** - SPWM:$V_{ref} = M \cdot \sin(2\pi f t)$(调制比$M$≤1) - SVPWM:提高电压利用率15.47% 2. **数字闭环控制** - 采样周期<10μs - 误差精度:12位ADC可达±0.05% 3. **保护制** - 过流保护:$I_{max} = 1.2I_{rated}$ - 过温保护:结温监测($T_j$≤150℃) ### 四、FPGA实现优势 1. 并行处理能力: - 可同时执行PWM生成、AD采样、保护监测等任务 2. 纳秒级响应: - 保护触发延迟<100ns 3. 灵活重构: - 支持在线更新控制算法 ### 五、设计流程 1. 需求分析: - 确定输电压范围(例:0-300V DC) - 设定功率等级(例:1kW) 2. 算法仿真: - MATLAB/Simulink建模验证 - 蒙特卡洛分析法评估稳定性 3. FPGA开发: ```verilog // PWM生成示例代码 module pwm_gen( input clk, input [7:0] duty, output reg pwm_out ); reg [7:0] counter; always @(posedge clk) begin counter <= counter + 1; pwm_out <= (counter < duty) ? 1&#39;b1 : 1&#39;b0; end endmodule ``` 4. 硬件实现: - 选择Xilinx Zynq或Intel Cyclone系列FPGA - 布局考虑: - 功率地与信号地分离 - 散热设计:每瓦损耗需≥10cm²散热面积 ### 六、典型参数指标 | 项目 | 参数范围 | |-----------|------------| | 输精度 | ±0.1% FS | | 纹波系数 | <0.5% | | 效率 | >92%@满载 | | 谐波失真 | THD<3% | ### 七、应用场景 1. 新能源发电系统并网逆变 2. 电驱动测试电源 3. 电力电子装置老化测试 4. 实验室可编程电源 **设计注意事项:** 1. 电磁兼容设计: - 开关频率避开敏感频段 - 添加RC吸收电路:$R=10Ω$, $C=1nF$ 2. 时序约束: - 保证PWM信号死区时间$t_d$≥100ns 3. 热设计: - 功率器件结温裕量≥25℃ 需要更深入了解某个模块(如数字滤波实现、故障诊断方法等),可以进一步说明具体需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追逐者-桥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值