用Verilog实现串并和并串转换
- 首先我们先了解并串和串并转换的原理
串行数据输出是将组成数据和字符的码元按时序逐位予以传输,并行数据传输是将固定位数(通常为8位或16位等)的数据和字符码元同时传输至接收端,串并转换是完成这两种传输方式之间转换的技术。
例如:需要传输的数据有32bit,用串行传输则需要32个时钟周期完成传输,如果用8位并行传输,则32bit数据只需要4个时钟周期就可以完成传输。
并串转换:
并转串电路主要由时钟(clk)、复位信号(rst)、并行输入信号(pdin)、串行输出信号(sdout)和使能信号(en)组成。使能信号表示开始执行并转串操作,由于并转串是移位操作,先将八位数据暂存于一个八位寄存器器中,然后左移输出到一位输出端口,通过一个“移位”来实现,当一次并转串完成后,需要重新载入待转换的并行数据时,使能信号要再起来一次。
串并转换:
新输入的位值成为原来数据的最低位,将原来数据的最高位舍去,这里可以通过一个简单的“连接符”来实现。
- 转换可以采用两种方式实现
一:lsb优先 Least Significant Bit,最低比特,最低位优先
二:msb优先 Most Significant Bit,最高比特,最高位优先
通过位拼接运算符来进行高位舍去,实现左移
module Deserialize(
input clk,
input rst_n,
input data_i,
output reg [7:0] data_o
);
//lsb first
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
data_o <= 8'b0;
end
else begin
data_o <= {data_o[6:0], data_i}; //去掉了高位,让data_i来代替高位,相当于左移一位
end
end
endmodule
补充: 截取数据的不同位数进行拼接:
例: data1 = 0101_1101
data2 = 1011_0011
data = {data1[3:0],data2[7:4]}
则可得:data = 1101_1011
testbench仿真
`timescale 1ns/1ns
`define clock_period 20
module Deserialize_tb;
reg clk;
reg rst_n;
reg data_i;
wire [7:0] data_o;
Deserialize Deserialize_0(
.clk(clk),
.rst_n(rst_n),
.data_i(data_i),
.data_o(data_o)
);
initial clk = 1;
always #(`clock_period/2) clk = ~clk;
initial begin
rst_n=0;
data_i=0;
#(`clock_period*200)
rst_n=1;
#(`clock_period*200)
data_i=1;
#(`clock_period*200)
data_i=0;
# (`clock_period*200)
data_i=1;
# (`clock_period*200)
data_i=0;
# (`clock_period*200)
data_i=1;
# (`clock_period*200)
data_i=0;
# (`clock_period*200)
data_i=1;
# (`clock_period*200)
data_i=0;
# (`clock_period*200)
data_i=1;
# (`clock_period*200)
data_i = 0;
# (`clock_period*200)
data_i = 0;
# (`clock_period*200)
data_i = 0;
# (`clock_period*200)
data_i = 1;
# (`clock_period*200)
data_i = 1;
# (`clock_period*200)
data_i = 1;
# (`clock_period*200)
data_i = 0;
# (`clock_period*200)
$stop;
end
endmodule
波形图
分析:每当clk上升沿且rst_n=1时变化,开始时data_i=0,此时data_o=0000_0000,当data_i=1时,则 data_o <= {data_o[6:0], data_i};data_o=0000_0001,实现了高位舍弃,低位用data_i作为新输入的数据来成为data_o的最低位。
msb优先
//msb first
module Deserialize(
input clk,
input rst_n,
input data_i,
output reg [7:0] data_o
);
reg [2:0] cnt;
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
data_o <= 8'b0;
cnt <= 3'd0; //三位十进制
end
else if(cnt == 3'b111)
cnt <= 3'd0;
else begin
data_o[7 - cnt] <= data_i; //用计数来进行7-0的移位操作
cnt <= cnt + 1'b1;
end
end
endmodule
testbench仿真
`timescale 1ns/1ns
`define clock_period 20
module Deserialize_tb;
reg clk;
reg rst_n;
reg data_i;
reg [2:0] cnt;
wire [7:0] data_o;
Deserialize Deserialize_0(
.clk(clk),
.rst_n(rst_n),
.data_i(data_i),
.data_o(data_o)
);
initial clk = 1;
always #(`clock_period/2) clk = ~clk;
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)
cnt <= 3'd0; //三位十进制
else if(cnt == 3'b111)
cnt <= 3'd0;
else
//用计数来进行7-0的移位操作
cnt <= cnt + 1'b1;
end
initial begin
rst_n=0;
data_i=0;
#(`clock_period*200)
rst_n=1;
#(`clock_period*200)
data_i=1;
#(`clock_period*200)
data_i=1;
# (`clock_period*200)
data_i=1;
# (`clock_period*200)
data_i=1;
# (`clock_period*200)
data_i=1;
# (`clock_period*200)
data_i=1;
# (`clock_period*200)
data_i=1;
# (`clock_period*200)
data_i=1;
# (`clock_period*200)
data_i=1;
# (`clock_period*200)
data_i = 0;
# (`clock_period*200)
data_i = 0;
# (`clock_period*200)
data_i = 0;
# (`clock_period*200)
data_i = 1;
# (`clock_period*200)
data_i = 1;
# (`clock_period*200)
data_i = 1;
# (`clock_period*200)
data_i = 1;
# (`clock_period*200)
data_i = 1;
# (`clock_period*200)
data_i = 1;
# (`clock_period*200)
data_i = 1;
# (`clock_period*200)
data_i = 1;
# (`clock_period*200)
data_i = 1;
# (`clock_period*200)
$stop;
end
endmodule
波形图