[Verilog]用Verilog实现串并转换/并串转换

2023-12-15 11:18:35

用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) begin
    if(cnt == N/2 - 1) begin
    	cnt     <= 14'b0;
    	clk_out <= ~clk_out;
    end 
    else
	    cnt <= cnt + 1'b1;
end
 

always @(posedge clk or negedge rst_n) begin
    if(~rst_n) data <= 4'h0;
    else       data <= {data[2:0], d};
end
 
always @(posedge clk_out or negedge rst_n) begin
    if(~rst_n) para_data_out <= 4'h0;
    else       para_data_out <= data;
end
 
endmodule

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) begin
	if (~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]};	//高位先赋值,右移
end

always @(posedge clk or negedge rst_n) begin
	if(~rst_n) begin
      ser_bit_cnt <= {CNT_WIDTH{1'b0}};
      valid       <= 1'h0;
    end
    else if(ser_bit_cnt == DATA_WIDTH-1) begin
      ser_bit_cnt <= {CNT_WIDTH{1'b0}};
      valid = 1'b1;
    end
    else begin
      ser_bit_cnt <= ser_bit_cnt + 1'b1;
      valid       <= 1'b0;
    end
end


endmodule

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)begin
    if(rst_n == 1'b0) begin
        para_data_o <= {DATA_WITH{1'b0}};
        cnt <= {CNT_WIDTH{1'd0}};
    end
    else begin
        para_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)begin
    if(rst_n == 1'b0) begin
        para_data_o <= {DATA_WITH{1'b0}};
        cnt <= {CNT_WIDTH{1'd0}};
    end
    else begin
        para_data_o[cnt] <= data_i;   //低位先赋值
        cnt <= cnt + 1'b1;
    end
end
*/
 
endmodule

文章来源:https://blog.csdn.net/gsjthxy/article/details/134928214
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。