用Verilog实现串并转换/并串装换
摘要
一、串并转换模块
串转并就是将低3位信号和输入信号一起赋值。因为经过转换后,码元速率会将为原来四分之一,所以设置4分频时钟,将其输出。而并转串就是不断右移,取高位输出。
module serial2para(input clk, rst_n,input ser_data_in,output reg [3:0] para_data_out
);parameter N = 4;//四分频模块
reg [13:0] cnt;
reg clk_out;
reg [3:0] data;always @(posedge clk or negedge rst_n) beginif(cnt == N/2 - 1) begincnt <= 14'b0;clk_out <= ~clk_out;end elsecnt <= cnt + 1'b1;
endalways @(posedge clk or negedge rst_n) beginif(~rst_n) data <= 4'h0;else data <= {data[2:0], d};
endalways @(posedge clk_out or negedge rst_n) beginif(~rst_n) para_data_out <= 4'h0;else para_data_out <= data;
endendmodule
1.1 利用移位寄存器
串行转并行数据输出:采用位拼接技术(移位寄存器),将串行的数据总数先表示出来,然后发送一位数据加一,后面的接收的这样标志:para_data_o <= {para_data_o[6:0], ser_data_i };
module serial_parallel #(parameter DATA_WIDTH = 8
)(input clk,input rst_n,input left_shift,input ser_data_in, //1位串行输入output valid,output reg [DATA_WIDTH-1:0] para_data_o //8位并行输出
);parameter CNT_WIDTH = $clog2(DATA_WIDTH);reg [CNT_WIDTH-1:0] ser_bit_cnt;always @(posedge clk or negedge rst_n) beginif (~rst_n)para_data_o <= {DATA_WIDTH{1'b0}};else if (left_shift == 1'b1)para_data_o <= {para_data_o[DATA_WIDTH-2:0], ser_data_in}; //低位先赋值,左移else if(left_shift == 1'b0)para_data_o <= {ser_data_in, para_data_o[DATA_WIDTH-1:1]}; //高位先赋值,右移
endalways @(posedge clk or negedge rst_n) beginif(~rst_n) beginser_bit_cnt <= {CNT_WIDTH{1'b0}};valid <= 1'h0;endelse if(ser_bit_cnt == DATA_WIDTH-1) beginser_bit_cnt <= {CNT_WIDTH{1'b0}};valid = 1'b1;endelse beginser_bit_cnt <= ser_bit_cnt + 1'b1;valid <= 1'b0;end
endendmodule
1.2 利用计数器
利用计数器cnt 时钟计数,开始数据先给高位,每过一个时钟周期,数据便给低一位。这样便可以达到串转并的效果。
module serial_parallel(parameter DATA_WITH = 8
)(input clk,input rst_n,input ser_data_in,input valid,output reg [DATA_WITH-1:0] para_data_o
);parameter CNT_WIDTH = $clog2(DATA_WITH);//msb first most significant bit 表示二进制数据的最高位
reg [DATA_WITH-1:0] cnt; //计数器0-7 always @(posedge clk or negedge rst_n)beginif(rst_n == 1'b0) beginpara_data_o <= {DATA_WITH{1'b0}};cnt <= {CNT_WIDTH{1'd0}};endelse beginpara_data_o[DATA_WITH-1 - cnt] <= ser_data_in; //高位先赋值cnt <= cnt + 1'b1;end
end/*
//lsb first (least significant bit) 表示二进制数据的最低位reg [2:0] cnt;always @(posedge clk or negedge rst_n)beginif(rst_n == 1'b0) beginpara_data_o <= {DATA_WITH{1'b0}};cnt <= {CNT_WIDTH{1'd0}};endelse beginpara_data_o[cnt] <= data_i; //低位先赋值cnt <= cnt + 1'b1;end
end
*/endmodule