题目要求:
利用有限状态机实现实现一个具有启动、停止、清零功能的秒表,显示格式:分:秒:十分秒。启动、停止、清零由一个按键控制,按键按下时,功能按启动、停止、清零顺序循环。
思路分析:
参考知乎上的这篇文章FPGA | Finite State Machine 有限状态机,对比两种状态机:
1.Mealy型状态机
2.Moore型状态机:
从这两张图上看,这两种状态机的唯一区别在于决定输出的是什么,在本实验中,最终的输出是数码管上的显示结果,题目中说“启动、停止、清零由一个按键控制,按键按下时,功能按启动、停止、清零顺序循环”也就是说按键的次数会影响到数码管的显示,因此本实验采用Mealy型状态机。
画出秒表的状态图:
S1: 0状态,所有数码管显示为0
S2:计时并显示
S3:停止计时,显示不变动
状态之间的“0”代表按键输入,本项目所用的开发板在不按动的情况下产生高电位,按动了就产生低电位,由于开发板的按键使用了施密特触发电路,因此在代码中就不做消抖了。
我在硬件设计代码里使用枚举类型来表示这3个状态,综合器在综合时,会自动对它们四个编码,将状态表示为二进制码的形式。
本项目用3个process,1s = 1000000000 ns
刚刚编译的时候出现了一条警告信息:
Warning (10631): VHDL Process Statement warning at Second.vhd(46): inferring latch(es) for signal or variable "current_state", which holds its previous value in one or more paths through the process
参考了http://www.itdaan.com/blog/2012/05/28/171e7e47cea3348ae9b125dc8154ecb3.html
看到的说法是:
解释:信号被综合成了latch,锁存器的EN和数据输入端口存在一个竞争的问题
好了,我的代码如下:
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_unsigned.all ;
use ieee.std_logic_arith.all ;entity Second is
port (clk : in std_logic ; -- the signal from 50MHZ clockkey : in std_logic ; -- the signal from key3 on development boardhex7 : out std_logic_vector(0 to 6) ;hex6 : out std_logic_vector(0 to 6) ;hex5 : out std_logic_vector(0 to 6) ;hex4 : out std_logic_vector(0 to 6) ;hex3 : out std_logic_vector(0 to 6) ;hex2 : out std_logic_vector(0 to 6) ;hex1 : out std_logic_vector(0 to 6) ;hex0 : out std_logic_vector(0 to 6) ; -- the result to outputseparate1 : out std_logic ;separate2 : out std_logic ;separate3 : out std_logic ;separate4 : out std_logic ;separate5 : out std_logic -- to separate hour, minute, second.) ;
end Second ;architecture Timer of Second isconstant matrix_num : integer := 9 ;constant MAX_INT : integer := 2147483647 ;TYPE Number is array (0 to matrix_num) of std_logic_vector(0 to 6);signal initial : Number := (('0', '0', '0', '0', '0', '0', '1'), -- 0('1', '0', '0', '1', '1', '1', '1'), -- 1('0', '0', '1', '0', '0', '1', '0'), -- 2('0', '0', '0', '0', '1', '1', '0'), -- 3('1', '0', '0', '1', '1', '0', '0'), -- 4('0', '1', '0', '0', '1', '0', '0'), -- 5('0', '1', '0', '0', '0', '0', '0'), -- 6('0', '0', '0', '1', '1', '1', '1'), -- 7('0', '0', '0', '0', '0', '0', '0'), -- 8('0', '0', '0', '0', '1', '0', '0') -- 9) ;TYPE state_type is (s1, s2, s3) ; -- how many states does the circuit have?signal current_state : state_type ;
beginprocess(key) -- to decide to changevariable num : integer := 0 ; -- how many times does user press the key?beginif falling_edge(key) thennum := (num + 1) MOD 3 ;end if ;if (num = 0) thencurrent_state <= s1 ;elsif (num = 1) thencurrent_state <= s2 ;elsif (num = 2) thencurrent_state <= s3 ;end if ;end process ;process(clk, current_state, initial)variable jump : integer ; -- store the times the clock risingvariable tenth : integer ;variable i : integer ;beginif (current_state = s1) thenjump := 0 ;tenth := 0 ;elsif (current_state = s2) thenif rising_edge(clk) thenjump := jump + 1 ;if (jump = 5000000) thententh := (tenth + 1) MOD MAX_INT ;jump := 0 ;end if ;end if ;end if ;hex7 <= initial((tenth/36000)/10) ;hex6 <= initial((tenth/36000) MOD 10) ;hex5 <= initial(((tenth MOD 36000) / 600) / 10) ;hex4 <= initial(((tenth MOD 36000) / 600) MOD 10) ;hex3 <= initial((((tenth MOD 36000) MOD 600) / 10) / 10) ;hex2 <= initial((((tenth MOD 36000) MOD 600) / 10) MOD 10) ;hex1 <= initial(((tenth MOD 36000) MOD 600) mod 10);hex0 <= ('1', '1', '1', '1', '1', '1', '1') ;separate1 <= '1' ;separate2 <= '1' ;separate3 <= '1' ;separate4 <= '1' ;separate5 <= '1' ;end process ;
end Timer ;