题目:
试用 FPGA 实现如下 32bit 数据
32‘hCA535A7E
的
CMI
码,FPGA 输入时钟
30M,码流输出时钟为 5M,给出代码并仿真。
分析:
为了提高通信系统的有效性,一般需要对将要发送的数据进行
信源编码
,通信信号信源编码的主要任务有两个:一是将信源送出的模拟信号数字化,即 A/D变换,用一定的数字脉冲组合来表示信号的一定幅度。通常将这种过程称为脉冲编码调制(PCM),简称为编码。二是提高信号传输的有效性,进行压缩编码。
编码信号反转码(CMI 码)
:编码信号反转码(CMI 码)是由 CCITT 建议、适合于光信道传输的码型之一。其具体的编码规则是:二进制代码中的“1”码交替
地用 “11”和“00”表示;“0”码则固定地用“01”表示
。CMI 码是一种二元码。CMI 码的特点是电平随二进制数码依次跳变,因而便于恢复定时信号,尤其当用负跳变直接提取定时信号时,不会产生相位不确定问题。其具有检测错误的能力,因为在这种传输码中,只有 00、11、01 这三种码组,而没有 10 这一码组。编码规则如图所示:

为实现题目所需功能,需要设计一个编码模块,对输入数据进行编码,转换规则按照 CMI 的编码规则来编写,注意转码时钟的处理。由上图可知,一位的输入码字将编码为两位的码字,速率为原来的两倍。按照一位一位的转换,还需要一个将并行输入数据转为串行
的处理方法,这样就可以对每一位进行转换,完成编码过程。
主要设计框图如下所示:

设计代码如下:
//CMI 编码:
//二进制代码中的"1"码交替地用 "11"和"00"表示;"0"码则固定地用"01"表 示
module CMIcode(
input clk,
input rst,
input [31:0]data,
output [1:0]cmicode,
output signal
);
parameter clkfreq=30000000, //系统时钟 30MHz
datafreq=5000000,
freqcnt=clkfreq/datafreq;
reg dataclk; //码流时钟
reg [3:0] cnt;
reg [7:0] N;
reg [1:0] cmicode;
reg signal;
reg DATA;
reg [4:0] i;
reg [4:0] bitcnt;
//分频产生 5MHz 时钟
always @(posedge clk or negedge rst) begin
if(!rst) begin
cnt<=1'b0;
dataclk<=1'b0;
end
else if(cnt==(freqcnt>>1)-1'b1) begin
dataclk<=~dataclk;
cnt<=1'b0;
end
else
cnt<=cnt+1'b1;
end
always@(posedge dataclk or negedge rst) begin
if(!rst) begin
i<=5'd31;
end
else begin
i<=i-1'b1;
if(i==1'b0) begin
i<=5'd31;
end
end
end
always@(posedge clk or negedge rst) begin
if(!rst) begin
DATA<=1'b0;
end
else begin
DATA<=data[i];
end
end
always@(posedge dataclk or negedge rst) begin
if(!rst) begin
N<=0;
cmicode<=0;
end
else begin
if(DATA==1'b0) begin
cmicode<=2'b01;
end
else begin
N<=N+1'b1;
if(N[0]==1'b0) begin
cmicode<=2'b11;
end
else begin
cmicode<=2'b00;
end
if(N==32) begin
N<=1'b0;
end
end
end
end
always@(posedge dataclk or negedge rst) begin
if(!rst) begin
signal<=1'b0;
bitcnt<=1'b0;
end
else begin
bitcnt<=bitcnt+1'b1;
if(bitcnt==5'd31) begin
signal<=1'b1;
bitcnt<=1'b0;
end
else begin
signal<=1'b0;
end
end
end
endmodule
仿真的部分结果如下所示:

由图可知,输入数值
32‘hCA535A7E
写成二进制形式后,被编码为 64 位的新二进制数,编码规则满足 CMI 编码,且在最后一位编码完毕后产生了脉冲,与理论结果一致,仿真正确。如按照一定速率传入所需要的输入数据,则可实现串行的 CMI 编码输出。
仿真代码如下:
`timescale 1ns / 1ps
module CMIcode_tb();
reg clk;
reg rst;
reg [31:0] data;
wire [1:0] cmicode;
wire signal;
always #16.67 clk<=~clk;
initial begin
clk<=1'b0;
rst<=1'b0;
data<=32'b0;
#20 rst<=1'b1;
#20 data<=32'hCA535A7E;
end
CMIcode code(
.clk(clk),
.rst(rst),
.data(data),
.cmicode(cmicode),
.signal(signal)
);
endmodule