原创 Hdb3之FPGA实现

2011-5-31 16:53 5847 17 21 分类: FPGA/CPLD

  (转载请写明出处,谢谢!)

一:前言

    2天在帮一同学弄用cpld实现hdb3的编码和解码,要用vhdl,可惜我只是会一点verilog,所以我开始就用verilog来写,写出来后看点vhdl的语法就可以很快用vhdl搞定了。这里我还是选取自己比较熟悉的verilog来讲解。

Hdb33阶高密度双极码。Hdb3码因为其无直流分量、低频分量少,连0个数不超过3、便于时钟的提取和恢复,适合对基带信号直接传输。应用还是比较广泛的,所以ITU-T规定,对于2M8M32M的数字接口均采用HDB3接口,可见其作用不可小觑。

关于Hdb3码的编码解码大家可以去网上查下。

二:编码

编码过程分为3个步骤。

1:加V

废话不说,先看代码。

 

module AddV(Clk,Data_In,Data_OutV);

input Clk,Data_In;

output reg [1:0]Data_OutV;

reg[1:0]Count0;

always@(posedge Clk)

begin

    if(Data_In==1'b1)

       begin

           Data_OutV<=2'b01;

           Count0<=2'b0;

       end

    else if(Data_In==1'b0)

       begin

           Count0<=Count0+2'b1;

           if(Count0==2'b11)//because it is parall,so it is 3,not 4

           begin

              Count0<=2'b0;

               Data_OutV<=2'b11;

           end

           else Data_OutV<=2'b00;

       end          

end

endmodule

 

模块有2个输入,即系统时钟和需要传输的基带数字信号(只有01,1个输出,即经过加V后的数字信号(00代表0,01代表1,11代表V.

具体方法是判断输入Data_In的电平,如果为1,那么输出Data_OutV就为01,如果输入为0,则用Count0计数其0出现的次数,如果Count0小于3个,则输出为00,否则输出为11。这里为什么用小于3个呢,而不是4个呢?因为hdl语言是并行执行的。看相关代码:

begin

           Count0<=Count0+2'b1;

           if(Count0==2'b11)//because it is parall,so it is 3,not 4

           begin

              Count0<=2'b0;

              Data_OutV<=2'b11;

           end

    end

Count01是和Count0是否等于3是并行执行的,也就是说当第一个0到来时,虽然Count01了,但是用if判断时其还是0,以此类推。

2:加B

module AddB(Clk,Data_In,Data_OutB);

input Clk;

input[1:0] Data_In;

output reg[1:0] Data_OutB;

reg[1:0] Buffer[4];

reg FirstV;

reg Count_Even;//Count_Even only can be assigned as 0 or 1;so 0 is stand for even,1 // is stand for odd

always@(posedge Clk)

Data_OutB=(FirstV==1'b1&&Count_Even==1'b0&&Buffer[0]==2'b11)?2'b10:Buffer[3];

always@(posedge Clk)    //take in turn of coming into the register Buffer;

begin

    Buffer[0]<=Data_In;

    Buffer[1]<=Buffer[0];

    Buffer[2]<=Buffer[1];

    Buffer[3]<=Buffer[2];

end

always@(posedge Clk)

begin

    if(2'b01==Buffer[3])            //here we judge the high bit of Buffer,because Data_OutB                                 

       Count_Even<=Count_Even+1'b1;       //is usually assigned as Buffer[3];

    else if(2'b11==Buffer[0])   //here we judge the low bit of Buffer,because if Buffer[0]

Count_Even<=1'b0;    //is 2'b11.then Buffer[1],Buffer[2],Buffer[3] is //  2'b00,so we  

end                         //should not conut Buffer[3];

always@(posedge Clk)

begin

    if(2'b11==Buffer[0])   //Judeg if it is the first coming of 'v',if it is ,hten //FisrtV is 1;

       if(1'b0==FirstV)

           FirstV<=1'b1;

end

endmodule

B模块也是2个输入,其中1个输入为加V的输出,另一个是时钟;一个输出,即加B后的数字信号输出。(00代表0,01代表1,10代表B11代表V

B模块在加V模块的基础上主要是完成把某些地方的00变成10,什么地方呢?首先,我们知道,V前面肯定有30,我们就是要把V最前面的那个0变成B,但并不是所有的这样的0都需要变,还必须满足在两个V之间非0的个数(也就只剩下1了)为偶数的情况下我们才需要把这样的0变成B,两者缺一不可。

怎样判断非0个数的奇偶呢?我们这里采用的是1个位宽的变量Count_Even,因为只有1个位宽,所有非01。当然因为其初始化为0,遇到两个V之间的1Count_Even就加1,此时Count_Even=1,再碰到1个时又加1,这时Count_Even1就回到了0啦。因此,Count_Even=0时代表两V之间有偶数个1Count_Even1时代表两V之间有奇数个1。这方法比较简单,不必用变量累加,然后对2取模判断奇偶!

因为我们用到了判断2V之间的1的个数,所以我们还需要1个标志FirstV表示我们检测到了第1V,只有当我们检测到了第1V后我们才开始统计1的个数。

难点在加B,因为当检测到2V之间1的个数为偶数时,我们需要把后面V的最前面那个0变成B,所以我们的设计必须有记忆功能,要记住至少4个将要发送的数据。这里我们采用4个长度的数组Buffer作为记忆存储。并且数据Data_OutB是从Buffer[3]中输出的,因此上电后系统输出有一下延时。下面解释下这里为什么采用长度为4的数组来记忆呢?因为我们判断1是在FirstV=1的前提下,且是通过Buffer[3]判断的,所以当第二个V(V是通过Buffer[0])来临时,Buffer[1] Buffer[2]Buffer[3]肯定全为0,因为V前面有30,而我们就是想把Buffer[3]改为B即可。

3:单双极性变化;

module Polar(Clk,Data_In,Hdb3);

input Clk;

input[1:0]Data_In;

output reg[1:0]Hdb3;

reg FlagP;

always@(posedge Clk)

begin

   if(2'b01==Data_In||2'b10==Data_In)

   begin

       FlagP<=FlagP+1'b1;  //FlagP stands for if we should make the code //number negetive

       if(1'b1==FlagP)    //if FlagP is 1,we should output -1

          Hdb3<=2'b10;

       else Hdb3<=2'b01;

   end

   else if(2'b11==Data_In) //if it is 'v',we should make sure it is the same //polar of the pre 'b' or '1'

   begin

       if(1'b1==FlagP)  //if FlagP is 1,we should output +1

          Hdb3<=2'b01;

       else Hdb3<=2'b10;

   end

   else if(2'b00==Data_In)  //here stay the same

          Hdb3<=2'b00;

end

endmodule

 

单双极性变换很简单,输入为加B后的输出,单极性;输出为双极性,有正有负数,当然+V-V+B-V也是用+1-1表示了,因为都是数字信号。(+1+B+V01表示,000表示,-V,-B-110表示)。

因为除V外,1B都是正负交错输出的(B也可以看做1),V与前面的1B同极性。所以为了达到交错的目的,用了FlagP来判断B1的奇偶数,类似前面的Count_Even

利用FlagP来输出正负1B的输出,显然,也可以利用FlagP来输出正负V的,只是规则恰好相反。

 

三:解码

解码分为2个部分,去VB部分;单双极性转换部分。

1:去V和B;

module AbandonVB(Clk,Hdb3,Data_OutP);

input Clk;

input[1:0]Hdb3;

output reg[1:0] Data_OutP;

reg[1:0]Buffer[5];

reg[1:0]Count_0;

always@(posedge Clk)

begin

    Buffer[4]=Buffer[3];

    Buffer[3]=Buffer[2];

    Buffer[2]=Buffer[1];

    Buffer[1]=Buffer[0];

    Buffer[0]=Hdb3;  

    begin

       if(2'b0==Buffer[0])

           Count_0=Count_0+2'b1;

       else if(2'b10==Count_0&&(2'b00==(Buffer[0]^Buffer[3])))

       begin

           Buffer[0]=2'b00;

           Buffer[3]=2'b00;

           Count_0=2'b0;

       end

       else if(2'b11==Count_0&&(2'b00==(Buffer[0]^Buffer[4])))

       begin

           Buffer[0]=2'b0;

           Count_0=2'b0;

       end

       else// if(2'b01==Buffer[0]||2'b10==Buffer[0]||2'b11==Buffer[0])

           Count_0=2'b0;

    end

    Data_OutP=Buffer[4];

end

endmodule

    VB,我是根据解码规则:当有3个连续0时判断这30前后数字符号是否相同,如果符号相同,则30后面的那个肯定是V,这时只需将V变成0即可;当有2个连续的0时,如果20前后的数字符号一致,这20前面那个肯定是B,后面那个肯定是V,所以将此时的VB都变成0即可。这里判断符号相同采用异或,异或结果为0则符号相同。VB的存在仅以上2种情况,不可能出现1个连续0前后有VB的。当然这里也采用了Count_0来计数连续0的个数。

2:双单极性转换

module Polar(Clk,Data_In,True_Code);

input Clk;

input[1:0]Data_In;

output reg True_Code;

always@(posedge Clk)

begin

    if(2'b01==Data_In||2'b10==Data_In)

       True_Code<=1'b1;

    else if(2'b00==Data_In)

       True_Code<=1'b0;

end

endmodule

这个最简单了,不管是正负1都输出1,是0就输出0就可以了。因为Hdb3码的源码肯定只有位宽为101.

四:测试

    分为2个版本,verilogVHDL,每个版本都包含编码器(encode)和解码器(decode)。

 

其中编码的测试数字信号代码为:

原码:1  0  0  1  1  0  0  0  0  1  0  1  1  0  1  0  0  0  0  1  1  1  0

V: 01 00 00 01 01 00 00 00 11 01 00 01 01 00 01 00 00 00 11 11 11 11 00

(以上为加V后的代码。此处的00代表0,01代表1,11代表V

B: 01 00 00 01 01 00 00 00 11 01 00 01 01 00 01 10 00 00 11 11 11 11 00:

(以上为加B后的代码。此处的00代表0,01代表1,10代表B11代表V

Hdb301 00 00 10 01 00 00 00 01 10 00 01 10 00 01 10 00 00 10 01 10 01 00

(以上为双单极性变换后的代码。此处的00代表0,01代表+1,10代表-1

即: +1  0  0  -1  1  0  0  0  1  -1  0  1  -1  0  1  -1  0  0  -1  1  -1  1  0

 

其顶层模块如下:

20110531165149001.jpg

仿真波形图如下:

20110531165149002.jpg

 

其中解码的测试数字信号代码为:

接收码:01 00 10 10 01 00 00 00 01 10 00 01 10 00 01 10 00 00 10 01 10 01 00

(和编码规则定义的相同,此处的00代表0,01代表+1,10代表-1

即:+1  0  0  -1  1  0  0  0  1  -1  0  1  -1  0  1  -1  0  0  -1  1  -1  1  0

VB后:01 00 00 10 01 00 00 00 00 10 00 01 10 00 01 00 00 00 00 01 10 01 00

(去掉VB的编码,此处00代表0,01代表1,10代表0

解码后:1  0  0  1  1  0  0  0  0  1  0  1  1  0  1  0  0  0  0  1  1  1  0

 

其顶层模块如下:

20110531165149003.jpg

仿真波形图如下:

20110531165150004.jpg

 

五:附录

VHDL版本编码

1.V

library ieee;

use ieee.std_logic_1164.all;

entity AddV is

port(Clk:in std_logic;Data_In:in std_logic;Data_OutV:out std_logic_vector(1 downto 0));

end AddV;

architecture AddV of Addv is

--signal Count0:std_logic_vector(0 to 1);

signal Count0:integer range 0 to 3;

begin

    process(Clk)

    begin

    --  wait until Clk='1' and Clk'event;

    if( Clk='1' and Clk'event)then

       if(Data_In='1')then

           Data_OutV<="01";

           Count0<=0;

       elsif(Data_In='0')then

              Count0<=Count0+1;

              if(Count0=3)then

                  Count0<=0;

                  Data_OutV<="11";

              else Data_OutV<="00";

              end if;

       end if;

    end if;

    end process;

end AddV;

2.B

library ieee;

use ieee.std_logic_1164.all;

entity AddB is

port(Clk:in std_logic;Data_In:in std_logic_vector(1 downto 0);

     Data_OutB:out std_logic_vector(1 downto 0));

end AddB;

architecture AddB of AddB is

type array_4 is array(3 downto 0) of std_logic_vector(1 downto 0);

signal FirstV:std_logic;

signal Buf:array_4;

signal Count_Even:integer range 0 to 1;

begin

    ShuChu:process(Clk)

    begin

       if( Clk='1' and Clk'event)then

           if(FirstV='1' and Count_Even=0 and Buf(0)="11")then

              Data_OutB<="10";

           else Data_OutB<=Buf(3);

           end if;

--         Data_OutB<=(FirstV='1'&&Count_Even=0&&Buf[0]="11")?"10":Buf(3);

       end if;

    end process ShuChu;

    Buff:process(Clk)

    begin

       if( Clk='1' and Clk'event)then

       Buf(0)<=Data_In;

       Buf(1)<=Buf(0);

       Buf(2)<=Buf(1);

       Buf(3)<=Buf(2);

       end if;

    end process Buff;

    Count:process(Clk)

    begin

       if( Clk='1' and Clk'event)then

           if("01"=Buf(3))then           --here we judge the high bit of --Buffer,because Data_OutB                               

              Count_Even<=Count_Even+1;       --is usually assigned as --Buffer[3];

           elsif("11"=Buf(0))then   --here we judge the low bit of Buffer,because if Buffer[0]

              Count_Even<=0;       --is 2'b11.then --Buffer[1],Buffer[2],Buffer[3] is 2'b00,so we  

           end if;                  --should not conut Buffer[3];

       end if;

    end process Count;

    JudgeV:process(Clk)

    begin

       if( Clk='1' and Clk'event)then

           if("11"=Buf(0)) then --Judeg if it is the first coming of 'v',if it --is ,hten FisrtV is 1;

              if('0'=FirstV)then

                  FirstV<='1';

              end if;

           end if;

       end if;

    end process JudgeV;

end Addb;

 

3.单双极性转换:

library ieee;

use ieee.std_logic_1164.all;

entity Polar is

port(Clk:in std_logic;Data_In:std_logic_vector(1 downto 0);

     Hdb3:out std_logic_vector(1 downto 0));

end Polar;

architecture Polar of Polar is

signal FlagP:integer range 0 to 1;

begin

    process(Clk)

    begin

       if(Clk='1' and Clk'event)then

           if("01"=Data_In or "10"=Data_In)then

              FlagP<=FlagP+1;

              if(1=FlagP)then

                  Hdb3<="10";

              else Hdb3<="01";

              end if;

           elsif("11"=Data_In) then

              if(1=FlagP)then

                  Hdb3<="01";

              else Hdb3<="10";

              end if;

           elsif("00"=Data_In)then

              Hdb3<="00";

           end if;      

    end if;

    end process;

end Polar;

VHDL版本解码

1.VB

library ieee;

use ieee.std_logic_1164.all;

entity AbandonVB is

port(Clk:in std_logic;Hdb3:in std_logic_vector(1 downto 0);

 Data_OutP:out std_logic_vector(1 downto 0));

end AbandonVB;

architecture AbandonVB of AbandonVB is

type array_5 is array(4 downto 0) of std_logic_vector(1 downto 0);

shared variable Buf:array_5;

shared variable Count_0:integer range 0 to 3;

begin

process(Clk)

begin

    if(Clk='1' and Clk'event)then

        Buf(4):=Buf(3);

        Buf(3):=Buf(2);

        Buf(2):=Buf(1);

        Buf(1):=Buf(0);

        Buf(0):=Hdb3;

        if("00"=Buf(0))then

           Count_0:=Count_0+1;

        elsif(2=Count_0 and ("00"=(Buf(0) xor Buf(3))))then

           Buf(3):="00";

           Buf(0):="00";

           Count_0:=0;

        elsif(3=Count_0 and ("00"=(Buf(0) xor Buf(4))))then

           Buf(0):="00";

           Count_0:=0;

        else Count_0:=0; 

        end if;

        Data_OutP<=Buf(4);

    end if;   

end process;

end AbandonVB;

2.双单极性转换:

library ieee;

use ieee.std_logic_1164.all;

entity Polar is

port(Clk:in std_logic;Data_In:in std_logic_vector(1 downto 0);

    True_Code:out std_logic);

end Polar;

architecture Polar of Polar is

begin

process(Clk)

begin

    if(Clk='1' and Clk'event)then

        if("10"=Data_In or "01"=Data_In)then

           True_Code<='1';

        elsif("00"=Data_In)then

           True_Code<='0';

        end if;

    end if;

end process;

end Polar;

六:总结

通过fpga仿真实现hdb3编码解码,感受到了verilogVHDL的使用不同,VHDL语法比较严格,难弄,个人还是喜欢潇洒的verilog风格些。

 

rar.gifHdb3之fpga实现(工程代码).rar

PARTNER CONTENT

文章评论4条评论)

登录后参与讨论

用户377235 2013-6-15 15:32

很好,学习了。

用户377235 2013-6-2 18:35

else if(Data_In==1'b0) begin Count0<=Count0+2'b1; if(Count0==2'b11)//because it is parall,so it is 3,not 4 begin Count0<=2'b0; Data_OutV<=2'b11; end else Data_OutV<=2'b00; end 这里的 Count0不是竞争了?一个时钟赋值两次

用户377235 2012-11-4 09:47

不过,正好课设是这个题目,学习了

xucun915_925777961 2011-6-1 16:29

不错,来学习一下^_^
相关推荐阅读
用户253961 2012-03-03 11:54
Matlab DIP(瓦)ch3小笔记
         对应上篇文章Matlab DIP(瓦) ch3中用到的一些小知识点,自己联系时写下的小笔记。 matlab版本2009a,matlab7.8的。 f = imr...
用户253961 2012-03-03 11:51
Matlab DIP(瓦) ch3练习
      Matlab是一种图像视频处理实现的好工具,因为matlab是基于数组操作的,而一副图像就是一个数组。因此搞DIP或者CV的是一种必需掌握的工具。     为了学会使用matlab...
用户253961 2012-03-01 18:46
opencv源码解析之滤波前言
     对图像的滤波和平滑是出来数字图像处理和计算机视觉非常重要的一个步骤,那么什么是滤波呢?滤波用编程语言到底是怎么实现的呢?效果怎么样?本人打算学习opencv有关滤波的源码,进一步加强图像...
用户253961 2011-09-24 23:14
怎样在MFC中捕获摄像头并显示出来
Visual_C++编程实现摄像头视频捕捉.pdf 说实话,要用MFC显示摄像头视频,对于入门者来说真是件难事情。网上这方面的文档简直就是太少了。倒是有很多源代码,但是对于MFC不熟悉的同学有源代码...
用户253961 2011-05-30 21:53
基于FPGA的bmp图片显示
好久没有更新博客了,最近去了趟厦门参加考研复试,在深圳实习了1个月,然后赶回来弄毕设,一时间没更新博客。下面把我毕业设计的论文放上来,毕设题目是《基于大规模fpga的bmp图库管理》,这个题目名字...
EE直播间
更多
我要评论
4
17
关闭 站长推荐上一条 /3 下一条