串并转换在数字电路的设计,特别在通信方面在尤其重要,比如uart 串口协议, iic 串口协议的发送都需要用到并串转换,而接收就相反,需要用到串并转换器,下面我们首先一起来简单设计一个并转串的电路。
1.并转串
并转串的设计思想是这样的,首先准备好一组寄存器,把需要发送的数据放到这个寄存器组里面,然后通过不断左移位(右移),把数据一位一位发送出去,所以我们仅仅要设计一个可以左移位的寄存器组就可以了。
代码:
moduleparallel_to_serial(//并转串
clk,rst_n,
parallel_data,//并行数据输入
parallel_load,//并行数据使能信号
serial_data,//串行数据输出
serial_turn//串行数据使能
);
inputclk,rst_n;
input[7:0]parallel_data;
inputparallel_load;
inputserial_turn;
output[7:0]serial_data;
reg[7:0]data;
always@(posedgeclkornegedgerst_n)
begin
if(!rst_n)
data<=8'd0;
elseif(parallel_load)//使能信号
data<=parallel_data;
elseif(serial_turn)//转换使能
data<={data[6:0],data[7]};
//不断左移位(右移)
else
data<=data[7];
end
assignserial_data=data;
endmodule
`timescale1ns/1ns
`defineclock_period20
moduleparallel_to_serial_tb();
regclk,rst_n;
reg[7:0]parallel_data;
regparallel_load,serial_turn;
wireserial_data;
initialclk=1;
always#(`clock_period/2)clk=~clk;
initialbegin
rst_n=0;
parallel_data=0;
parallel_load=0;
serial_turn=0;
#(`clock_period*5+1);
rst_n=1;
#(`clock_period+1);
parallel_data<=8'b1010_1101;
parallel_load<=1;
#(`clock_period*10);
parallel_load<=0;
serial_turn=1;
#(`clock_period*50);
serial_turn=0;
#(`clock_period*50);
$stop;
end
parallel_to_serialparallel_to_serial(
.clk(clk),.rst_n(rst_n),
.parallel_data(parallel_data),//并行数据输入
.parallel_load(parallel_load),//并行数据使能信号
.serial_data(serial_data),//串行数据输出
.serial_turn(serial_turn)//串行数据使能
);
endmodule
仿真波形图:
由仿真图可看到,当 parallel_load 为高电平的时候, save_data把parallel_data的值给捕获,然后当 serial_turn 为高电平的时候,serial_data 开始输出串行数据, parallel_data = 8’ b10101101 而serial_data 的变化是 1→0→1→0→1→1→0→1 跟 parall_data 的数据完成一样。
2.串转并
串转并的设计思想是这样的,首先准备好一组寄存器,当来了一
位数据的时候,寄存器组左移(右移)一位,然后把发送过来的数据
寄存到寄存器组的最低位(最高位),当一组数据完整接收完毕的时
候,标志位会变高,表示当前数据可以采样。
代码:
moduleserial_to_parallel(//并转串
clk,rst_n,
parallel_data,//并行数据输出
parallel_turn,//并行数据转换使能信号
parallel_finsh,//并行数据输出标志位
serial_data//串行数据输入
);
inputclk,rst_n;
inputserial_data;//串行数据输入
inputparallel_turn,//并行数据转换使能信号
outputreg parallel_finsh,//并行数据输出标志位
outputreg[7:0]parallel_data,//并行数据输出
reg[3:0]cnt;
reg[7:0]data;
wirecmp_result;//计数器比较结果
assigncmp_result=(cnt[3]==1'd1)?1'd1:1'd0;//判断移位次数是否满足8次
always@(posedgeclkornegedgerst_n)
begin
if(!rst_n)
data<=8'd0;
elseif(parallel_turn)
data<={data[6:0],serial_data};
else
data<={data[6:0],1'd0};
end
always@(posedgeclkornegedgerst_n)
begin
if(!rst_n)begin
parallel_data<=8'd0;
parallel_finsh<=1'd0;
end
elsebegin
parallel_data<=data;
parallel_finsh<=cmp_result;//并行数据标准为输出
end
end
always@(posedgeclkornegedgerst_n)
begin
if(!rst_n)
cnt<=4'd0;
elseif(parallel_turn^cmp_result)
cnt<=cnt+1'd1;
elseif(parallel_turn)
cnt<=4'd1;//连续转换,计数器初始值1
else
cnt<=4;d0;
end
endmodule
`timescale1ns/1ns
`defineclock_period20
moduleparallel_to_serial_tb();
regclk,rst_n;
regserial_data;
regparallel_turn;
wireparallel_finsh;
wire[7:0]parallel_data;
initialclk=1;
always#(`clock_period/2)clk=~clk;
initialbegin
rst_n=0;
parallel_turn=0;
serial_data=0;
#(`clock_period*5+1);
rst_n=1;
#(`clock_period*5);
parallel_turn=1;
#(`clock_period*50);
$stop;
end
always@(posedgeclk)
serial_data<={$random}%2;
serial_to_parallelserial_to_parallel(//并转串
.clk(clk),.rst_n(rst_n),
.parallel_data(parallel_data),//并行数据输出
.parallel_turn(parallel_turn),//并行数据转换使能信号
.parallel_finsh(parallel_finsh),//并行数据输出标志位
.serial_data(serial_data)//串行数据输入
);
endmodule
仿真波形图:
由仿真图可以看到, parallel_finsh 为高电平的时候,parallel_data 等于 8’ b11010101,而在 parallel_turn 变成高电平的时候, serial_data 的变化为 1→ 1→ 0→ 1→ 0→1→ 0→ 1,parallel_data 的值完全等于 serial_data 的 8 次连续变化,而截至第二次 parallel_finsh 为高电平的时候, parallel_data 等于8’ b10100010,而 serial_data 接着之前 1→1→0→1→0→1→0→1变化,继续变化成 1→0→1→0→0→0→1→0,也是跟 parallel_data的值完全一样的.