FPGA 学习笔记

本文介绍了串行信号如何转换为并行输出,以及并行数据如何转换为串行输出的过程,同时涵盖了移位寄存器在延迟和数据传输中的应用。此外,详细讲解了边沿检测电路的实现方法,并提供了曼彻斯特编码和解码的模块设计。这些内容是数字通信和信号处理的基础技术。
摘要由CSDN通过智能技术生成

目录

1.串行信号转换为并行输出

2.并行数据转换为串行输出 

3.移位寄存器

4.边沿检测电路

5.曼切斯特编码

6.曼切斯特解码



在此,开始我的第一篇博客,一起加油,一起记录从零开始

1.串行信号转换为并行输出

比如要转换16位的信号,一个周期16位输出一次,前15个周期都在寄存,最后一个周期一块输出

module serial_to_parallel(
input clk,
input rst,
input din,

output reg [15:0] data   //并行数据输出

)

reg[4:0] cnt;            //记数转换个数
reg TEM_CS;              //转换使能信号

always@(posedge clk or negedge rst)
begin
	if(rst == 1'b0)//reset signial
	begin
		data <= 0;
		cnt  <= 0;
		dout <= 0;
	end
	else if(TEM_CS == 1'b0)	
            begin
                if (cnt == 5'd15)   
                    begin      //get all 16bit data,change dout			
                        dout[15-cnt] <= din;
                        dout[15:1]   <= data[15:1];
                        cnt  <= 0;
                    end
                else  
                    begin
                        data[15-cnt] <= din;
                        cnt <= cnt + 1;
                    end		
            end
end

2.并行数据转换为串行输出 

代码实现在conv_en的控制下,将16位并行数据,转换为串行数据输出,并行数据转换为串行数据后,第一个周期是空的,第二个周期才会有数据输出,因为复位过后的din_reg初始值为0。

module parallel_to_serial( 
input clk,
input rst,
input conv_en,
input [15:0] din,
 
output reg dout,
);
 
parameter Num=16;
 
reg [15:0]din_reg; 
reg [4:0]cnt;
 
//先输出高位,左移,若想输出低位则右移
always @(posedge clk or negedge rst)begin
    if(!rst) 
        begin
            dout <= 0;
            din_reg<=3'd0;
            cnt  <= 0;
        end
    else if(conv_en == 1)
        begin
          if(cnt==Num - 1)
             begin
                dout<= din_reg[Num - 1];
                din_reg<=din;
                cnt<=1'd0;
             end
          else 
             begin
                din_reg <= din_reg <<1; 
                dout<= din_reg[Num - 1];
                cnt<=cnt+1'b1;
             end
        end
end

tb

`timescale 1ns/100ps
 
module tb_adf4351;
 
parameter SYSCLK_PERIOD = 100;// 10MHZ
 
reg SYSCLK;
reg NSYSRESET;
reg SYN_EN;
 
initial
begin
    SYSCLK = 1'b1;
    NSYSRESET = 1'b0;
    SYN_EN = 1'b0;
end
 
//
// Reset Pulse
//
initial
begin
    #(SYSCLK_PERIOD * 10 )
        NSYSRESET = 1'b1;
end
 
 
//
// Clock Driver
//
always @(SYSCLK)
    #(SYSCLK_PERIOD / 2.0) SYSCLK <= !SYSCLK;
 
reg [15:0] DIN;
 
integer j;
 
initial
begin
#(SYSCLK_PERIOD*150) SYN_EN = 1'b1;
#(SYSCLK_PERIOD*450) SYN_EN = 1'b0;
end
 
initial
begin
	#1 DIN = 0;
	for(j = 0;j<20;j = j+1)
	begin
		#(SYSCLK_PERIOD*100) DIN = 16'hccee;
		#(SYSCLK_PERIOD*100) DIN = 16'haaaa;
		#(SYSCLK_PERIOD*100) DIN = 16'hccee;
		#(SYSCLK_PERIOD*100) DIN = 16'haaaa;
		#(SYSCLK_PERIOD*100) DIN = 16'hccee;
	end
end
 
wire dout;
wire [15:0]din_reg; 
wire [4:0]cnt;
 
 
 
ADF4351_CTRL ADF4351_CTRL_0 (
    // Inputs
    .clk(SYSCLK),
    .rst(NSYSRESET),
    .din(DIN),
 
    // Outputs
    .dout(dout ),
    .din_reg(din_reg),
    .cnt(cnt),
    .SYN_CLK_F( SYN_CLK_F)
 
);
 
endmodule
 

3.移位寄存器

//延时N个clk时钟周期

parameter N = 10;
reg [N-1:0] temp;
reg input; //需要打拍的信号
reg input_dly10; //打拍后的信号

always@(posedge clk or negedge rst)
    if(!rst)
        temp <= 0;   
    else
        temp <= {temp[N-2:0],input};


assign input_dly10 = temp[N-1]; 

4.边沿检测电路

通过对输入信号进行打两拍进行寄存

input      signal;

reg signal_r1;
reg signal_r2;
 
wire signal_rising;
wire signal_down;
 
always@(posedge clk or negedge rst)
    if(!rst)
    signal_r1<= 1'b0;
    else
    signal_r1<= signal;
 
always@(posedge clk or negedge rst)
    if(!rst)
    signal_r2<= 1'b0;
    else
    signal_r2<= signal_r1;
 
assign signal_rising = ((signal_r1 == 1'b1)&&(signal_r2 == 1'b0))? 1:0; //检测上升延
assign signal_down   = ((signal_r1 == 1'b0)&&(signal_r2 == 1'b1))? 1:0; //检测下降延


//-----------便捷方法如下----------

input        signal;
reg  [3:0]   sig_nsyn_r;   //信号异步移位
wire         signal_rising;
wire         signal_down;

always@(posedge clk or negedge rst)
begin
       if(!rst) 
         sig_nsyn_r <= 4'd0;    //检测的信号平时状态为0
         //sig_nsyn_r <= 4'b11; //检测的信号平时状态为1
       else         
         sig_nsyn_r <= {sig_nsyn_r[2:0],signal};
end

assign     signal_rising = ~sig_nsyn_r[3] & sig_nsyn_r[2];
assign     signal_down   =  sig_nsyn_r[3] & ~sig_nsyn_r[2];

reg 类型变量 加满后自动清零 不需要单独有清零操作

5.曼切斯特编码

module manchester_encoder (

    input clk,
    input rst,
    input enc_in,
    output reg q
  );

  localparam  S0 = 2'd0;
  localparam  S1 = 2'd1;
  localparam  S2 = 2'd2;


  reg [1:0] state ;
  reg clk_base;

  always @(posedge clk or negedge rst)
    begin
      if(!rst)
        clk_base <= 1'b0;
      else
        clk_base <= ~clk_base;
    end

  //状态转换
  always @(posedge clk)
    begin
      if (!rst)
        begin
          q<= 1'b0;
          state <= S0;
        end
      else
        case (state)
          S0:
            begin
              if (clk_base)
                state <= S0;
              else
                if (enc_in)
                  begin
                    q<= 1'b1;
                    state <= S1;
                  end
                else
                  begin
                    q<= 1'b0;
                    state <= S2;
                  end
            end
          S1:
            begin
              q<= 1'b0;
              state <= S0;
            end
          S2:
            begin
              q<= 1'b1;
              state <= S0;
            end
          default:
            state <= S0;
        endcase
    end


endmodule

tb

module tb_manchester_encoder;

  // Parameters

  // Ports
  reg clk = 0;
  reg rst = 0;
  reg enc_in = 0;
  reg clk_base = 0;
  wire q;

  manchester_encoder  manchester_encoder_dut (
    .clk (clk ),
    .rst (rst ),
    .enc_in (enc_in ),
    .q  ( q)
  );

  initial begin
    begin
       clk = 1;
       rst = 0;
       clk_base = 1;
       enc_in = 0;
       #200
       rst = 1;
       #200
       @(posedge clk_base)
       enc_in = 1;
       @(posedge clk_base)
       enc_in = 0;
       @(posedge clk_base)
       enc_in = 1;
       @(posedge clk_base)
       enc_in = 0;

       #200 $stop;
    end
  end

  always
    #10 clk = ! clk ;
always @(posedge clk) clk_base = ~clk_base;

endmodule

6.曼切斯特解码

module manchester_decoder (

    input clk,
    input rst,
    input enc_out,
    output reg dec_out
  );

  localparam  S0 = 2'd0;
  localparam  S1 = 2'd1;
  localparam  S2 = 2'd2;


  reg [1:0] state ;
  reg clk_base;

  always @(posedge clk or negedge rst)
    begin
      if(!rst)
        clk_base <= 1'b0;
      else
        clk_base <= ~clk_base;
    end

  //状态转换
  always @(posedge clk)
    begin
      if (!rst)
        begin
          dec_out<= 1'b0;
          state <= S0;
        end
      else
        case (state)
          S0:
            begin
              if (!clk_base)
                state <= S0;
              else
                if (enc_out)
                  begin
                    dec_out<= 1'b1;
                    state <= S1;
                  end
                else
                  begin
                    dec_out<= 1'b0;
                    state <= S2;
                  end
            end
          S1:
            state <= S0;
          S2:
            state <= S0;
          default:
            state <= S0;
        endcase
    end


endmodule

7.二进制转格雷码

//二进制转格雷码
module bin2gray
#(
	parameter	data_width  = 'd4			//数据位宽
)
(
    input	[data_width - 1 : 0]	bin	,  	//二进制
	output	[data_width - 1 : 0]	gray	//格雷码	
); 
assign gray = (bin >> 1) ^ bin;
endmodule

8.任意偶分频电路

parameter N = 8; // 16分频

reg clk_div_N;
reg [$clog2(N):0] cnt_dig_N;


always@(posedge clk or negedge rst)
begin
    if(!rst)
       cnt_dig_N <= 1'b0;
    else if(cnt_dig_N == N - 1'd1)
       cnt_dig_N <= 1'b0;
    else
       cnt_dig_N <= cnt_dig_N + 1'd1;
end   

always@(posedge clk or negedge rst)
begin
    if(!rst)
       clk_div_N <= 1'b0;
    else if(cnt_dig_N == N - 1'd1)
       clk_div_N <= ~clk_div_N;
    else
       clk_div_N <= clk_div_N;
end   

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值