原创 【博客大赛】【原创】状态机输入与输出相关带来的时序问题[后篇]

2012-5-23 19:28 1849 20 22 分类: FPGA/CPLD

如果用单片机来写这个程序,我们会这么写,先输出col,再检测row行值。同样上面的Verilog代码目的也是要实现这个时序,但恰恰是检测 row在输出col之前。所以对这个代码进行修改的话就是让它满足,先输出col,再检测row的时序。我们可以通过插入额外的状态来实现,修改后的代码 如下:

 

/*************************************************/  

       parameter NO_KEY_PRESSED=4'b0000;//没有键按下

       parameter SET_COL0      =4'b0001;

       parameter SCAN_COL0     =4'b0010;//扫描第 0 列

       parameter SET_COL1      =4'b0011;

       parameter SCAN_COL1     =4'b0100;//扫描第 1 列

       parameter SET_COL2      =4'b0101;

       parameter SCAN_COL2     =4'b0110;//扫描第 2 列

       parameter SET_COL3      =4'b0111;

       parameter SCAN_COL3     =4'b1000;//扫描第 3 列

       parameter SET_ALL       =4'b1001;

       parameter KEY_PRESSED   =4'b1010;//有键按下

 

/*************************************************/

      

       reg [5:0]current_state,next_state;  //现态和次态

        

/*************************************************/

       always @(posedge key_clk or negedge rst_n)

              if(!rst_n)

                     current_state<=SET_ALL;

              else

                     current_state<=next_state;

 

/*************************************************/          

       always @ (current_state)     //根据条件转移状态

              case (current_state)

                     SET_ALL :

                                   next_state=NO_KEY_PRESSED;

 

                     NO_KEY_PRESSED:      //没有键按下                        

                            if(row!=4'hf)

                                   next_state=SET_COL0;    

                            else

                                   next_state=SET_ALL;

 

                     SET_COL0:

                           next_state=SCAN_COL0;

                     SCAN_COL0:           //扫描第 0 列

                            if(row!=4'hF)

                                   next_state=KEY_PRESSED;

                            else

                                   next_state=SET_COL1;      

                     SET_COL1:

                           next_state=SCAN_COL1;            

                     SCAN_COL1:          //扫描第 1 列

                            if(row!=4'hF)

                                   next_state=KEY_PRESSED;

                            else

                                   next_state=SET_COL2;

                     SET_COL2:

                           next_state=SCAN_COL2;            

                     SCAN_COL2:         //扫描第 2 列

                            if(row!=4'hF)

                                   next_state=KEY_PRESSED;

                            else

                                   next_state=SET_COL3;      

                     SET_COL3:

                           next_state=SCAN_COL3;            

                     SCAN_COL3:        //扫描第 3 列

                            if(row!=4'hF)

                                   next_state=KEY_PRESSED;

                            else

                                   next_state=NO_KEY_PRESSED;      

                     KEY_PRESSED:      //有按键按下

                            if(row!=4'hf)

                                   next_state=KEY_PRESSED;

                            else

                                   next_state=SET_ALL;                 

              endcase

 

/*************************************************/

              reg key_pressed_flag; //按键按下标志

              reg [3:0]col_val;      //列值

              reg [3:0]row_val;     //行值

 

/*************************************************/

              //根据次态,给相应的寄存器赋值

/*************************************************/

              always @(posedge key_clk or negedge rst_n)

                     if(!rst_n)       //复位

                            begin

                            col<=4'h0;

                            key_pressed_flag<=0;

                            end

                     else begin

                            case (next_state)

                                   SET_ALL : col<=4'b0000 ;                       

                                   NO_KEY_PRESSED:

                                          begin

                                          key_pressed_flag<=0;

                                          end

                                   SET_COL0 : col<=4'b1110 ;                                     

                                   SCAN_COL0: ;      //扫描第 0 列         

                                   SET_COL1 : col<=4'b1101;

                                   SCAN_COL1: ;      //扫描第 1 列

                                   SET_COL2 : col<=4'b1011;

                                   SCAN_COL2: ;            //扫描第 2 列

                                   SET_COL3 : col<=4'b0111;

                                   SCAN_COL3: ;       //扫描第 3 列

                                   KEY_PRESSED:     //有按键按下

                                          begin

                                          col_val<=col; // 锁存列值

                                          row_val<=row; // 锁存行值

                                          key_pressed_flag<=1;         // 置键盘按下标    

                                          end

                                   end 

                            endcase

 

话说终于可以松口气了…喝口雪碧…

 

等等!好像有什么不对,为什么以前写状态机没遇到过这种情况呢?

我左想友想上想下想,跟以前的状态机一比较,还真发现问题了。

 

比如说典型的售货机,投进去多少钱(当然要是它能认的,不认的它可不收),币值是多少,顺序咋样,谁说了算?当然是我们说了算,售货机只管钱够不够,够了就吐东西,不够继续等待投币。也就是说输出跟输入没有半毛关系。

 

再看这个按键检测,输入的数据,不仅受按键是否按下、哪个键按下有关,还跟此时Col的输出有关,而输出又要受状态控制,这就是症结所在了。

 

哎 ,算是彻底的解脱了,但以后碰到这种输入与输出相关的状态机,还得多加注意时序啊!

 

文章评论2条评论)

登录后参与讨论

用户401816 2012-5-24 14:51

技术需要严谨,但不一定非得搞得苦大仇深似的,为何不欢乐点呢,呵呵

用户403664 2012-5-24 08:32

哈,博主叙事方式很有喜感~
相关推荐阅读
用户401816 2012-08-24 11:16
HDL代码维护:都会有的第一次
  尊重原作者的劳动。   以欣赏的眼光去阅读代码,吸取其精妙之处。   清醒地认识到代码存在的问题,并仔细斟酌。   代码分析步骤:   阅读设计文档,仔细、...
用户401816 2012-05-23 19:25
【博客大赛】【原创】状态机输入与输出相关带来的时序问题[中篇]
可一到运行起来就蛋疼了,呵呵…. 下面分析一下,仅供参考,若有不对,敬请指正!   看上面时序图在 1、第0~2个时钟周期内 row(输入)为4’b1111代表无键按下,...
用户401816 2012-05-23 19:21
【博客大赛】【原创】状态机输入与输出相关带来的时序问题[前篇]
昨天帮同学修改一个不知道从哪里Ctrl+C、Ctrl+V来的矩阵键盘检测代码,没有分频、没有消抖,直接拿来用就别指望了,呵呵…在这里拿出来主要是想说明一个隐藏的时序问题。废话不多说,直接上代码,注...
用户401816 2012-04-18 22:56
双向口采用纯组合逻辑产生的组合回环
这是一个RAM的代码: me :使能信号 io: 控制输入输出 io=1接收,io=0输出 marL:地址寄存使能信号 /*----------------------------...
我要评论
2
20
关闭 站长推荐上一条 /2 下一条