通訊原理---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
我們可以看到,兩個相鄰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