zoukankan      html  css  js  c++  java
  • PPM解码器

    PPM即Pulse Position Modulation(脉冲位置调制),利用脉冲的相对位置来传递信息的一种调制方式。在这种调制方式中,数据能够高速的传递。本文就来详细介绍一下PPM解码器。

    1、PPM的功能描述

    输入信号

    • clk,时钟周期为0.59us
    • rst,异步复位信号,低电平有效
    • din,输入的PPM编码后的数据

    输出信号

    • [7:0] dout,PPM解码后的8位数据
    • d_en,输出数据有效标志,高电平有效,持续一个时钟周期
    • f_en,帧头检测有效标志,高电平有效,持续一个时钟周期

    PPM数据编码格式.png

    PPM数据帧格式.png

    2、PPM的功能分析

    计数器用来控制时序,移位寄存器用来暂存数据,状态机用来进行状态转换。

    2.1计数器

    时钟的周期是0.59us,而输入的每一位数据宽度为9.44us=0.59us※16,解码2bit的数据需要的时间为75.52us=0.59us※128,解码一个完整的8位数据,需要302.08us=75.52us※4。基于以上分析,我们可以设置3个计数器来控制数据的采样。

    • count0,0~15,每16个时钟周期采一位din信号。
    • count1,0~7,解码2bit需要采到8位din信号。
    • count2,0~3,完成一个完整的8位信号,需要解码2bit数据4次。

    计数器count0.png
    计数器count1.png
    计数器count2.png

    2.2移位寄存器

    我们要对输入数据的8位数据进行判读,就要求我们对数据进行暂存。这里我们采用移位寄存器对输入数据进行暂存。与此同时,输出的8bit数据是2bit数据输出累加到8bit,所以我们也需要移位寄存器对输出数据进行暂存。

    • [7:0] reg1,对输入的数据进行移位操作,{reg1[6:0],din}
    • [7:0] reg2,对输出的数据进行暂存,等待8bit移满,就进行数据的输出,{2'b11,reg2[7:2]}{2'b00,reg2[7:2]}{2'b10,reg2[7:2]}{2'b01,reg2[7:2]}

    移位寄存器reg1.png
    移位寄存器reg2.png

    2.3状态机

    在传送数据的时候,主要有两个状态。要么是收到帧头解码数据,要么是没有收到帧头不进行解码。

    • S0,表示没有收到帧头,处于未工作状态。
    • S1,表示收到帧头,开始进行解码。

    状态转移图.png

    :以上电路图和状态转移图的判断条件有所简化。

    具体代码如下:

      module PPM(
           clk,
           rst,
           din,
           dout,
           d_en,
           f_en);
           
       input clk,rst;
       input din;
       output [7:0] dout;
       output d_en,f_en;
       reg [7:0] dout;
       reg d_en,f_en;
    
       reg [3:0] count0;
       reg [2:0] count1;
       reg [2:0] count2;
    
       reg [7:0] reg1;
       reg [7:0] reg2;
       reg cs,ns;
    
      parameter  SOF=8'b01111011,
                 EOF=4'b1101,
                d_00=8'b10111111,
                d_01=8'b11101111,
                d_10=8'b11111011,
                d_11=8'b11111110,
                   S0=1'b0,
                   S1=1'b1;
          
        always@(posedge clk or negedge rst)
           begin
             if(!rst)
                cs<=S0;
             else 
              cs<=ns;
           end
    
           always@(cs or count0 or count1 or reg1)
             begin
              case(cs)
                S0:begin
                 if((count0==15)&&(reg1==SOF))
                   begin
                   ns=S1;
                  f_en=1'b1;
                  end
                 else
                    begin
                    ns=S0;
                   f_en=1'b0;
                    end
                 end
         S1:begin
        if((count0==15)&&(count1==3)&&(reg1[3:0]==EOF))
        begin
          ns=S0;
          f_en=1'b0;
        end
      else
        begin
          ns=S1;
          f_en=1'b0;
        end
      end
      default:begin
                 ns=ns;
                f_en=1'b0;
               end
      endcase          
    end
    
          always@(posedge clk or negedge rst)
           begin
            if(!rst)
              begin
            count0<=0;
            reg1<=8'b00000000;
            end
         else
            begin 
              if(count0==15)
                begin
               reg1<={reg1[6:0],din};
              count0<=0;
             end
         else
         count0<=count0+1;   
     end
    end
    
    always@(posedge clk or negedge rst)
       begin
        if(!rst)
           count1<=0;
       else
       begin 
    if(cs==S1)
      if(count0==15)
         if(count1==7)
           count1<=0;
         else
           count1<=count1+1;
      else
        count1<=count1;
    else
      count1<=0;
     end
    end
        
    always@(posedge clk or negedge rst)
    begin
      if(!rst)
      count2<=0;
    else
    begin
      if((count0==15)&&(cs==S1)&&(count1==7))
        if(count2==3)
          count2<=0;
        else
          count2<=count2+1;
    end
    end
    
     always@(posedge clk or negedge rst)
     begin
     if(!rst)
         d_en<=0;
       else
         begin
           if((count0==15)&&(count1==7)&&(cs==S1)&&(count2==3))  
             d_en<=1;
           else
             d_en<=0;
          end
      end
    
     always@(posedge clk or negedge rst)
     begin
    if(!rst)
      reg2<=8'b00000000;
    else
    begin 
      if(cs==S1)
       if((count0==15)&&(count1==7)&&(count2<=3))     
              begin
              case(reg1)
              d_00:reg2<={2'b00,reg2[7:2]};
              d_01:reg2<={2'b01,reg2[7:2]};
              d_10:reg2<={2'b10,reg2[7:2]};  
              d_11:reg2<={2'b11,reg2[7:2]};
              default:reg2<=reg2;
              endcase  
              end
         else reg2<=reg2;
         else reg2<=0;     
      end
    end        
    
    always@(posedge clk or negedge rst)
      begin
      if(!rst)
    dout<=0;
      else 
      begin
       if((d_en)&&(cs==S1))
    dout<=reg2;
      else if (cs==S0)
    dout<=0;
     end
    end    
    
     endmodule 
    

    对以上代码做如下说明
    用拼接符号{}实现了移位寄存器,在使用拼接符号时一定要指定每一个元素的位宽。在位拼接表达式中不允许存在没有指明位数的信号。
    仿真波形图.png

    3、testbench的编写

    我们下面举一个例子来说明用文件读入的方法对存储器赋值。
    先定义一个有256个地址的字节存贮器
    reg [7:0] mem[40:0]; 地址为0~40,一个地址上存放着8bit的数据
    利用文件读入的方法对men赋值

    • initial $readmemb("mem.txt",mem);
      以二进制的方式读取mem.txt中的数据到mem中。
    • initial $readmemh("mem.txt",mem,16);
      以十六进制的方式读取mem.txt中的数据到mem[16]-mem[40]。
    • initial $readmemh("mem.data",mem,23,1);
      以十六进制的方式读取mem.txt中的数据到mem[23]-mem[1]。

    对读入文件做几点说明

    • 不同地址的数据以空格键或者回车键结束,从mem[0]开始读入数据。

    • 对一个地址的数据读入是从高位开始的,即从mem[0][7]开始读入mem.txt中的第一个数据,第一位地址的第7个元素为mem[1][7]=0 。

    • 对读入文件的命名规则,比如.txt文件名为mem,那么读入文件名应该为“mem.txt”。

    • 在Verilog中支持的文件路径格式为C:/Users/XQ/Desktop/mem.txt,而不是传统Windows底下的C:UsersXQDesktopmem.txt

    • 必须在run xx ns以后才能对存储器进行复制,初始的存储器的值都为xx。
      下面是一个名为mem的txt文件:

         00000000 //无效输入
         01111011 //帧头
         10111111 //"00"
         11101111 //"01"
         11111011 //"10"
         11111110 //"11"输出数据e4
         11111011 //"10"
         11111110 //"11"
         10111111 //"00"
         11101111 //"01"输出数据4e
         11010000 //帧尾
         00001100
         01111011 //帧头
         11111011 //"10"
         11111110 //"11"
         10111111 //"00"
         11101111 //"01"输出数据4e
         11111110 //"11"
         11101111 //"01"
         11111011 //"10"
         11111110 //"11"输出数据e7
         10111111 //"00"
         11101111 //"01"
         11111110 //"11"
         11101111 //"01"输出数据74
         11010010 //帧尾
         11010010
         01111011 //帧头
         10111111 //"00"
         11101111 //"01"
         11111011 //"10"
         11111110 //"11"输出数据e4
         10111111 //"00"
         11101111 //"01"
         11111011 //"10"
         11111110 //"11"输出数据e4
         11111011 //"10"
         11111110 //"11"
         10111111 //"00"
         11101111 //"01"输出数据4e
         11010000 //帧尾
      

    tb文件代码如下:

      `timescale 1ns/1ns
        module PPM_top;
    
         reg clk,rst;
         reg din;
         wire [7:0]dout;
         wire d_en,f_en;
    
         reg [7:0] mem[40:0];  
        integer i,j;
    
         initial
           begin
               $readmemb("C:/Users/XQ/Desktop/mem.txt",mem);
              for(i=0;i<41;i=i+1)
                 for(j=7;j>=0;j=j-1)
                   begin
                    #9440 
                     din=mem[i][j];
                      $display("mem[%0d][%0d]=%b",i,j,mem[i][j]);
                 end
               end
    
      always
         #295 clk=~clk;
    
       initial
         begin
          clk=0;
          rst=1;
          #200
         rst=0;
         #259
         rst=1;   
        end
    
      PPM ut1(
               .clk(clk),
               .rst(rst),
               .din(din),
               .d_en(d_en),
               .f_en(f_en),
               .dout(dout)
               );
                     
    endmodule
    

    :reg类型的数据默认为是无符号的数,若reg [7:0] j那么在j=j-1中就不会出现负数,而是0-1=8'b11111111=255;若integer [7:0] j那么就会出现0-1=-1,正好符合我们的本意。采用integer配合FOR语句,行数比较少,但是integer不能综合,只能用来仿真。

  • 相关阅读:
    176. Second Highest Salary
    175. Combine Two Tables
    172. Factorial Trailing Zeroes
    171. Excel Sheet Column Number
    169. Majority Element
    168. Excel Sheet Column Title
    167. Two Sum II
    160. Intersection of Two Linked Lists
    个人博客记录
    <meta>标签
  • 原文地址:https://www.cnblogs.com/xuqing125/p/8888081.html
Copyright © 2011-2022 走看看