串并转换原理
串并转换,简单来说,就是一个时钟或者多个时钟进来一个数据,将N个位宽为Data_Width的数据拼接成一个数据宽度为N*Data_Width的单个数据。那么其时序应该如下图所示(对于小模块的代码编写,在设计程序前,可以画一下时序图,更容易个人理解与代码的编写,个人观点,不喜勿喷)。
Verilog程序代码
module serial_parallel
#(
parameter Data_Width = 8, //单个数据宽度
parameter Data_Number= 8 //进行串并转换的数据个数
)
(
input clk , //系统时钟信号
input rst_n , //复位信号
input start , //开始串并转换信号
input [Data_Width-1:0] data_in , //串行输出的数据
output reg finish , //串并转换结束信号
output reg [Data_Number*Data_Width-1:0] data_out //并行输出的数据
);
//======================================
// 内部变量声明
//======================================
reg [$clog2(Data_Number)-1:0] cnt;
reg start_reg;
//======================================
// 内部程序
//======================================
//start_reg
always @(posedge clk or negedge rst_n)
if(!rst_n)
start_reg <= 1'b0;
else if(start)
start_reg <= 1'b1;
else if(finish)
start_reg <= 1'b0;
else
start_reg <= start_reg;
//counter
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt <= 0;
else if(start_reg) begin
if(cnt == Data_Number-1) begin
cnt <= 0;
end
else begin
cnt <= cnt + 1'b1;
end
end
else if(finish)
cnt <= 0;
else
cnt <= cnt;
//finish signal
always @(posedge clk or negedge rst_n)
if(!rst_n)
finish <= 1'b0;
else if(cnt == Data_Number-2)
finish <= 1'b1;
else
finish <= 1'b0;
//or
// assign finish = (Data_Number-1) ? (1'b1) : (1'b0);
//======================================
// 数据拼接
//======================================
always @(posedge clk or negedge rst_n)
if(!rst_n)
data_out <= 0;
else if(start_reg)
data_out[cnt*Data_Width+:Data_Width] <= data_in;
else
data_out <= data_out;
endmodule
Test_Bench
module tb_serial_parallel();
parameter Data_Width = 2;
parameter Data_Number= 4;
reg clk,rst_n,start;
wire finish;
reg [Data_Width-1:0] data_in;
wire [Data_Number*Data_Width-1:0] data_out;
initial begin
clk = 1;
start = 0;
data_in = 0;
rst_n = 0;
#60
rst_n = 1;
#20
start = 1'b1;
data_in <= 2'b01;
#20
start = 1'b0;
data_in <= 2'b10;
#20
data_in <= 2'b11;
#20
data_in <= 2'b00;
end
always #10 clk = ~clk;
serial_parallel
#(
.Data_Width (Data_Width ),
.Data_Number(Data_Number)
)
serial_parallel_inst
(
.clk (clk ),
.rst_n (rst_n ),
.start (start ),
.data_in (data_in ),
.finish (finish ),
.data_out (data_out )
);
endmodule
仿真结果
仿真如下图所示,第一个时钟输入二进制数值01,此时计数器cnt=0,将01填入data_out的低2位,于是在第二个时钟的上升沿处得到输出数值data_out=00000001;在第二个时钟输出二进制数值10,此时计数器cnt=1,将10填入data_out的第4位和第3位,于是在第三个时钟的上升沿处得到输出数值data_out=00001001;…,以此类推,在第五个时钟的上升沿处得到串并转换完成的输出数值data_out=00111001。
在这里有一点需要注意的是,串并转换完成信号(finish)需要在计数器cnt计数到Data_Number-2(Data_Number表示数据个数,即几个数据进行串并转换)的时候,拉高为高电平,表示一组数据进行串并转换结束。
所以,在设计过程中,当需要进行数据串并转换时,可以将start信号拉高一个时钟周期,表示开始进行串并转换,而完成了数据的串并转换后,又输出串并转换结束信号finish。
备注:以上仅为个人学习笔记,如有问题,欢迎探讨交流,如有帮助,给个赞吧!