Augus

10.菜鸟初入FPGA之串并转换

0
阅读(10573)

串并转换在数字电路的设计,特别在通信方面在尤其重要,比如uart 串口协议, iic 串口协议的发送都需要用到并串转换,而接收就相反,需要用到串并转换器,下面我们首先一起来简单设计一个并转串的电路。

1.并转串

并转串的设计思想是这样的,首先准备好一组寄存器,把需要发送的数据放到这个寄存器组里面,然后通过不断左移位(右移),把数据一位一位发送出去,所以我们仅仅要设计一个可以左移位的寄存器组就可以了。

代码:

module parallel_to_serial( //并转串 clk,rst_n, parallel_data,//并行数据输入 parallel_load,//并行数据使能信号 serial_data,//串行数据输出 serial_turn//串行数据使能 ); input clk,rst_n; input [7:0]parallel_data; input parallel_load; input serial_turn; output [7:0]serial_data; reg [7:0]data; always @(posedge clk or negedge rst_n) begin if(!rst_n) data <= 8'd0; else if(parallel_load)//使能信号 data <= parallel_data; else if(serial_turn)//转换使能 data <= {data[6:0],data[7]}; //不断左移位(右移) else data <= data[7]; end assign serial_data = data; endmodule `timescale 1ns/1ns `define clock_period 20 module parallel_to_serial_tb(); reg clk,rst_n; reg [7:0]parallel_data; reg parallel_load,serial_turn; wire serial_data; initial clk = 1; always #(`clock_period/2)clk = ~clk; initial begin 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_serial parallel_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

仿真波形图:

2016-04-04_165227.jpg

由仿真图可看到,当 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.串转并

串转并的设计思想是这样的,首先准备好一组寄存器,当来了一
位数据的时候,寄存器组左移(右移)一位,然后把发送过来的数据
寄存到寄存器组的最低位(最高位),当一组数据完整接收完毕的时
候,标志位会变高,表示当前数据可以采样。


代码:

module serial_to_parallel( //并转串 clk,rst_n, parallel_data,//并行数据输出 parallel_turn,//并行数据转换使能信号 parallel_finsh,//并行数据输出标志位 serial_data//串行数据输入 ); input clk,rst_n; input serial_data;//串行数据输入 input parallel_turn,//并行数据转换使能信号 output reg parallel_finsh,//并行数据输出标志位 output reg [7:0]parallel_data,//并行数据输出 reg [3:0]cnt; reg [7:0]data; wire cmp_result;//计数器比较结果 assign cmp_result = (cnt[3] == 1'd1)?1'd1:1'd0;//判断移位次数是否满足8次 always @(posedge clk or negedge rst_n) begin if(!rst_n) data <= 8'd0; else if(parallel_turn) data <= {data[6:0],serial_data}; else data <= {data[6:0],1'd0}; end always @(posedge clk or negedge rst_n) begin if(!rst_n)begin parallel_data <= 8'd0; parallel_finsh <= 1'd0; end else begin parallel_data <= data; parallel_finsh <= cmp_result;//并行数据标准为输出 end end always @(posedge clk or negedge rst_n) begin if(!rst_n) cnt <= 4'd0; else if(parallel_turn ^ cmp_result) cnt <= cnt + 1'd1; else if(parallel_turn) cnt <= 4'd1;//连续转换,计数器初始值1 else cnt <= 4;d0; end endmodule `timescale 1ns/1ns `define clock_period 20 module parallel_to_serial_tb(); reg clk,rst_n; reg serial_data; reg parallel_turn; wire parallel_finsh; wire [7:0]parallel_data; initial clk = 1; always #(`clock_period/2)clk = ~clk; initial begin 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 @(posedge clk) serial_data <= {$random}%2; serial_to_parallel serial_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

仿真波形图:

2016-04-04_174543.jpg

由仿真图可以看到, 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的值完全一样的


Baidu
map