1. 程式人生 > >通訊原理---FPGA---HDB3碼編碼

通訊原理---FPGA---HDB3碼編碼



參考資料:

樊昌信,曹麗娜 . 《通訊原理》(第7版)

https://wenku.baidu.com/view/24b7bc227fd5360cba1adb6c  (這個PPT給了很多啟發)

https://wenku.baidu.com/view/7cd940274b35eefdc8d3330f.html

https://baike.baidu.com/item/HDB3%E7%A0%81/3815309?fr=aladdin

HDB3碼(High Density Bipolar of Order 3),三階高密度雙極性碼,它是AMI碼的一種改進,目的是克服AMI的缺點,使連續“0”的個數不超過3個。其編碼規則如下:

(1) 先檢查連“0”個數,若小於等於3,則與AMI碼相同;

(2)當連“0”個數大於3時,將每4個連“0”化作一個小節,用“000V”代替,其中V取值+1或-1,V的極性與前一個相鄰的非“0”脈衝極性相同(這破壞了極性交替規則,故稱V為破壞脈衝);

(3) 相鄰的V極性必須交替,當V滿足(2)但不滿足(3)時,將“000V”更改為“B00V”,B的極性與後面的V一致,B稱調節脈衝,==>即兩個相鄰V之間的“1”的個數為偶數時V的極性不滿足交替,需要替換為“B00V”;為奇數時V的極性能滿足交替,不需要替換;

(4)V後面的傳號碼極性也要交替。

訊息碼:     1   0   0   1   1   0   0   0   0   1   0   1   1   0   1   0   0   0   0   1   1   1   1   0

 AMI碼:  +1  0   0  -1 +1  0   0   0   0  -1   0 +1 -1   0 +1   0   0   0   0 -1 +1 -1 +1   0

加V    :   +1  0   0  -1 +1  0   0   0 +V

-1   0 +1 -1   0 +1   0   0   0 +V-1 +1 -1 +1   0

我們可以看到,兩個相鄰V之間的非0個數為偶數,造成兩V的極性相同,不符合(3),所以加B

加B    :   +1  0   0  -1 +1  0   0   0 +V -1   0 +1 -1   0 +1 -B   0   0 -V -1 +1 -1 +1   0


若對0、1、B、V用兩位二進位制數表示(00,01,10,11),則在不考慮極性的情況下,加B後應該輸出

       01  00  00  01  00  00  00  11  01  00  01  01  00  01  10  00  00  11  01  01  01  01  00

由此,我們使用Verilog語言進行編寫HDB3碼的編碼程式。

(1)先不考慮極性(+或-),只考慮輸出是0、1、B還是V,對上述4個數編碼,0--00,1--01,B--10,V--11

(2)加V操作,判斷輸入的字元是“1”還是“0”,1=>01, 0=>00,若為4個連“0”,前三個輸出“00”,第四個輸出“11”

always @ ( posedge clk or negedge rst_n )
begin
 if( !rst_n )  begin
  count0 <= 0;
 end
 else  begin
  if( codein == 1'b1 )  begin  //輸入1
   codeout_v <= 2'b01;
   count0 <= 2'b00;    //出現1後就要重新對0計數
  end
  else  begin       //輸入0
   count0 <= count0 + 1'b1; //對0的計數加1
   if( count0 == 2'b11 ) begin //0的個數等於3,因為是並行,其實是4個了,只是在下一個時鐘上升沿變為4
    codeout_v <= 2'b11;  //輸出V
    count0 <= 2'b00;   //重新對0計數
   end
   else  begin 
    codeout_v <= 2'b00;
   end
  end
 end
end

(3)加B操作,判斷兩個相鄰的V之間的非“0”(此時兩V之間非0的應該只有1,即“01”)的個數是否為偶數,若為偶數,從後一個V往前數,第三個0變為B;若為奇數,正常輸出;

注意:此處如何操作V前面的第三個0很關鍵,按照正常的邏輯似乎不太好把已經輸出的0變為B,所以我們可以將輸出的資料進行一定的延時,這樣要操作的數還在暫存器裡沒有輸出(正要輸出最好),即可進行更改後再輸出,延時的方法可以使用移位暫存器,利用非租塞賦值(<=)的延時,使輸出延時3個週期,操作後正好輸出

always @ ( posedge clk )
begin
 buffer[0] <= codein_v; //移位暫存器延時
 buffer[1] <= buffer[0];
 buffer[2] <= buffer[1];
end

always @ ( posedge clk or negedge rst_n )
begin
 if( !rst_n )  begin
  count01 <= 0;
  first_v <= 0;
 end
 else  begin
  if( codein_v == 2'b11 )  begin  //11-->V
  if( first_v == 1'b0 ) begin  //還沒出現過V,就不存在兩個V之間非0數為偶數的情況,不需要對1計數
    first_v <= 1;     //已經出現了V
    count01 <= 2'b00;    //出現11後就要重新對01計數
    codeout_b <= buffer[2];  //延時後的輸出
   end
   else  begin
    if( count01[0] == 0 )  begin //1的個數為偶數
     codeout_b <= 2'b10;   //B-->10
     count01 <= 2'b00; 
    end
    else  begin
     codeout_b <= buffer[2];
     count01 <= 2'b00; 
    end
   end
  end
  else if( codein_v == 2'b01 )  begin  //01--->1
   if( first_v == 1'b1 ) begin
    count01 <= count01 + 1'b1;
    codeout_b <= buffer[2];
   end  
  end
  else begin
   codeout_b <= buffer[2];
  end
 end
end

(4)極性判斷輸出,這一步還沒做,先寫到這,頂層bdf如下(還差個極性轉換,有時間再寫),Modelsim模擬如下(部分關鍵程式碼)

initial
begin
    #0 clk = 1'b0;
    #0 rst_n = 1'b0;
    #2 rst_n = 1'b1;
    #100000 $stop;
end

always #15
begin
    clk = ~clk;
end

always
begin
    #30 codein <= 1'b1;
  #30 codein <= 1'b0;
  #30 codein <= 1'b0;
  #30 codein <= 1'b1;
  #30 codein <= 1'b1;
  #30 codein <= 1'b0;
  #30 codein <= 1'b0;
  #30 codein <= 1'b0;
  #30 codein <= 1'b0;
  #30 codein <= 1'b1;
  #30 codein <= 1'b0;
  #30 codein <= 1'b1;
  #30 codein <= 1'b1;
  #30 codein <= 1'b0;
  #30 codein <= 1'b1;
  #30 codein <= 1'b0;
  #30 codein <= 1'b0;
  #30 codein <= 1'b0;
  #30 codein <= 1'b0;
  #30 codein <= 1'b1;
  #30 codein <= 1'b1;
  #30 codein <= 1'b1;
  #30 codein <= 1'b1;
  #30 codein <= 1'b0;
end