HDB3 的编码 ②(Verilog 语言实现)2021-9-12


前言

在上一篇有关hdb3 的编码和译码的介绍中,简单介绍了hdb3的编码规则,以及使用MATLAB进行了仿真实验。感兴趣的朋友可以去看一下。HDB3 的编码与译码 ①(MATLAB 实现)2021-9-11。仿真实验过后,就要在FPGA中实现,通过这次学习也是对FPGA的相关知识有了进一步的了解。下面也是介绍了相关部分的设计,主要的参考资料是:HDB3码编码器及解码器verilog代码编程及实现这个课件给出了详细的设计流程,编码设计主要参考了这个课件的介绍。
本篇文章也是介绍了编码的实现过程。译码过程在下一篇文章中介绍。


一、实现HDB3编码步骤

梳理好完善逻辑就是成功的一半,要实现的HDB3的编码不可操之过急。上述课件中,给出了详细的过程以及相应的代码。
在来哦哦饥饿这个编程最初,我一直也不是很理解hdb3编码中的V还有B要用什么代替,以及最后的正负极性,要如何处理?这些问题都在课件中给出了相应的解释。
跟做MATLAB的仿真一样,在编码之中一共有四中符号:1,0,B,V。那就用一个两位的寄存器来分别表示就可以了。
0:00
1:01
B:10
V:11
这就是开始的“原材料”准备。下面开始分模块。
主要的流程有三个:
第一步:插入符号V。
第二步:插入符号B。
第三步整体统一改变极性。并且将代表各符号的值统一成0,+1和-1。
分好了模块,就可以一个模块一个模块的进行设计。

1. 插入V模块

第一个模块是插V模块。在这个模块中,要将输入进来的单极性信号转变为两位的信号,同时在固定格式下插上V。那么固定格式是什么格式那?在HDB3的编码规则中,不允许有超过三个0连续,如果有就将第四个0转变成V那么这第四个零就是要插V的位置了。
首先先来完成逻辑框图。
在这里插入图片描述

整体的逻辑就是进行判断分类,再分类。

module add_v
(
	Clk,Rstn_,
	DataIn,DataOut
);

	input Clk;
	input Rstn_;
	
	input DataIn;
	
	output [1:0] DataOut;
	
	reg [1:0] DataOut;
	
	reg [1:0] count; //连“0”计数器 最多就会有4个 0
	
	always @ (posedge Clk or negedge Rstn_)
		if (!Rstn_)
		begin
			count <= 2'd0;
			DataOut <= 2'b00;
		end
		else
		begin
			if (DataIn == 1'b1)  //如果收到的是 1 
				begin
					count <= 2'd0;
					DataOut <= 2'b01;  //先不考虑极性
				end
			else
			begin
				count <= count + 1'b1;
				if (count == 2'd3) // 连 0 达到 4个 输出 “V” 11
				begin
					count <= 2'd0;
					DataOut <= 2'b11;
				end
				else
					DataOut <= 2'b00; //连 0 未达到 4个 输出 00 
			end
		end				
endmodule

简单看一下仿真结果:
在这里插入图片描述
可以看到在仿真结果图中,开始端的01前面有一小段00,那是因为在时钟的上升沿手到达之前,编码的值就是00。从而可以的出一个结论,在实际使用hdb3编码模块的时候应当加一个使能位,使用的顺序应当是先给好数据,随后快速地使能模块,再进行编码,这样保证整体的编码质量。

2. 插入B模块

插入B模块可以说是整个编码的核心了,还是一样捋一下逻辑。什么时候才会插入B那?当两个V之间的1的个数为偶数个时,就需要将后面那个V前面的三个0中的第一个0转变成B。
这其中有几个很重要的点:
第一个点就是要检测V,同时转变的是V之后的第四个值,所以要设计一个四位的移位寄存器。这样才能保证,既能看到前面又能变后面。
第二个点就是偶数这个问题要怎么处理,如何判断1的个数是奇数还是偶数那?这里的解决方案非常牛逼,我们是不知道两个V之间是会有多少个1的,有可能很多,也有可能很少,所以不可能将每一个1都计上去,这里就利用了寄存器会溢出的特性。
定义一个一位的寄存器,有一个奇数个1,寄存器的值就是1。有偶数个1,寄存器的值就是0;

/**
 时间:2021年9月9日 
 文件名:add_B.v
 所属项目:hdb3 编解码
 顶层模块:hdb3.v
 模块名称及其描述:hdb3 编码过程中实现插入 “B” 的操作
 修改记录:无
*/
module add_B
(
	Clk,Rstn_,
	DataIn_B,DataOut_B
);

	input Clk;
	input Rstn_;
	
	input [1:0] DataIn_B;
	
	output [1:0] DataOut_B;
	
	
	
	/****************V和1的计数器设计************************/	
	
	reg count_1;  //对 “1” 的计数器
	
	reg [1:0] count_V;  //对 “V” 的计数器
	
	always @ (posedge Clk or negedge Rstn_)
		if (!Rstn_)
		begin
			count_1 <= 1'b0;
			count_V <= 1'b0;
		end
		else
		begin
			if(data[0] == 2'b11)  //输入进来的是 V 将1的计数器清零,同时将V的计数器+1
			begin
				count_1 <= 1'b0; 
				count_V  = count_V + 1'b1;
			end
			else if(data[0] == 2'b01) //输入进来的是 1  //1的计数器加1 
			begin
				count_1 <= count_1 + 1'b1;
				if(count_V  == 2'd2)//当这个V当过后边的V时,重新将它变成前面的V
					count_V <= 1'b1;
			end
			else			//输入进来的是 0 
			begin
				if(count_V  == 2'd2)//当这个V当过后边的V时,重新将它变成前面的V
					count_V <= 1'b1;
			end
		end
		
		
	/****************四位的移位寄存器************************/	
	
	reg [1:0] data[3:0];
	reg [1:0] i;
	always @ (posedge Clk or negedge Rstn_)
		if (!Rstn_)
		begin
		//	for (i=0; i<3; i=i+1)
		//		data[i] <= 2'b0;
		end
		else
		begin
			data[3] <= data[2];
			data[2] <= data[1];
			data[1] <= data[0];
			data[0] <= DataIn_B;
		end

		
	/***************数据输出端口的设计*************************/	
	
	//count_1==0 && count_V==1 表示 1的个数是偶数个 
	//data[0]==2'b11 表示偶数个的个数是在两个 V 之间数出来的 
	assign DataOut_B = (count_1==0)&&(count_V==1)&&(data[0]==2'b11)? 2'b10:data[3];
	
	
endmodule

前文给出的资料中,PPT中的例程代码是有一个小小的bug在这里做了订正。他的bug是,如果源码的开始是110000…也就是开始就会有偶数个1。那么他也会在第一个V的前面加上B,这是不合理的。这里给出了修正。
现在来分析一下每个计数器的工作逻辑。
在这里插入图片描述
可以看到只有在两个V之间1的个数为偶数个的时候才会插入一个B。
看一下仿真的结果:
在这里插入图片描述
由于四位移位寄存器的存在,所以输出会滞后四个钟。同时还要注意的是,第一个B应该是0,也是PPT中的bug。

3. 整理极性

通过前两部的整理,信号源码已经整理成,00,01,10,11了,也就是0,1,B,V。这里开始整理极性,同时在整理完极性之后的输出应该整理为0,+1,-1。这里用00来代表0,用01来代表+1,用10来代表-1;
极性的变化规则是:
1.1和 B看成一组,正负交替变化,一般第一个1的极性是负号。
2.V的极性看成一组,正负交替变化,第一个V的极性和前一个非0符号的极性相同。
这里对B模块输入进来的数据进行判断整理即可。还是简单的画一个逻辑图。
在这里插入图片描述
极性的整体统一还有另一个功能,就是产生脉冲,当然输出的数据两位也可以当做正负脉冲来使用,这里还是使用了两个端口来产生正负脉冲。
整体的代码:


module polar
(
	Clk,Rstn_,
	DataOut_B,PolarOut,
	BP,BN
);

	input Clk;
	input Rstn_;
	
	input [1:0] DataOut_B;
	
	output [1:0] PolarOut;
	
	//设计正脉冲和负脉冲
	output BP;  // 正脉冲
	output BN;  // 负脉冲
	
	reg [1:0] PolarOut;
	
	reg BP;  
	reg BN;
	
	/****************极性翻转************************/
	
	reg even = 0;

	always @ (posedge Clk or negedge Rstn_)
		if (!Rstn_)
		begin

		end
		else 
		begin
			if( (DataOut_B == 2'b01) || (DataOut_B == 2'b10) ) //输入为 1 或者 B 两者翻转
			begin
				if(even == 1) //将初始位设计成 -1
					PolarOut <= 2'b01;
				else  
					PolarOut <= 2'b10;  
				even <= ~even; //将标识位翻转
			end
			else if(DataOut_B == 2'b11) //输入进来的是 V
			begin
				if(even == 1)
					PolarOut <= 2'b10;
				else
					PolarOut <= 2'b01;
			end
			else  //输入为 00 
				PolarOut <= 2'b00;
		end
		
		
	/****************极性翻转************************/		
	
	always @ (posedge Clk or negedge Rstn_)
		if (!Rstn_)
		begin

		end	
		else
		begin
			if(PolarOut == 2'b01) //输入为 +1
			begin
				BP <= 1'b1;
				BN <= 1'b0;
			end
			else if(PolarOut == 2'b10)  //输入为 -1
			begin
				BP <= 1'b0;
				BN <= 1'b1;
			end			
			else
			begin
				BP <= 1'b0;
				BN <= 1'b0;
			end			
			
		end
endmodule

其中主要注意的点就是1和V的极性,他们各自是交替变化,但同时第一个V的极性又和前一个1的极性有关系(这里的1包含B),这里就是用一个寄存器even来控制整体的极性。来看一下仿真结果。
在这里插入图片描述
和自己手算的结果比较一下,可以得出相应的结果。


二、 总结

通过对hdb3的编码,通过这个小课题使得自己认识到,基本还是比较差,另外也产生另一个问题,就是不会使用相应的仿真工具也就是ModelSim,之前使用的一直是逻辑分析仪,没有使用过这种,数据量的仿真,都是跑跑时序,现阶段也是总结出来最适合我的开发方法,如果要调试时序类的程序,跑跑时序什么的有条件就可以用逻辑分析仪,要是处理数据编码什么的 程序还是需要到仿真环境ModelSim。积累吧,积累多了自然就会了。

  • 17
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: HDB3编码是一种高密度双极性3零编码,用于将数字信号转换为电信号以便在传输线路上传输。以下是HDB3编码Verilog实现步骤: 1. 定义模块的输入和输出端口: ```verilog module hdb3_encoder( input clk, input rst, input [7:0] data_in, output [7:0] data_out, output bipolar_out ); ``` 其中,`clk` 是时钟输入端口,`rst` 是复位输入端口,`data_in` 是输入数据端口,`data_out` 是输出数据端口,`bipolar_out` 是双极性输出端口。 2. 定义内部变量: ```verilog reg [3:0] count = 0; reg last_data = 0; reg [3:0] zero_count = 0; reg bipolar = 1; ``` 其中,`count` 记录当前连续出现的零的数量,`last_data` 记录上一次的数据,`zero_count` 记录当前连续出现的零的数量,`bipolar` 记录当前输出的信号的极性。 3. 实现HDB3编码逻辑: ```verilog always @(posedge clk) begin if (rst) begin count <= 0; last_data <= 0; zero_count <= 0; bipolar <= 1; data_out <= 0; bipolar_out <= 0; end else begin if (data_in == 1) begin if (last_data == 1) begin count <= count + 1; if (count == 4) begin data_out <= 0; bipolar_out <= bipolar; bipolar <= ~bipolar; count <= 0; end else begin data_out <= 1; bipolar_out <= bipolar; end end else begin data_out <= 1; bipolar_out <= bipolar; count <= 1; last_data <= 1; end end else begin if (last_data == -1) begin count <= count + 1; if (count == 4) begin if (zero_count == 0) begin data_out <= 0; bipolar_out <= bipolar; bipolar <= ~bipolar; end else begin data_out <= 1; bipolar_out <= ~bipolar; end count <= 0; zero_count <= 0; end else begin data_out <= -1; bipolar_out <= bipolar; end end else begin zero_count <= zero_count + 1; if (zero_count == 4) begin data_out <= 0; bipolar_out <= bipolar; bipolar <= ~bipolar; zero_count <= 0; end else begin data_out <= 0; bipolar_out <= 0; end end last_data <= -1; end end end ``` 在上述逻辑中,当输入数据为 1 时,根据上一次的数据和零的数量进行编码。当输入数据为 0 时,根 ### 回答2: HDB3编码是一种数字信号编码方法,用于在数字通信中传输数据。其Verilog实现的步骤如下: 1. 定义输入和输出信号:在Verilog代码中,首先需要定义输入信号和输出信号。输入信号是要进行HDB3编码的数字信号,输出信号是编码后得到的数字信号。 2. 实现HDB3编码逻辑:在Verilog代码中,使用逻辑门和时序元件来实现HDB3编码逻辑。首先,对输入信号进行判断,如果是0,则将编码后的信号分为两种情况:如果出现连续的0次数为偶数,则按照正常的替换规则进行编码。如果出现连续的0次数为奇数,则进行特殊的替换规则。具体的编码规则可以参考HDB3编码标准。 3. 设计状态机:HDB3编码过程中包含状态变化的过程,需要使用状态机来实现状态的切换。在Verilog代码中,需要定义状态寄存器和状态转移逻辑,根据输入信号和当前状态来确定下一个状态。 4. 运行仿真和验证:编写测试代码,针对不同的输入信号进行仿真和验证。通过输出结果和编码要求进行比对和验证。 5. 实现其他功能:根据设计需求,可能需要添加其他功能,如错误检测、时钟控制等。根据具体需求进行功能扩展。 6. 进行综合和布局布线:将Verilog代码进行综合和布局布线,在芯片级别进行优化和设计。 7. 进行验证和调试:通过验证和仿真工具对设计进行验证和调试。根据验证结果和仿真波形进行调整和优化。 8. 生成比特流或物理层信号:根据设计需求,通过FPGA或ASIC等芯片将编码后的数字信号转换为比特流或物理层信号,用于传输和接收数据。 总结:HDB3编码Verilog实现步骤包括定义输入和输出信号、实现编码逻辑、设计状态机、运行仿真和验证、实现其他功能、进行综合和布局布线、进行验证和调试,最后生成比特流或物理层信号。 ### 回答3: HDB3(High Density Bipolar 3 Zeros)编码是一种用于数字通信的线路编码方式,常用于ISDN(Integrated Services Digital Network)等应用。下面是HDB3编码Verilog实现步骤。 1. 首先,根据HDB3编码规则,确定要编码的信号序列。 2. 在Verilog中,可以使用寄存器或变量来存储信号序列。初始化存储变量,并为每个存储单元设置合适的位宽。 3. 根据HDB3编码规则,实现以下步骤: a. 将输入的信号逐个读取,并根据当前信号位和前一个信号位的状态,判断要编码的信号。 b. 如果当前信号位为0,检查前一个信号位的状态。 c. 如果前一个信号位是高电平(positive pulse),根据前一个信号位的计数器状态执行以下操作: - 如果前一个计数器状态是0,输出当前信号位的编码(偶性编码)。 - 如果前一个计数器状态是1或2,输出替换信号“000V”(V为与上一个替换信号相反的极性)。 - 如果前一个计数器状态是3,输出下一个计数器状态为1的替代信号。 d. 如果前一个信号位是零电平(zero pulse),根据前一个计数器状态执行以下操作: - 如果前一个计数器状态为0或1,输出当前信号位的编码。 - 如果前一个计数器状态为2或3,输出零编码“000V”(V为与前一个替换信号相反的极性)。 e. 更新前一个信号位状态和计数器状态。 4. 将输出的编码信号保存到输出寄存器或变量中。 5. 重复步骤3和4,直到完成所有信号的编码。 6. 可以通过模拟器或FPGA平台来验证和测试Verilog实现。 以上是HDB3编码Verilog实现步骤,根据具体的需求和环境,可能会有不同的实现方式和细节处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值