自动饮料贩卖机

178 阅读4分钟

1 fpga内部的存储器资源

FPGA内部有两种存储器资源,一种是BLOCK RAM,另一种是LUT查找表配置成的内部存储器,也就是分布式RAM。

2 时钟抖动 时钟偏斜

时钟抖动: jitter

由于晶振本身的稳定性,电源以及温度变化等原因造成了时钟频率的变化,相对于理想时钟产生的不随时间积累的,时而超前,时而滞后的偏移。 时钟周期在不同的周期上可能加长或缩短,它是一个平均值为0的平均变量。

时钟偏移:skew

指同样的时钟产生的多个子时钟信号之间的延时差异,skew时钟偏斜通常是时钟相位上的不确定。由于时钟域到达不同寄存器所经历路径的驱动和负载不同,时钟边沿的位置有所差异,因此带来了skew。

3 FPGA对时钟的使用

FPGA芯片有固定的时钟路由,这些路由可以减少时钟抖动和偏差。需要对时钟进行相位移动或者变频时候,一般不允许对时钟进行逻辑操作,这样不仅会增加时钟的偏差和抖动,还会使时钟带上毛刺。 一般的处理方法是采用FPGA芯片自带的时钟管理单元PLL、DLL,或者把逻辑转换为触发器的D输入。

4 查找表的原理和结构

查找表LUT,本质是一个RAM。目前FPGA中多使用4输入的LUT,每一个LUT可以看成4位地址线的16x1的RAM。当用户描述逻辑电路后,FPGA开发软件会自动计算逻辑电路的所有可能的结果,并把结果事先写入RAM,这样每输入一个信号进行逻辑运算就等于输入一个地址进行查表,找出地址对应的内容,然后输出即可。

自动饮料贩卖机

请设计状态机电路,实现自动售卖机功能,A饮料5元钱,B饮料10元钱,售卖机可接收投币5元钱和10元钱,每次投币只可买一种饮料,考虑找零的情况。

电路的接口如下图所示。sel信号会先于din信号有效,且在购买一种饮料时值不变。 sel为选择信号,用来选择购买饮料的种类,sel=0,表示购买A饮料,sel=1,表示购买B饮料; din表示投币输入,din=0表示未投币,din=1表示投币5元,

  • din=2表示投币10元,不会出现din=3的情况;
  • drinks_out表示饮料输出,drinks_out=0表示没有饮料输出,drinks_out=1表示输出A饮料,drinks_out=2表示输出B饮料,不出现drinks_out =3的情况,输出有效仅保持一个时钟周期;
  • change_out表示找零输出,change_out=0表示没有找零,change_out=1表示找零5元,输出有效仅保持一个时钟周期。

接口电路图如下:

image.png 经典三段式状态机,第一段采用同步时序描述状态转移。state<=next_state.第二段采用组合逻辑判断状态转移条件.第三段描述状态输出(这里采用时序电路输出)都可以case语句使用阻塞和非阻塞都行。

****mealy状态机的输出不仅与当前状态值有关,而且与当前输入有关。
moore状态机的输出仅与当前状态值有关,而与此时的输入无关

我们使用mealy型状态机 减少状态数


module sale(
   input                clk   ,
   input                rst_n ,
   input                sel   ,//sel=0,5$dranks,sel=1,10&=$drinks
   input          [1:0] din   ,//din=1,input 5$,din=2,input 10$
 
   output   reg  [1:0] drinks_out,//drinks_out=1,output 5$ drinks,drinks_out=2,output 10$ drinks
   output	reg        change_out   
);
    //两个状态,饮料机空闲和饮料机输出饮料B但只投了五块钱
    //声明状态变量  使用mealy型状态机减少状态数
    reg [1:0]state,next_state;
    parameter IDLE = 2'b01,
    S_Five = 2'b10;
    
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            state <= IDLE;
        else
            state <= next_state;
    always@(*)
        case(state)
            //空闲状态 ,只有在sel为1购买b饮料,且din=1只有5元挑战状态
            IDLE:next_state = sel ? (din == 1 ? S_Five : IDLE) : IDLE;
            //din =0 ,没钱,不跳转状态。有钱就可以跳转空闲,再做判断
            S_Five: next_state = din==0?S_Five:IDLE;
            
            default: next_state = IDLE;
        endcase            
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            drinks_out <= 2'd0;
        // sel为0表示购买A饮料5元,IDLE表示空闲状态。din=1为5元,din=2为10元
        else if(!sel)begin
            if((state == IDLE&&din==1) || (state==IDLE&&din==2))
                drinks_out <= 2'd1;
            else
                drinks_out <= 2'd0;
        end
        // 购买B饮料需要10元
        else begin
            
            if((state == IDLE && din==2)||(state==S_Five&&din==1)||(state == S_Five&&din==2))
                drinks_out <= 2'd2;
            else
                drinks_out <= 2'd0;
        end
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            change_out <= 1'b0;
        //买A饮料输入10元   买B饮料在第二个状态再输入10元
    else if((sel==1'b0&&state==IDLE &&din==2)||(sel&&state==S_Five&&din==2))
            change_out <= 1'b1; 
        else
            change_out <= 1'b0;
    
        
    
    
    
    
    
    
    
    
endmodule
```