IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 数字IC-1.7 状态机学习 -> 正文阅读

[嵌入式]数字IC-1.7 状态机学习

一、定义(大型工程的基石,每个状态代表着一个事件被触发)

共同的:两种状态机,状态跳转只与输入状态有关。?

不同的:在输出时,若最后的输出只和当前状态有关而与输入无关则是moore(木耳)状态机。若最后的输出不仅当前状态有关还与输入也有关则是mealy(米丽)状态机。?

状态转移:从上一个事件发生跳转下一个事件发生。

作用领域:状态机适合描述那些顺序发生,有时序规律的事件。

二、状态转移图(表明状态跳转的条件和先后过程,帮助编写代码逻辑)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 图例

简单例子:可乐机里的饮料3元一瓶。每次只能投一枚一元的硬币,投三个硬币吐出一瓶可乐。用状态机硬件语言实现其功能。

模块引脚设计图

状态转移图绘制:? ( 1/0符号说明:1状态输入 /? 0?状态输出 )?

状态转移三要素

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 输入:?投入1元硬币

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 输出:吐出可乐、不吐出可乐

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 状态:投入0元时、投入1元时、投入2元时、投入3元时

状态转移三要素

????????????????????输入:?投入1元硬币
????????????????????输出:吐出可乐、不吐出可乐
????????????????????状态:投入0元时、投入1元时、投入2元时、投入3元时

状态分析:
? ? ? ? ? ? ? ? ? ? ? ? ? ?* 投入0元时:1、没有投掷,即0/0自身状态不变。2、被投掷了(输入)一枚硬币。即1/0转到下一个1元的状态。
? ? ? ? ? ? ? ? ? ? ? ? ? * 投入1元时:1、没有投掷,即0/0自身状态不变。2、被投掷了(输入)一枚硬币。即1/0转到下一个2元的状态。
? ? ? ? ? ? ? ? ? ? ? ? ? * 投入2元时:1、没有投掷,即0/0自身状态不变。2、被投掷了(输入)一枚硬币。对于mealy型状态机(只当前状态、输入都有关),即此时已经3元硬币了,需要转到下一个0元状态,并且输出一瓶可投入3元时乐,即1/1。 对于moore型状态机(只和当前状态有关,和输入无关),则转向下一个3元状态,并且不吐出可乐,即1/0.
? ? ? ? ? ? ? ? ? ? ? ? ? * 投入3元时(仅moore型状态机):1、此时即使不投硬币也会出可乐,也要转移到下一个状态,因此本状态不存在独立的自环状态。2、需要转移到0元的状态。由于没有投币输入行为,有出可乐输出行为,因此为0/1。3、若在出可乐过程中,又被投入了一枚硬币,此时将要在输出可乐的同时,转移到1元状态,即1/1.

状态机选择:对于本题,由于mealy型状态机(左)比moore型状态机(右)需要的状态更少,代码编写更加方便,因此我们选择mealy型状态机

三、简单状态机VHDL代码

? ? ? ? 代码时序逻辑波形图绘制(设高电平持续一个时钟周期表示投入了一枚硬币)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

代码编写

状态机编码方法分为:?独热码(IDLE = 3'b001? ONE ?= 3'b010? TWO ?= 3'b100)、二进制编码(IDLE = 2'b00? ONE ?= 2'b10? TWO ?= 2'b11)、格雷码(IDLE = 3'b000? ONE ?= 3'b001? TWO ?= 3'b011)。? ? ? ?其中格雷码,是一种错误最小化的?编码方式,因为每个数字之间只有一个二进制位发生改变,且最大值和最小值是头尾相连的。在数字系统中,常要求代码按一定顺序变化。例如,按自然数递增计数,若采用8421码,则数0111变到1000时四位均要变化,而在实际电路中,4位的变化不可能绝对同时发生。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?格雷码示意

注意:本例使用独热码对状态进行编号。因为二进制编码的存储位数虽然最小,但是其占用的组合逻辑资源更多。由于独热码每个状态都单独占一位二进制,因此综合器会优化器组合逻辑资源至一位。而在芯片设计中组合逻辑资源往往比寄存器资源要小的多,因此我们使用独热码形式。

使用情况
? ? ? ? ? ? 设状态个数为D。

? ? ? ? ? ? 当 D < 4,?二进制编码进行状态编码时会使用到联合比较器,可能存在时延稳定问题。
? ? ? ? ? ? 当 D >= 24,状态较多时使用格雷码进行状态编码。
? ? ? ? ? ? 当4 <= D < 24,状态较少时使用独热码进行状态编码。
? ? ? ? ? ? 如果在高速器件中,无论状态数是多少,一般都使用独热码编码。

状态机代码编写形式

? ? ? ? ? ? ?*一段式:?在一段代码中使用时序逻辑即?描述状态的转移,也描述状态的输出。可是这种形式不能描述较为复杂或者大型的状态机。

? ? ? ? ? ? ?*二段式:分两段描写状态机。第一段使用时序逻辑描述状态的转移,第二段使用组合逻辑描述状态的输出。但是面临状态输出时有计数的情况无法适用,因为组合逻辑不允许自加行为。另外,在状态输出时,若使用组合逻辑,会使得信号产生许多毛刺。

? ? ? ? ? ? ?*三段式:分三段描写状态机。第一段使用时序逻辑描述状态的转移,第二段使用组合逻辑判断状态转移条件、描述状态转移规律,第三段使用组合逻辑或者时序逻辑描述状态的输出。

? ? ? ? 上述三种方法是老的方法,编写时必须按照严格的格式践行编写,综合器才能识别其为状态机并生成电路。

? ? ? ? ? *新二段式:分两段描写状态机。第一段使用时序逻辑描述状态的转移和?状态转移条件,第二段同样使用时序逻辑描述状态的输出。这种形式可以直接根据转台转移图写出,并且几乎所有的综合器都能识别它是状态机,因此本例使用这种结构编写。

寄存器传输级文件

`timescale  1ns/1ns

// Project Name  : simple_fsm
// Target Devices: Altera EP4CE10F17C8
// Tool Versions : Quartus 13.0
// Description   : 简单状态机


module  simple_fsm
(
    input   wire    sys_clk     ,   //系统时钟50MHz
    input   wire    sys_rst_n   ,   //全局复位
    input   wire    pi_money    ,   //投币方式可以为:不投币(0)、投1元(1)

    output  reg     po_cola         //po_cola为1时出可乐,po_cola为0时不出可乐
);

/*态机编码方法分为:?
        独热码(IDLE = 3'b001? ONE ?= 3'b010? TWO ?= 3'b100)  
        二进制编码(IDLE = 2'b00? ONE ?= 2'b10? TWO ?= 2'b11)
        格雷码(IDLE = 3'b000? ONE ?= 3'b001? TWO ?= 3'b011)
        
    其中格雷码,是一种错误最小化的?编码方式,因为每个数字之间只有一个二进制位发生改变,
    且最大值和最小值是头尾相连的。在数字系统中,常要求代码按一定顺序变化。
    例如,按自然数递增计数,若采用8421码,则数0111变到1000时四位均要变化,而在实际电路中,
    4位的变化不可能绝对同时发生。
*/

/*
    使用情况:
            设状态个数为D。当 D < 4,?二进制编码进行状态编码时会使用到联合比较器,
            可能存在时延稳定问题。
            当 D >= 24,状态较多时使用格雷码进行状态编码。
            当4 <= D < 24,状态较少时使用独热码进行状态编码。
            如果在高速器件中,无论状态数是多少,一般都使用独热码编码。
             
    注意:
        本例使用独热码对状态进行编号。因为二进制编码的存储位数虽然最小,
    但是其占用的组合逻辑资源更多。由于独热码每个状态都单独占一位二进制,
    因此综合器会优化器组合逻辑资源(比较器)至一位。而在芯片设计中组合逻辑资源往往比
    寄存器资源要小的多,因此我们使用独热码形式。
*/

//parameter define
parameter   IDLE = 3'b001;
parameter   ONE  = 3'b010;
parameter   TWO  = 3'b100;

//reg   define
reg     [2:0]   state; // 存储状态转移的当前状态

//第一段状态机,描述当前状态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

//第二段状态机,描述当前状态state和输入pi_money如何影响po_cola输出
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)) // 因为状态转移图里2元到0元的链接是1/1
        po_cola <= 1'b1;
    else
        po_cola <= 1'b0;

endmodule

仿真测试文件

`timescale  1ns/1ns

// Module Name   : tb_simple_fsm
// Project Name  : simple_fsm
// Target Devices: Altera EP4CE10F17C8N
// Tool Versions : Quartus 13.0
// Description   : 简单状态机仿真文件


module  tb_simple_fsm();

//reg define
reg     sys_clk;
reg     sys_rst_n;
reg     pi_money;

//wire  define
wire    po_cola;

//初始化系统时钟、全局复位
initial begin
    sys_clk    = 1'b1;
    sys_rst_n <= 1'b0;
    #20
    sys_rst_n <= 1'b1;
end

//sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz
always  #10 sys_clk = ~sys_clk;

//pi_money:产生输入随机数,模拟投币1元的情况
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pi_money <= 1'b0;
    else
        pi_money <= {$random} % 2;  //取模求余数,产生非负随机数0、1

//------------------------------------------------------------
//将RTL模块中的内部信号引入到Testbench模块中进行观察
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_inst------------------------
simple_fsm  simple_fsm_inst(
    .sys_clk    (sys_clk    ),  //input     sys_clk
    .sys_rst_n  (sys_rst_n  ),  //input     sys_rst_n
    .pi_money   (pi_money   ),  //input     pi_money

    .po_cola    (po_cola    )   //output    po_cola
);

endmodule

modelsim仿真:

?

?? ? ??

四、进阶状态机VHDL代码

进阶例子:可乐机里的饮料2.5元一瓶。每次能投一枚1元的硬币或者一枚0.5元的硬币,可乐机里的前大于或者等于2.5元时吐出一瓶可乐,若可乐机里为3元则需要吐出一瓶可乐并且找补零钱0.5元。请用状态机硬件语言实现其功能。

模块引脚图:

时序逻辑分析图:

拽他转移示意图:

?

?* 其中 00/00?是指? ?"(00无投币、01投币0.5元、10投币1元) /? ?(00不出可乐不找零钱、 10只出可乐不找零钱、11又出可乐又找0.5元零钱)?"

寄存器传输级文件

`timescale 1ns/1ns
// 复杂例子:可乐机里的饮料2.5元一瓶。每次能投一枚1元的硬币或者一枚0.5元的硬币,
// 可乐机里的前大于或者等于2.5元时吐出一瓶可乐。用状态机硬件语言实现其功能。
module complex_fsm(
    input wire sys_clk,
    input wire res_n,
    input wire money_in_one,
    input wire money_in_half,
    
    output reg cola_out,
    output reg half_out
);

 // 状态机编码:独热码    
    localparam IDLE       = 5'b00001; // 0
    localparam HALF       = 5'b00010; // 0.5
    localparam ONE        = 5'b00100; // 1
    localparam ONE_HALF   = 5'b01000; // 1.5
    localparam TWO        = 5'b10000; // 2

 // 状态追踪变量
    reg [4:0] state;
 
 // 新二段式状态机
 
 // 第一段:状态机转移以及触发条件
    always@(posedge sys_clk or negedge res_n) begin
        if(res_n == 1'b0)
            state <= IDLE;
        else begin
            case(state)
                IDLE : if(money_in_one == 1'b1) state <= ONE;  
                        else if(money_in_half == 1'b1) state <= HALF; 
                        else state <= IDLE;
                HALF  : if(money_in_one == 1'b1) state <= ONE_HALF;  
                        else if(money_in_half == 1'b1) state <= ONE; 
                        else state <= HALF;
                ONE  : if(money_in_one == 1'b1) state <= TWO;  
                        else if(money_in_half == 1'b1) state <= ONE_HALF; 
                        else state <= ONE;
                ONE_HALF : if(money_in_one == 1'b1) state <= IDLE;  
                        else if(money_in_half == 1'b1) state <= TWO; 
                        else state <= ONE_HALF;
                TWO   : if(money_in_one == 1'b1) state <= IDLE;  
                        else if(money_in_half == 1'b1) state <= IDLE; 
                        else state <= TWO;
                default: state <= IDLE;
            endcase
        end
    end
 
 // 第二段:状态输出行为判断、输出
    always@(posedge sys_clk or negedge res_n) begin
        if(res_n == 1'b0)
            cola_out <= 1'b0;
        else begin
            if((state == TWO && money_in_half == 1'b1) || 
               (state == TWO && money_in_one  == 1'b1) ||
               (state == ONE_HALF && money_in_one == 1'b1)) 
                cola_out <= 1'b1;
            else
                cola_out <= 1'b0;
        end
    end
    
    always@(posedge sys_clk or negedge res_n) begin
        if(res_n == 1'b0)
            half_out <= 1'b0;
        else begin
            if(state == TWO && money_in_one  == 1'b1)
                half_out <= 1'b1;
            else
                half_out <= 1'b0;
        end
    end
endmodule

?仿真测试文件

`timescale  1ns/1ns

// Module Name   : tb_complex_fsm
// Project Name  : complex_fsm
// Target Devices: Altera EP4CE10F17C8N
// Tool Versions : Quartus 13.0
// Description   : 复杂状态机仿真文件


module  tb_complex_fsm();

//reg define
reg     sys_clk;
reg     res_n;
reg     money_in_one;
reg     money_in_half;
reg     random_data_gen;

//wire  define
wire    cola_out;
wire    half_out;

//初始化系统时钟、全局复位
initial begin
    sys_clk    = 1'b1;
    res_n <= 1'b0;
    #20
    res_n <= 1'b1;
end

//sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz
always  #10 sys_clk = ~sys_clk;

// 注意:由于money_in_one与money_in_half是互斥的,不能同时为1,因此我们需要另一个信号来同时约束它们输出
//random_data_gen:产生非负随机数0、1
always@(posedge sys_clk or negedge res_n)
    if(res_n == 1'b0)
        random_data_gen <= 1'b0;
    else
        random_data_gen <= {$random} % 2;
        
//money_in_one:产生输入随机数,模拟投币1元的情况
always@(posedge sys_clk or negedge res_n)
    if(res_n == 1'b0 || money_in_half == 1'b1)
        money_in_one <= 1'b0;
    else
        money_in_one <= random_data_gen;  //取模求余数,产生非负随机数0、1
        
//money_in_half:产生输入随机数,模拟投币0.5元的情况
always@(posedge sys_clk or negedge res_n)
    if(res_n == 1'b0)
        money_in_half <= 1'b0;
    else
        money_in_half <= ~random_data_gen;
        
//------------------------------------------------------------
//*******将RTL模块中的内部信号引入到Testbench模块中进行观察*******模块内部过程变量监视方法
wire [4:0] state = tb_complex_fsm_inst.state; // 注意这里的父级引用的是测试生成的新对象文件

initial begin
    $timeformat(-9, 0, "ns", 6);
    $monitor("@time %t: money_one=%b money_half=%b state=%b cola_out=%b half_out=%b",
                $time, money_in_one, money_in_half, state, cola_out, half_out);
end

//------------------------simple_fsm_inst------------------------
complex_fsm  tb_complex_fsm_inst(
    .sys_clk         (sys_clk        ),  //input     sys_clk
    .res_n           (res_n          ),  //input     sys_rst_n
    .money_in_one    (money_in_one   ),  //input     money_in_one
    .money_in_half   (money_in_half  ),  //input     money_in_half

    .cola_out        (cola_out       ),  //output    cola_out
    .half_out        (half_out       )   //output    half_out 
);

endmodule

本教程感谢野火官方教程的支持。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 23:22:24  更:2022-04-06 23:23:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:18:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码