FPGA—可乐机拓展训练题(状态机)

news2024/12/24 2:22:02

      题目:以可乐机为背景,一瓶可乐的价格还是 2.5 元。用按键控制投币(加入按键消抖功能),可以投 0.5 元硬币和 1 元硬币,投入 0.5 元后亮一个灯,投入 1 元后亮 2 个灯,投入 1.5 元后亮 3 个灯,投入 2 元后亮 4 个灯,如果投币后 10s 不再继续进行投币操作则可乐机回到初始状态。投入 2.5 元后出可乐不找零,此时 led 灯实现单向流水操作,流水10s后自动停止;投入 3 元后出可乐找零,此时 led 灯实现双向流水操作,流水 10s 后自动停止。有复位键,其功能是终止本次投币操作,使可乐机立刻回到初始状态。

   套用三要素法来分析:

输入:不投币、投入 0.5 元硬币、投入 1 元硬币;

输出:不出可乐/不找零、出可乐/不找零、出可乐/找零;

状态:可乐机中有 0 元、可乐机中有 0.5 元、可乐机中有 1 元、可乐机中有 1.5 元、可乐机中有 2 元、可乐机中有 2.5 元、可乐机中有 3 元。

1. 模块框图

2. 状态转换图

3. RTL代码

3.1 按键消抖部分

       实现按键消抖,注意有两个输入故调用两次。效果为当检查到按键被按下后,输出的key_flag被拉高一个时钟,作为标志信号输入给下一个模块。

`timescale  1ns/1ns

module  key_filter
#(
    parameter CNT_MAX = 20'd999_999 
)
(
    input   wire    sys_clk     ,   
    input   wire    sys_rst_n   ,   
    input   wire    key_in      ,   

    output  reg     key_flag        
                                    
);

reg     [19:0]  cnt_20ms    ;   //计数器

//cnt_20ms:如果时钟的上升沿检测到外部按键输入的值为低电平时,计数器开始计数
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_20ms <= 20'b0;
    else    if(key_in == 1'b1)
        cnt_20ms <= 20'b0;
    else    if(cnt_20ms == CNT_MAX && key_in == 1'b0)
        cnt_20ms <= cnt_20ms;
    else
        cnt_20ms <= cnt_20ms + 1'b1;

//key_flag:当计数满20ms后产生按键有效标志位
//且key_flag在999_999时拉高,维持一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        key_flag <= 1'b0;
    else    if(cnt_20ms == CNT_MAX - 1'b1)
        key_flag <= 1'b1;
    else
        key_flag <= 1'b0;

endmodule

3.2 complex_fsm部分

        实现随着状态切换后小灯的各种显示效果。注意影响状态切换的条件除了投币还有10s有效时间。使用两类均采用时序逻辑的 always 块,第一类 always 块描述状态(state)的转移为第一段状态机,第二类 always 块描述数据的输出为第二段状态机,所以写状态机一般则采用两段式。

       总结一下套用的格式有哪些主要部分构成:第一部份端口列表部分; 第二部份状态编码部; 第三部份是定义的状态变量; 第四部份分为第一段状态机和第二段状态机。一共有四部分,写状态机代码的时候根据这种格式依次编写,非常容易的就可以实现。

`timescale  1ns/1ns

module  complex_fsm
#(
    parameter   CNT_MAX  = 25'd24_999_999,       //0.5s定时器计时
    parameter   CNT_KEY = 20'd999_999            //20ns按键稳定状态
)
(
    input   wire         sys_clk         ,   
    input   wire         sys_rst_n       ,   
    input   wire         pi_money_one    ,   //投币1元
    input   wire         pi_money_half   ,   //投币0.5元
                         
    output  reg   [3:0]  led
);

//只有七种状态,使用独热码                        
parameter   IDLE     = 7'b0000001;
parameter   HALF     = 7'b0000010;
parameter   ONE      = 7'b0000100;
parameter   ONE_HALF = 7'b0001000;
parameter   TWO      = 7'b0010000;   
parameter   TWO_HALF = 7'b0100000;
parameter   THREE    = 7'b1000000;               

reg     [6:0]   state  ;

reg     [3:0]   led_a  ;
reg     [3:0]   led_b  ;
reg     [3:0]   led_c  ;

reg     [24:0]  cnt    ;
reg     [4:0]   cnt_10s = 5'd21;

reg             move   ;

reg     po_money     ;                     
reg     po_cola      ;
                              
wire    [1:0]   pi_money;
wire            po_money_half;
wire            po_money_one ;

wire            cola_flag;                 

//pi_money:为了减少变量的个数,用 位拼接 把输入的两个1bit信号拼接成1个2bit信号
//投币方式可以为:不投币(00)、投0.5元(01)、投1元(10),每次只投一个币
assign pi_money = {po_money_one, po_money_half};

//满足出可乐条件的所有情况
assign  cola_flag = (state == TWO && pi_money == 2'b01) || (state == TWO && 
          pi_money == 2'b10) || (state == ONE_HALF && pi_money == 2'b10);
		  
//第一段状态机,当前状态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 == 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_HALF;
                          else  if(cnt_10s == 5'd20)
                              state <= IDLE;
    
                ONE     : if(pi_money == 2'b01)
                              state <= ONE_HALF;
                          else    if(pi_money == 2'b10)
                              state <= TWO;
                          else  if(cnt_10s == 5'd20)
                              state <= IDLE;
    
                ONE_HALF: if(pi_money == 2'b01)
                              state <= TWO;
                          else    if(pi_money == 2'b10)
                              state <= TWO_HALF;
                          else  if(cnt_10s == 5'd20)
                              state <= IDLE;
    
                TWO     : if(pi_money == 2'b01)
                              state <= TWO_HALF;
                          else   if(pi_money == 2'b10)
                              state <= THREE;
                          else  if(cnt_10s == 5'd20)
                              state <= IDLE;
    
                TWO_HALF: if(cnt_10s == 5'd20)    //10秒没有投币     
                              state <= IDLE;
                          else if(pi_money == 2'b01)  //继续投币 0.5元
                              state <= HALF;
						  else if(pi_money == 2'b10)  //继续投币 1元
						      state <= ONE;
					     
      
                THREE   : if(cnt_10s == 5'd20)     //10秒没有投币 
                              state <= IDLE;
                          else if(pi_money == 2'b01)  //继续投币 0.5元
                              state <= HALF;
						  else if(pi_money == 2'b10)  //继续投币 1元
						      state <= ONE;
							  
                default :     state <= IDLE;
            endcase

//第二段状态机,cnt:计数器计数 500ms
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt <= 25'b0;
    else if(cnt == CNT_MAX)
        cnt <= 25'b0;
    else if(cnt_10s != 5'd21)     //开始计时
        cnt <= cnt + 1'b1;
//第二段状态机,10s计数器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_10s <= 5'd21;
    else    if((pi_money != 2'd0)  //开始计时
        cnt_10s <= 5'd0;
    else    if(cnt == CNT_MAX)
        cnt_10s <= cnt_10s + 1'b1;
    else    if(cnt_10s == 5'd20)
        cnt_10s <= 5'd0 ;
//第二段状态机,led_a:投币控制led状态
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        led_a <= 4'b1111;
    else    if(state == TWO)
        led_a <= 4'b0000;
    else    if(state == ONE_HALF)
        led_a <= 4'b0001;
    else    if(state == ONE)
        led_a <= 4'b0011;
    else    if(state == HALF)
        led_a <= 4'b0111;
    else    if(state == IDLE)
        led_a <= 4'b1111;	
//第二段状态机,led_b:led 单向循环流水
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        led_b <= 4'b0001;
    else if(led_b == 4'b1000 && cnt == CNT_MAX)
        led_b <= 4'b0001;
    else if(cnt == CNT_MAX)
        led_b <= led_b << 1'b1; //左移  
//第二段状态机,led_c:led双向循环流水
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        led_c <=  4'b0001;
    else    if(move == 1'b0 && cnt == CNT_MAX)
        led_c <= led_c  >>1'b1; //右移
    else    if(move == 1'b1 && cnt == CNT_MAX)
        led_c <= led_c  <<1'b1; //左移
    else
        led_c <= led_c ;
//led循环流水使能信号
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        move <= 1'b0;
    else    if(led_c == 4'b1000)
        move <= 1'b0;
    else    if(led_c == 4'b0001)
        move <= 1'b1;
		
//根据状态机控制led状态
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        led <= 4'b1111;
    else    if((state == THREE)&&(cnt_10s != 5'd20))
        led <= led_c;
    else    if((state == TWO_HALF)&&(cnt_10s != 5'd20))
        led <= led_b;
    else   
        led <=~led_a;
		
//第二段状态机,描述当前状态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(cola_flag == 1'b1)
        po_cola <= 1'b1;
    else
        po_cola <= 1'b0;
//第二段状态机,描述当前状态state和输入pi_money如何影响po_money输出
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n ==	1'b0)
        po_money <= 1'b0;
    else if((state == TWO) && (pi_money == 2'b10))
        po_money <= 1'b1;
    else
        po_money <= 1'b0;

		
//分别调用两个按键模块
key_filter
#(
    .CNT_MAX(CNT_KEY)
)
key_filter_inst1
(
    .sys_clk   (sys_clk         ),
    .sys_rst_n (sys_rst_n       ),
    .key_in    (pi_money_half   ),

    .key_flag  (po_money_half   )   
);
key_filter
#(
    .CNT_MAX(CNT_KEY)
)
key_filter_inst2
(
    .sys_clk   (sys_clk     ),
    .sys_rst_n (sys_rst_n   ),
    .key_in    (pi_money_one),

    .key_flag  (po_money_one)         

);
endmodule

5. 总结

1. 编写状态机的步骤,格式。

2. 如何绘制状态转换图,抓住“三要素”。

3. 处理LED输出按显示效果分类后输出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/563787.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【统计模型】学生课程类型选择影响因素分析

目录 学生课程类型选择影响因素分析 一、研究目的 二、数据来源和相关说明 三、描述性分析 3.1 样本描述 3.2 样本可视化 3.2.1 直方图 3.2.2 列联表 3.2.3 箱线图与折线图 3.2.4 相关性热力图 四、数学建模 4.1 无序多分类logistic回归模型 4.1.1 无序多分类logist…

STM32F030C8T6最小系统板和流水灯(原理图和PCB)

STM32F030C8T6最小系统板和流水灯。 嵌入式课的课程设计&#xff0c;要做个流水灯&#xff0c;我就顺便画个最小系统板&#xff0c;开源出来了&#xff0c;各位大佬指点指点&#xff0c;有哪里需要优化改进的。 那个WS2812的RGB灯用错引脚了&#xff0c;所以没法用PWM来控制&…

MQTT GUI 客户端 可视化管理工具

MQTT GUI 客户端 可视化管理工具 介绍 多标签页管理&#xff0c;同时打开多个连接提供原生性能&#xff0c;并且比使用 Electron 等 Web 技术开发的同等应用程序消耗的资源少得多支持 MQTT v5.0 以及 MQTT v3.1.1 协议&#xff0c;支持通过 WebSocket 连接至 MQTT 服务器以树…

数字信号处理7

昨天着重就是离散时间系统的复习&#xff0c;包括离散时间系统的分类有哪些&#xff0c;是根据什么进行分类的&#xff0c;要搞清楚&#xff0c;LTI系统是一个什么样的系统&#xff0c;以及卷积的操作&#xff0c;因果LTI等&#xff0c;回顾完这些之后&#xff0c;就开始了今天…

Python面向对象编程详细解析(都带举例说明!)

前言 Python面向对象编程&#xff08;Object-Oriented Programming&#xff0c;简称OOP&#xff09;是一种编程范式&#xff0c;它将数据和操作数据的方法封装在一起&#xff0c;形成一个对象。 Python中的面向对象编程包括以下内容&#xff1a; 目录点击对应章节可直接跳转…

数据治理项目易失败?企业数据治理的解决思路在这里

据Gartner 的一项调查显示&#xff0c;我国超过90%的数据治理项目都失败了。大家的感受也是如此&#xff1a;数据治理的项目不好落地&#xff0c;数据治理项目实施起来从理论到实践有一条巨大的鸿沟很难跨越。 失败的原因各种各样&#xff0c;总结起来大概有4类&#xff1a; …

编译原理个人作业--第六章——基于 编译原理 国防工业出版社 第三版

2 对表达式((a)(b)) (1) 按照表6.4属性文法构造抽象语法树 (2) 按6.17翻译模式构造表达式抽象语法树 5(1) 下列文法对整型常数、实型常熟世家加法运算符 生成表达式&#xff0c;当两个整型数相加&#xff0c;结果为整形&#xff0c;否则结果为实型 E → E T ∣ T E\r…

软件测试面试题

一、描述 TCP/IP 协议的层次结构&#xff0c;以及每一层中重要协议 TCP/IP&#xff08;Transmission Control Protocol/Internet Protocol&#xff09;是互联网的核心协议套件&#xff0c;它定义了在网络中进行通信的规则和标准。TCP/IP协议栈按照层次结构划分&#xff0c;每一…

【DataTable.js】DataTable基础应用

一、简介 DataTables是一个功能强大的Javascript库&#xff0c;用于向HTML表中添加交互特性&#xff0c;虽然简单性是整个项目的核心设计原则&#xff0c;但一开始可能会让人望而生畏。然而&#xff0c;采取这些第一步&#xff0c;让DataTables在你的网站上运行实际上是相当直…

测试——四元数绕轴旋转

float angle 40;Vector3 v rotatePoint.transform.position;Debug.Log("旋转向量 " v "__自身 " cube.transform.rotation);v.Normalize();Debug.Log(v);float f angle * Mathf.Deg2Rad / 2;float sinHalfAngle Mathf.Sin(f);float cosHalfAngle M…

智慧梁场3D建模

智慧梁场3D建模&#xff1a;数字化革命下的新起点 ​ 随着科技的迅猛发展&#xff0c;数字化已经成为了现代工业生产的必然趋势。作为传统工业的核心产业&#xff0c;建筑行业也在不断地探索数字化变革的新路径。而“智慧梁场3D建模”便是其中的一项杰出实践。 ​ 梁场是建筑…

FreeRTOS:系统内核控制函数

目录 前言一、内核控制函数预览二、内核控制函数详解2.1强制上下文切换宏2.2临界区2.3可屏蔽中断2.4调度器2.5调整系统节拍 前言 FreeRTOS 中有一些函数只供系统内核使用&#xff0c;用户应用程序一般不允许使用&#xff0c;这些 API 函 数就是系统内核控制函数。内核控制的一…

【iOS】—— iOS中的相关锁

文章目录 自旋锁1.OSSpinLock2.os_unfair_lock3.atomic 互斥锁pthread_mutexsynchronizedobjc_sync_enterobjc_sync_exit注意事项 NSLockNSRecursiveLock信号量条件锁NSConditionNSConditionLock 读写锁总结 锁作为一种非强制的机制&#xff0c;被用来保证线程安全。每一个线程…

数字时代安全文件共享的重要性

数字时代彻底改变了工作、学习、交流和生活方式的方式。从在线协作到远程工作和电子学习&#xff0c;数字世界为全球各地的人们开辟了新的机遇。然而&#xff0c;伴随着这种便利性和可访问性而来的是对安全文件共享的需求。随着越来越多的机密信息在网上共享&#xff0c;窃取该…

常用数据可视化相关型图表大全

大数据时代&#xff0c;工作中我们可能经常会需要处理很多数据&#xff0c;需要在总结汇报中展示呈现&#xff0c;俗话说“字不如表&#xff0c;表不如图”&#xff0c;那么如何缩短数据与用户的距离?让用户一眼Get到重点? 在理解或分析大量数据时&#xff0c;数据可视化起着…

开始第一个vue项目,环境搭建+html项目运行

【用vue.js&#xff0c;通过script标签导入】 1. 搭建vue脚手架 安装node js安装cnpm&#xff08;淘宝源&#xff09; 【vue】在windows中搭建vue开发环境&#xff08;全网最详细&#xff09;_vue环境搭建_一起来学吧的博客-CSDN博客2a 2. 官网下载地址&#xff1a; 安装 …

Python实现ACO蚁群优化算法优化随机森林分类模型(RandomForestClassifier算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蚁群优化算法(Ant Colony Optimization, ACO)是一种源于大自然生物世界的新的仿生进化算法&#xff0c…

伟大的公司只需要十一人

在生成式AI、云计算等技术逐渐抹平大企业与中小企业之间的技术、成本差距后&#xff0c;各企业真正比拼的&#xff0c;只剩下人才、创意与执行力。 目前&#xff0c;随着AI技术的快速迭代&#xff0c;各种基于AIGC&#xff08;人工智能内容生成&#xff09;技术的产品不断涌向…

pytest自动化测试框架和unittest自动化测试框架的区别

目录 Unittest vs Pytest 用例编写规则 用例前置与后置条件 断言 测试报告 失败重跑机制 参数化 用例分类执行 实例演示 前后置区别 参数化区别 总结 python的单元测试框架经常使用的是unittest&#xff0c;因为它比较基础&#xff0c;并且可以进行二次开发&#xf…

分布式事务的21种武器 - 3

在分布式系统中&#xff0c;事务的处理分布在不同组件、服务中&#xff0c;因此分布式事务的ACID保障面临着一些特殊难点。本系列文章介绍了21种分布式事务设计模式&#xff0c;并分析其实现原理和优缺点&#xff0c;在面对具体分布式事务问题时&#xff0c;可以选择合适的模式…