PPM解碼器

PPM即Pulse Position Modulation(脈沖位置調(diào)制),利用脈沖的相對位置來傳遞信息的一種調(diào)制方式。在這種調(diào)制方式中,數(shù)據(jù)能夠高速的傳遞。本文就來詳細(xì)介紹一下PPM解碼器。

1、PPM的功能描述

輸入信號

  • clk,時鐘周期為0.59us
  • rst,異步復(fù)位信號,低電平有效
  • din,輸入的PPM編碼后的數(shù)據(jù)

輸出信號

  • [7:0] dout,PPM解碼后的8位數(shù)據(jù)
  • d_en,輸出數(shù)據(jù)有效標(biāo)志,高電平有效,持續(xù)一個時鐘周期
  • f_en,幀頭檢測有效標(biāo)志,高電平有效,持續(xù)一個時鐘周期
PPM數(shù)據(jù)編碼格式.png
PPM數(shù)據(jù)幀格式.png

2、PPM的功能分析

計數(shù)器用來控制時序,移位寄存器用來暫存數(shù)據(jù),狀態(tài)機(jī)用來進(jìn)行狀態(tài)轉(zhuǎn)換。

2.1計數(shù)器

時鐘的周期是0.59us,而輸入的每一位數(shù)據(jù)寬度為9.44us=0.59us※16,解碼2bit的數(shù)據(jù)需要的時間為75.52us=0.59us※128,解碼一個完整的8位數(shù)據(jù),需要302.08us=75.52us※4?;谝陨戏治?,我們可以設(shè)置3個計數(shù)器來控制數(shù)據(jù)的采樣。

  • count0,0~15,每16個時鐘周期采一位din信號。
  • count1,0~7,解碼2bit需要采到8位din信號。
  • count2,0~3,完成一個完整的8位信號,需要解碼2bit數(shù)據(jù)4次。
計數(shù)器count0.png

計數(shù)器count1.png

計數(shù)器count2.png
2.2移位寄存器

我們要對輸入數(shù)據(jù)的8位數(shù)據(jù)進(jìn)行判讀,就要求我們對數(shù)據(jù)進(jìn)行暫存。這里我們采用移位寄存器對輸入數(shù)據(jù)進(jìn)行暫存。與此同時,輸出的8bit數(shù)據(jù)是2bit數(shù)據(jù)輸出累加到8bit,所以我們也需要移位寄存器對輸出數(shù)據(jù)進(jìn)行暫存。

  • [7:0] reg1,對輸入的數(shù)據(jù)進(jìn)行移位操作,{reg1[6:0],din}。
  • [7:0] reg2,對輸出的數(shù)據(jù)進(jìn)行暫存,等待8bit移滿,就進(jìn)行數(shù)據(jù)的輸出,{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狀態(tài)機(jī)

在傳送數(shù)據(jù)的時候,主要有兩個狀態(tài)。要么是收到幀頭解碼數(shù)據(jù),要么是沒有收到幀頭不進(jìn)行解碼。

  • S0,表示沒有收到幀頭,處于未工作狀態(tài)。
  • S1,表示收到幀頭,開始進(jìn)行解碼。
狀態(tài)轉(zhuǎn)移圖.png

:以上電路圖和狀態(tài)轉(zhuǎn)移圖的判斷條件有所簡化。

具體代碼如下:

  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 

對以上代碼做如下說明
用拼接符號{}實(shí)現(xiàn)了移位寄存器,在使用拼接符號時一定要指定每一個元素的位寬。在位拼接表達(dá)式中不允許存在沒有指明位數(shù)的信號。

仿真波形圖.png

3、testbench的編寫

我們下面舉一個例子來說明用文件讀入的方法對存儲器賦值。
先定義一個有256個地址的字節(jié)存貯器
reg [7:0] mem[40:0]; 地址為0~40,一個地址上存放著8bit的數(shù)據(jù)
利用文件讀入的方法對men賦值

  • initial $readmemb("mem.txt",mem);
    以二進(jìn)制的方式讀取mem.txt中的數(shù)據(jù)到mem中。
  • initial $readmemh("mem.txt",mem,16);
    以十六進(jìn)制的方式讀取mem.txt中的數(shù)據(jù)到mem[16]-mem[40]。
  • initial $readmemh("mem.data",mem,23,1);
    以十六進(jìn)制的方式讀取mem.txt中的數(shù)據(jù)到mem[23]-mem[1]。

對讀入文件做幾點(diǎn)說明

  • 不同地址的數(shù)據(jù)以空格鍵或者回車鍵結(jié)束,從mem[0]開始讀入數(shù)據(jù)。

  • 對一個地址的數(shù)據(jù)讀入是從高位開始的,即從mem[0][7]開始讀入mem.txt中的第一個數(shù)據(jù),第一位地址的第7個元素為mem[1][7]=0 。

  • 對讀入文件的命名規(guī)則,比如.txt文件名為mem,那么讀入文件名應(yīng)該為“mem.txt”。

  • 在Verilog中支持的文件路徑格式為C:/Users/XQ/Desktop/mem.txt,而不是傳統(tǒng)Windows底下的C:\Users\XQ\Desktop\mem.txt。

  • 必須在run xx ns以后才能對存儲器進(jìn)行復(fù)制,初始的存儲器的值都為xx。
    下面是一個名為mem的txt文件:

    00000000 //無效輸入
    01111011 //幀頭
    10111111 //"00"
    11101111 //"01"
    11111011 //"10"
    11111110 //"11"輸出數(shù)據(jù)e4
    11111011 //"10"
    11111110 //"11"
    10111111 //"00"
    11101111 //"01"輸出數(shù)據(jù)4e
    11010000 //幀尾
    00001100
    01111011 //幀頭
    11111011 //"10"
    11111110 //"11"
    10111111 //"00"
    11101111 //"01"輸出數(shù)據(jù)4e
    11111110 //"11"
    11101111 //"01"
    11111011 //"10"
    11111110 //"11"輸出數(shù)據(jù)e7
    10111111 //"00"
    11101111 //"01"
    11111110 //"11"
    11101111 //"01"輸出數(shù)據(jù)74
    11010010 //幀尾
    11010010
    01111011 //幀頭
    10111111 //"00"
    11101111 //"01"
    11111011 //"10"
    11111110 //"11"輸出數(shù)據(jù)e4
    10111111 //"00"
    11101111 //"01"
    11111011 //"10"
    11111110 //"11"輸出數(shù)據(jù)e4
    11111011 //"10"
    11111110 //"11"
    10111111 //"00"
    11101111 //"01"輸出數(shù)據(jù)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類型的數(shù)據(jù)默認(rèn)為是無符號的數(shù),若reg [7:0] j那么在j=j-1中就不會出現(xiàn)負(fù)數(shù),而是0-1=8'b11111111=255;若integer [7:0] j那么就會出現(xiàn)0-1=-1,正好符合我們的本意。采用integer配合FOR語句,行數(shù)比較少,但是integer不能綜合,只能用來仿真。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 教程一:視頻截圖(Tutorial 01: Making Screencaps) 首先我們需要了解視頻文件的一些基...
    90后的思維閱讀 4,988評論 0 3
  • [TOC] 音視頻&流媒體 是什么促使我要寫這一篇音視頻入門文章?那是因?yàn)楹鸵幻米哟蛸€碼率的概念,結(jié)果輸了;對一個...
    AllenWu閱讀 5,184評論 1 24
  • 摘要 該配置文件定義了支持高質(zhì)量音頻分發(fā)所需的Bluetooth?設(shè)備的要求。這些要求以終端用戶服務(wù)的方式表達(dá),并...
    公子小水閱讀 10,411評論 0 4
  • 你拖延過嗎? 我拖延過,幾乎每天都在拖延。 比如,這兩天單位讓填《房產(chǎn)普查登記樣表》,通知發(fā)了好幾周了,工作群里也...
    凌霄love閱讀 275評論 0 0
  • 一、linux加入GNU計劃并采用GPL協(xié)議發(fā)布 常見的linux發(fā)行版:ubuntu redhat centos...
    Gatsby_anan閱讀 513評論 0 0

友情鏈接更多精彩內(nèi)容