参考资料:
樊昌信,曹丽娜 . 《通信原理》(第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