原创 写状态机的流程(实例)

2011-9-12 09:23 1699 6 6 分类: FPGA/CPLD

写状态机的流程(实例)  

一、实验目标

设计两个可综合的电路模块:第一个模块(M1)能把4位的并行数据转化为符合以下协议的串行数据流,数据流用sclsda两条线传输,sclk为输入的时钟信号,data[3:0]为输入数据,ackM1请求M0发送数据信号。第二个模块(M2)能够把串行数据流内的信息接收到,并转换为相应的16条信号线的高电平,即若数据为1,则第一条线路为高电平,数据为n,则第N条线路为高电平。M0为测试用信号模块。该模块接收M1发出的ack信号,并产生新的测试数据data[3:0],如图1所示。

20110912092016001.gif

1 可综合模块结构及波形

通信协议:scl为不断输出的时钟信号,如果scl为高电平时,sda由高变低时刻,串行数据流开始;如果scl为高电平时,sda由低变高时刻,串行数据结束。sda信号的串行数据位必须在scl为低电平时变化,若变为高则为1,否则为零。

二、RTL级数据流

根据图1的可综合结构图,我们可以得到各模块之间的数据传输流程。

模块M1发送ack(高电平)信号 模块M0在检测到ack上升沿后,开始发送数据 模块M1在检测到ack为高电平之后开始数据。同时M1启动状态机将并行数据转化为串行数据,M2按照协议接收串行数据,进行处理并按照数据值在相应位输出高电平。图2,为M1M2模块的RTL视图。

20110912091501003.jpg

图2 M1和M2模块的RTL视图

三、时序

本题的时序可以分成三个部分进行理解,产生开始阶段、产生结束信号阶段、数据传输阶段。只要按照时序图,在scl相应的状态时,控制sda变化即可。

if(scl && ack) //generate start signal

               begin

                     sdabuf <= 0;

                     state  <= bit1;

               end

              else

               begin

                     state <= start;

           end

             bit1:

              if(!scl)   //change data in low of scl

               begin

            sdabuf <= databuf[3];

                     state  <= bit2;

           end

          else

            state  <= bit1;

             bit2:

              if(!scl)   //change data in low of scl

               begin

            sdabuf <= databuf[2];

                     state  <= bit3;

           end

          else

            state  <= bit2;

             bit3:

              if(!scl)   //change data in low of scl

                begin

             sdabuf <= databuf[1];

                      state  <= bit4;

            end

           else

             state  <= bit3;

             bit4:

              if(!scl)   //change data in low of scl

               begin

            sdabuf <= databuf[0];

                     state  <= bit5;

           end

          else

            state  <= bit4;

             bit5:

              if(!scl)

               begin

                     sdabuf <= 0;//pull down the bus

                     state  <= stop;

           end

          else

            state  <= bit5;

             stop:

              if(scl)

               begin

            sdabuf <= 1;//pull on the bus

                     state  <= IDLE;

           end

          else

            state  <= stop;

             IDLE:

              begin

               link_sda <= 0;//drop out from bus

               ack <= 0;

               state  <= ready;

              end

这个题目只有一个开关变量相对比较简单。

四、状态转换图

本想画张图,但感觉花1个小时画张并不实用的图,不如简单一些,用几个变量表达一下。

1.对于M1模块

parameter  ready  = 8'b0000_0000,//等待ack=1

           start  = 8'b0000_0001,//开始信号

           bit1   = 8'b0000_0010,//第三位数

           bit2   = 8'b0000_0100,//第二位数

           bit3   = 8'b0000_1000,//第一位数

           bit4   = 8'b0001_0000,//0位数

           bit5   = 8'b0010_0000,//为结束信号做准备

           stop   = 8'b0100_0000,//结束信号

           IDLE   = 8'b1000_0000;//

2.对于M2模块

开始信号和结束信号分别拥有单独的always进行检测,当满足条件时置位相应的标志位,然后开始传输数据。

always @ (negedge sda)

  if(scl)

   StartFlag <= 1;

  else if(EndFlag)

   StartFlag <= 0;

  

 always @ (posedge sda)

  if(scl)

   begin

    EndFlag <= 1;

    pdatabuf <= pdata;//得到数据,放入寄存器中.只有在接收完毕之后,patabuf才能得到数据

   end

  else

   EndFlag <= 0;

 

always @ (posedge scl)

  begin

   if(StartFlag)

    begin

      case(mstate)

          sbit0:

              begin

               mstate <= sbit1;

               pdata[3] <= sda;

               //$display("This is sdabit0");

              end

         sbit1:

              begin

               mstate <= sbit2;

               pdata[2] <= sda;

               //$display("This is sdabit1");

              end

         sbit2:

              begin

               mstate <= sbit3;

               pdata[1] <= sda;

               //$display("This is sdabit2");

              end

         sbit3:

              begin

               mstate <= sbit4;

               pdata[0] <= sda;

               //$display("This is sdabit3");

              end

         sbit4:

              begin

               mstate <= sbit0;

               //$display("Stop");

              end

         default:

              mstate <= sbit0;

     endcase

    end//if

   else

         mstate <= sbit0;//这句话可以确保每次进入case时,首先进入sbit0

  end//always

虽然,看明白了这个状态机,但自己写时依然感觉力不从心。只能是多总结,多思考,多练习。

文章评论0条评论)

登录后参与讨论
我要评论
0
6
关闭 站长推荐上一条 /2 下一条