目录

前言

题目

解题思路

基本框架

代码思路

第一部分(FPGA的FIFO以及串口发送接收)

1.FIFO

2.(FPGA串口发送)

3.FPGA串口接收

4.总结

第二部分(stm32接收数据进行FFT识别波形以及频率并发送)

1.stm32串口接收

2.stm32进行FFT

3.stm32串口发送

第三部分(FPGA得到波形与频率后生成波形)

第四部分(FPGA锁相)

1.鉴相

2.环路滤波

3.反馈

第五部分(DAC输出)

第六部分(移相)

1.按键消抖

2.按键设置相位差

3.数码管显示相位

第七部分(FPGA代码总结)

后记


前言

本文章除开要求一使用的增益为一的加法器以外,其余皆由FPGA+stm32实现。

题目

解题思路

题目要求从信号发生器输出两路波形A和B并通过一个增益为1的加法器生成信号C,我们需要做的就是从C中将A'和B'解出来,有一种方法是将C进行傅里叶变换然后识别出两路波形分别是什么然后将频域分离出来随后进行傅里叶逆变换再输出就行,还有一种方法就是本文章所使用的方法,由于题目不考虑波形的相位和峰峰值与原波形的关系,所以我们可以将输入的C信号进行傅里叶变换识别出两路波形的频率,并且由于AB波的峰峰值为固定的1V,而正弦波为单音信号频谱集中,三角波有三次谐波的存在导致基波信号的峰峰值会被削弱使得可以通过比较频谱中基波的幅值大小来识别输入的波形是三角波还是正弦波,然后就能得到两路波的波形以及频率,随后就可以使用dds重构出A'和B'波形,但是这个方法有一个问题就是由于重构的波形与信号发生器所出的波形不在同一个时钟上,由于不同时钟的微小差异,会使得相位差在不停的累积就会产生信号漂移,所以我们需要设计一个锁相环将生成的信号与原信号的相位锁住就不会再产生漂移了,移相只需要改变ROM表的地址就可以实现。

基本框架

C信号——>高速ADC——>FPGA——>FIFO——>串口——>stm32——>FFT——>识别波形和频率——>串口——>DDS——>锁相环——>高速DAC——>A',B'

代码思路

第一部分(FPGA的FIFO以及串口发送接收)

1.FIFO

此处使用的FIFO为黑金AX7035B所给的历程,其中写入速率为1MHz(与高速ADC的采样频率相同),读取速率为12.5KHz(串口的发送速率)

assign ad9238_clk_ch0 = clk_1M;
wire wr_en,rd_en,full,empty,wr_rst_busy,rd_rst_busy;
wire [10:0] rd_data_count,wr_data_count;
reg [7:0] w_data;
localparam      W_IDLE      = 1;
localparam      W_FIFO     = 2; 
localparam      R_IDLE      = 1;
localparam      R_FIFO     = 2; 

reg[2:0]  write_state;
reg[2:0]  next_write_state;
reg[2:0]  read_state;
reg[2:0]  next_read_state;

wire [7:0] rx_data,tx_data;
reg tx_vilid;

always@(posedge clk_1M or negedge rst)
begin 
	if(rst == 1'b0)
		write_state <= W_IDLE;
	else
		write_state <= next_write_state;
end

always@(*)
begin
	case(write_state)
		W_IDLE:
			if(empty == 1'b1)               //FIFO is empty, start writing FIFO
				next_write_state <= W_FIFO;
			else
				next_write_state <= W_IDLE;
		W_FIFO:
			if(full == 1'b1)                //FIFO is full
				next_write_state <= W_IDLE;
			else
				next_write_state <= W_FIFO;
		default:
			next_write_state <= W_IDLE;
	endcase
end

assign wr_en = (next_write_state == W_FIFO) ? 1'b1 : 1'b0; 

always@(posedge clk_1M or negedge rst)
begin
	if(rst == 1'b0)
		w_data <= 16'd0;
	else
	   if (wr_en == 1'b1)
		    w_data <= ADC;
		else
          w_data <= ADC;		
end



always@(posedge clk_1M or negedge rst)
begin
	if(rst == 1'b0)
		read_state <= R_IDLE;
	else
		read_state <= next_read_state;
end

always@(*)
begin
	case(read_state)
		R_IDLE:
			if(full == 1'b1)               //FIFO is full, starting read FIFO
				next_read_state <= R_FIFO;
			else
				next_read_state <= R_IDLE;
		R_FIFO:
			if(empty == 1'b1)              //FIFO is  empty
				next_read_state <= R_IDLE;
			else
				next_read_state <= R_FIFO;
		default:
			next_read_state <= R_IDLE;
	endcase
end
reg [10:0] rd_data_count_last;
always@(posedge clk or negedge rst)
begin
    if(!rst)
        rd_data_count_last<=0;
    else
    begin
        rd_data_count_last<=rd_data_count;
        if(rd_data_count_last!=rd_data_count && rd_en)
            tx_vilid<=1;
        else
            tx_vilid<=0;
    end    
end

assign rd_en = (next_read_state == R_FIFO) ? 1'b1 : 1'b0; 

fifo fifo (
  .rst(~rst),                      // input wire rst
  .wr_clk(clk_1M),                // input wire wr_clk
  .rd_clk(clk_100K),                // input wire rd_clk
  .din(w_data),                      // input wire [7 : 0] din
  .wr_en(wr_en),                  // input wire wr_en
  .rd_en(rd_en),                  // input wire rd_en
  .dout(tx_data),                    // output wire [7 : 0] dout
  .full(full),                    // output wire full
  .empty(empty),                  // output wire empty
  .rd_data_count(rd_data_count),  // output wire [10 : 0] rd_data_count
  .wr_data_count(wr_data_count)  // output wire [10 : 0] wr_data_count
);

2.(FPGA串口发送)

此处串口发送使用的也是黑金的AX7035B的历程(在FIFO中每读一个数就通过串口发送出去)

uart_tx#(
.CLK_FRE(50), 
.BAUD_RATE(115200) //serial baud rate
)uart_tx(
.clk(clk),              //clock input
.rst_n(rst),            //asynchronous reset input, low active 
.tx_data(tx_data),          //data to send
.tx_data_valid(tx_vilid),    //data to be sent is valid
.tx_pin(tx_pin)            //serial data output
); 
module uart_tx
#(
	parameter CLK_FRE = 50,      //clock frequency(Khz)
	parameter BAUD_RATE = 115200 //serial baud rate
)
(
	input                        clk,              //clock input
	input                        rst_n,            //asynchronous reset input, low active 
	input[7:0]                   tx_data,          //data to send
	input                        tx_data_valid,    //data to be sent is valid
	output reg                   tx_data_ready,    //send ready
	output                       tx_pin            //serial data output
);
//calculates the clock cycle for baud rate 
localparam                       CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
//state machine code
localparam                       S_IDLE       = 1;
localparam                       S_START      = 2;//start bit
localparam                       S_SEND_BYTE  = 3;//data bits
localparam                       S_STOP       = 4;//stop bit
reg[2:0]                         state;
reg[2:0]                         next_state;
reg[15:0]                        cycle_cnt; //baud counter
reg[2:0]                         bit_cnt;//bit counter
reg[7:0]                         tx_data_latch; //latch data to send
reg                              tx_reg; //serial data output
assign tx_pin = tx_reg;
always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		state <= S_IDLE;
	else
		state <= next_state;
end

always@(*)
begin
	case(state)
		S_IDLE:
			if(tx_data_valid == 1'b1)
				next_state <= S_START;
			else
				next_state <= S_IDLE;
		S_START:
			if(cycle_cnt == CYCLE - 1)
				next_state <= S_SEND_BYTE;
			else
				next_state <= S_START;
		S_SEND_BYTE:
			if(cycle_cnt == CYCLE - 1  && bit_cnt == 3'd7)
				next_state <= S_STOP;
			else
				next_state <= S_SEND_BYTE;
		S_STOP:
			if(cycle_cnt == CYCLE - 1)
				next_state <= S_IDLE;
			else
				next_state <= S_STOP;
		default:
			next_state <= S_IDLE;
	endcase
end
always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		begin
			tx_data_ready <= 1'b0;
		end
	else if(state == S_IDLE)
		if(tx_data_valid == 1'b1)
			tx_data_ready <= 1'b0;
		else
			tx_data_ready <= 1'b1;
	else if(state == S_STOP && cycle_cnt == CYCLE - 1)
			tx_data_ready <= 1'b1;
end


always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		begin
			tx_data_latch <= 8'd0;
		end
	else if(state == S_IDLE && tx_data_valid == 1'b1)
			tx_data_latch <= tx_data;
		
end

always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		begin
			bit_cnt <= 3'd0;
		end
	else if(state == S_SEND_BYTE)
		if(cycle_cnt == CYCLE - 1)
			bit_cnt <= bit_cnt + 3'd1;
		else
			bit_cnt <= bit_cnt;
	else
		bit_cnt <= 3'd0;
end


always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		cycle_cnt <= 16'd0;
	else if((state == S_SEND_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)
		cycle_cnt <= 16'd0;
	else
		cycle_cnt <= cycle_cnt + 16'd1;	
end

always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		tx_reg <= 1'b1;
	else
		case(state)
			S_IDLE,S_STOP:
				tx_reg <= 1'b1; 
			S_START:
				tx_reg <= 1'b0; 
			S_SEND_BYTE:
				tx_reg <= tx_data_latch[bit_cnt];
			default:
				tx_reg <= 1'b1; 
		endcase
end

endmodule 

3.FPGA串口接收

此处串口接收使用的也是黑金的AX7035B的历程(帧头为FF 帧尾为FE 第一个数据为第一个波的波形 第二个数据为第一个波的频率 第三个数据为第二个波的波形 第四个数据为第二个波的频率)

reg [7:0] data1,data2,data3,data4;
reg rx_start;
wire rx_done;
reg [2:0] state; 
      
uart_rx
#(
.CLK_FRE(50),      //clock frequency(Mhz)
.BAUD_RATE(115200) //serial baud rate
)uart_rx
(
.clk(clk),              //clock input
.rst_n(rst),            //asynchronous reset input, low active 
.rx_data(rx_data),          //received serial data
.rx_data_ready(rx_start),    //data receiver module ready
.rx_data_valid(rx_done),    //received serial data is valid
.rx_pin(rx_pin)            //serial data input
);    
 

always@(posedge clk or negedge rst)
begin
    if(!rst)
    begin
        state<=0;
        data1<=0;
        data2<=0;
        data3<=0;
        data4<=0;
    end
    else
    begin
        case(state)
        3'b000:
        begin
            rx_start<=1;
            if(rx_done)
            begin
                if(rx_data==8'hFF)
                begin
                    rx_start<=0;
                    state<=state+1;
                    data1<=0;
                    data2<=0;
                    data3<=0;
                    data4<=0;
                end
            end
        end
        3'b001:
        begin
            rx_start<=1;
            if(rx_done)
            begin
                rx_start<=0;
                data1<=rx_data;
                state<=state+1;
            end
        end
        3'b010:
        begin
            rx_start<=1;
            if(rx_done)
            begin
                rx_start<=0;
                data2<=rx_data;
                state<=state+1;
            end
        end
        3'b011:
        begin
            rx_start<=1;
            if(rx_done)
            begin
                rx_start<=0;
                data3<=rx_data;
                state<=state+1;
            end
        end
        3'b100:
        begin
            rx_start<=1;
            if(rx_done)
            begin
                rx_start<=0;
                data4<=rx_data;
                state<=state+1;
            end
        end
        3'b101:
        begin
            rx_start<=1;
            if(rx_done)
            begin
                if(rx_data==8'hFE)
                begin
                    rx_start<=0;
                    state<=0;
                    wave1<=data1;
                    wave1_freq<=data2;
                    wave2<=data3;
                    wave2_freq<=data4;
                end
                else
                begin
                    rx_start<=0;
                    state<=0;
                    data1<=0;
                    data2<=0;
                    data3<=0;
                    data4<=0;
                end
            end
        end
        endcase
    end
end
module uart_rx
#(
	parameter CLK_FRE = 50,      //clock frequency(Mhz)
	parameter BAUD_RATE = 115200 //serial baud rate
)
(
	input                        clk,              //clock input
	input                        rst_n,            //asynchronous reset input, low active 
	output reg[7:0]              rx_data,          //received serial data
	output reg                   rx_data_valid,    //received serial data is valid
	input                        rx_data_ready,    //data receiver module ready
	input                        rx_pin            //serial data input
);
//calculates the clock cycle for baud rate 
localparam                       CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
//state machine code
localparam                       S_IDLE      = 1;
localparam                       S_START     = 2; //start bit
localparam                       S_REC_BYTE  = 3; //data bits
localparam                       S_STOP      = 4; //stop bit
localparam                       S_DATA      = 5;

reg[2:0]                         state;
reg[2:0]                         next_state;
reg                              rx_d0;            //delay 1 clock for rx_pin
reg                              rx_d1;            //delay 1 clock for rx_d0
wire                             rx_negedge;       //negedge of rx_pin
reg[7:0]                         rx_bits;          //temporary storage of received data
reg[15:0]                        cycle_cnt;        //baud counter
reg[2:0]                         bit_cnt;          //bit counter

assign rx_negedge = rx_d1 && ~rx_d0;

always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
	begin
		rx_d0 <= 1'b0;
		rx_d1 <= 1'b0;	
	end
	else
	begin
		rx_d0 <= rx_pin;
		rx_d1 <= rx_d0;
	end
end


always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		state <= S_IDLE;
	else
		state <= next_state;
end

always@(*)
begin
	case(state)
		S_IDLE:
			if(rx_negedge)
				next_state <= S_START;
			else
				next_state <= S_IDLE;
		S_START:
			if(cycle_cnt == CYCLE - 1)//one data cycle 
				next_state <= S_REC_BYTE;
			else
				next_state <= S_START;
		S_REC_BYTE:
			if(cycle_cnt == CYCLE - 1  && bit_cnt == 3'd7)  //receive 8bit data
				next_state <= S_STOP;
			else
				next_state <= S_REC_BYTE;
		S_STOP:
			if(cycle_cnt == CYCLE/2 - 1)//half bit cycle,to avoid missing the next byte receiver
				next_state <= S_DATA;
			else
				next_state <= S_STOP;
		S_DATA:
			if(rx_data_ready)    //data receive complete
				next_state <= S_IDLE;
			else
				next_state <= S_DATA;
		default:
			next_state <= S_IDLE;
	endcase
end

always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		rx_data_valid <= 1'b0;
	else if(state == S_STOP && next_state != state)
		rx_data_valid <= 1'b1;
	else if(state == S_DATA && rx_data_ready)
		rx_data_valid <= 1'b0;
end

always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		rx_data <= 8'd0;
	else if(state == S_STOP && next_state != state)
		rx_data <= rx_bits;//latch received data
end

always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		begin
			bit_cnt <= 3'd0;
		end
	else if(state == S_REC_BYTE)
		if(cycle_cnt == CYCLE - 1)
			bit_cnt <= bit_cnt + 3'd1;
		else
			bit_cnt <= bit_cnt;
	else
		bit_cnt <= 3'd0;
end


always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		cycle_cnt <= 16'd0;
	else if((state == S_REC_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)
		cycle_cnt <= 16'd0;
	else
		cycle_cnt <= cycle_cnt + 16'd1;	
end
//receive serial data bit data
always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		rx_bits <= 8'd0;
	else if(state == S_REC_BYTE && cycle_cnt == CYCLE/2 - 1)
		rx_bits[bit_cnt] <= rx_pin;
	else
		rx_bits <= rx_bits; 
end
endmodule 

4.总结

这是与stm32通信模块的所有代码

module stm32_communication(
input clk,
input rst,
input clk_1M,           //采样率1MHz
input [7:0] ADC, 
input rx_pin,

output reg wave1,
output reg [7:0] wave1_freq,
output reg wave2,
output reg [7:0] wave2_freq,
output tx_pin
    );

reg clk_100K_reg;    //串口发送速率12.5Khz
reg [11:0] clk_100K_cnt;
wire clk_100K = clk_100K_reg;
always@(posedge clk or negedge rst)
begin
    if(!rst)
    begin
        clk_100K_cnt<=0;
        clk_100K_reg<=0;
    end
    else
    begin
        clk_100K_cnt<=clk_100K_cnt+1;    
        if(clk_100K_cnt==1999)
        begin
            clk_100K_cnt<=0;
            clk_100K_reg<=~clk_100K_reg;
        end               
    end
end    
 
    
wire wr_en,rd_en,full,empty,wr_rst_busy,rd_rst_busy;
wire [10:0] rd_data_count,wr_data_count;
reg [7:0] w_data;
localparam      W_IDLE      = 1;
localparam      W_FIFO     = 2; 
localparam      R_IDLE      = 1;
localparam      R_FIFO     = 2; 

reg[2:0]  write_state;
reg[2:0]  next_write_state;
reg[2:0]  read_state;
reg[2:0]  next_read_state;

wire [7:0] rx_data,tx_data;
reg tx_vilid;

always@(posedge clk_1M or negedge rst)
begin 
	if(rst == 1'b0)
		write_state <= W_IDLE;
	else
		write_state <= next_write_state;
end

always@(*)
begin
	case(write_state)
		W_IDLE:
			if(empty == 1'b1)               //FIFO is empty, start writing FIFO
				next_write_state <= W_FIFO;
			else
				next_write_state <= W_IDLE;
		W_FIFO:
			if(full == 1'b1)                //FIFO is full
				next_write_state <= W_IDLE;
			else
				next_write_state <= W_FIFO;
		default:
			next_write_state <= W_IDLE;
	endcase
end

assign wr_en = (next_write_state == W_FIFO) ? 1'b1 : 1'b0; 

always@(posedge clk_1M or negedge rst)
begin
	if(rst == 1'b0)
		w_data <= 16'd0;
	else
	   if (wr_en == 1'b1)
		    w_data <= ADC;
		else
          w_data <= ADC;		
end



always@(posedge clk_1M or negedge rst)
begin
	if(rst == 1'b0)
		read_state <= R_IDLE;
	else
		read_state <= next_read_state;
end

always@(*)
begin
	case(read_state)
		R_IDLE:
			if(full == 1'b1)               //FIFO is full, starting read FIFO
				next_read_state <= R_FIFO;
			else
				next_read_state <= R_IDLE;
		R_FIFO:
			if(empty == 1'b1)              //FIFO is  empty
				next_read_state <= R_IDLE;
			else
				next_read_state <= R_FIFO;
		default:
			next_read_state <= R_IDLE;
	endcase
end
reg [10:0] rd_data_count_last;
always@(posedge clk or negedge rst)
begin
    if(!rst)
        rd_data_count_last<=0;
    else
    begin
        rd_data_count_last<=rd_data_count;
        if(rd_data_count_last!=rd_data_count && rd_en)
            tx_vilid<=1;
        else
            tx_vilid<=0;
    end    
end

assign rd_en = (next_read_state == R_FIFO) ? 1'b1 : 1'b0; 

fifo fifo (
  .rst(~rst),                      // input wire rst
  .wr_clk(clk_1M),                // input wire wr_clk
  .rd_clk(clk_100K),                // input wire rd_clk
  .din(w_data),                      // input wire [7 : 0] din
  .wr_en(wr_en),                  // input wire wr_en
  .rd_en(rd_en),                  // input wire rd_en
  .dout(tx_data),                    // output wire [7 : 0] dout
  .full(full),                    // output wire full
  .empty(empty),                  // output wire empty
  .rd_data_count(rd_data_count),  // output wire [10 : 0] rd_data_count
  .wr_data_count(wr_data_count)  // output wire [10 : 0] wr_data_count
);
 
reg [7:0] data1,data2,data3,data4;
reg rx_start;
wire rx_done;
reg [2:0] state; 
      
uart_rx
#(
.CLK_FRE(50),      //clock frequency(Mhz)
.BAUD_RATE(115200) //serial baud rate
)uart_rx
(
.clk(clk),              //clock input
.rst_n(rst),            //asynchronous reset input, low active 
.rx_data(rx_data),          //received serial data
.rx_data_ready(rx_start),    //data receiver module ready
.rx_data_valid(rx_done),    //received serial data is valid
.rx_pin(rx_pin)            //serial data input
);    
 
uart_tx#(
.CLK_FRE(50), 
.BAUD_RATE(115200) //serial baud rate
)uart_tx(
.clk(clk),              //clock input
.rst_n(rst),            //asynchronous reset input, low active 
.tx_data(tx_data),          //data to send
.tx_data_valid(tx_vilid),    //data to be sent is valid
.tx_pin(tx_pin)            //serial data output
); 



always@(posedge clk or negedge rst)
begin
    if(!rst)
    begin
        state<=0;
        data1<=0;
        data2<=0;
        data3<=0;
        data4<=0;
    end
    else
    begin
        case(state)
        3'b000:
        begin
            rx_start<=1;
            if(rx_done)
            begin
                if(rx_data==8'hFF)
                begin
                    rx_start<=0;
                    state<=state+1;
                    data1<=0;
                    data2<=0;
                    data3<=0;
                    data4<=0;
                end
            end
        end
        3'b001:
        begin
            rx_start<=1;
            if(rx_done)
            begin
                rx_start<=0;
                data1<=rx_data;
                state<=state+1;
            end
        end
        3'b010:
        begin
            rx_start<=1;
            if(rx_done)
            begin
                rx_start<=0;
                data2<=rx_data;
                state<=state+1;
            end
        end
        3'b011:
        begin
            rx_start<=1;
            if(rx_done)
            begin
                rx_start<=0;
                data3<=rx_data;
                state<=state+1;
            end
        end
        3'b100:
        begin
            rx_start<=1;
            if(rx_done)
            begin
                rx_start<=0;
                data4<=rx_data;
                state<=state+1;
            end
        end
        3'b101:
        begin
            rx_start<=1;
            if(rx_done)
            begin
                if(rx_data==8'hFE)
                begin
                    rx_start<=0;
                    state<=0;
                    wave1<=data1;
                    wave1_freq<=data2;
                    wave2<=data3;
                    wave2_freq<=data4;
                end
                else
                begin
                    rx_start<=0;
                    state<=0;
                    data1<=0;
                    data2<=0;
                    data3<=0;
                    data4<=0;
                end
            end
        end
        endcase
    end
end
    
endmodule

第二部分(stm32接收数据进行FFT识别波形以及频率并发送)

1.stm32串口接收

stm32使用的是串口中断(使用DMA会更好)

	HAL_UART_Receive_IT(&huart2,rx_data,2048);    //打开串口中断
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{
	if (huart->Instance == USART2) 
	{
	    for(int i=0;i<2048;i++)
		{
			wave_form[i]=rx_data[i];        //接收后转存出来
		}
		
		HAL_UART_Receive_IT(&huart2,rx_data,2048);
	}
}

2.stm32进行FFT

stm32导入DSP库并使用FFT的方法在我之前的文章已经介绍过了

https://blog.csdn.net/2401_83129457/article/details/147152935?spm=1001.2014.3001.5501

接下来我就直接介绍如何通过频域来识别两种波形以及他们的频率

首先确定波的频率范围为20KHz-100KHz,步进为5KHz,所以我们可以只考虑20KHz-100KHz这个频率范围之间的能量。并且以5KHz的步进将能量聚集起来,得到能量最多的两个频段就是所需要的两个波形的频率,然后通过一个阈值比较,判断两个波的波形,较小的是三角波,较大的是正弦波

for (int i=35; i<1000;i++)                        //将5KHz以内的能量聚集起来
		{
			freq = (int)(((float)i*1000000/2048/5000)+0.5);
			if(freq==freq_last)
			{
				v_max = FFT_output[i]*FFT_output[i]+v_max;
			}
			else
			{
				v_max = sqrt(v_max);
				freq_change[cnt] = v_max;
				fre[cnt] = freq;
				freq_last=freq;
				cnt++;
			}
		}
		v_max=0;
		cnt=0;

		for(int i=0;i<100;i++)                    //计算出两个最大的能量的频率
		{
			if(freq_change[i]>max[0])
			{
				max[1]=max[0];
				idx[1]=idx[0];
				max[0]=freq_change[i];
				idx[0]=2.5*(fre[i]-1);
			}
			else if(freq_change[i]>max[1] && freq_change[i]<max[0])
			{
				max[1]=freq_change[i];
				idx[1]=2.5*(fre[i]-1);
			}

		}
		
		if(max[0]>5.7) wave[0] = 0;		//正弦波
		else wave[0] = 1;							//三角波
		if(max[1]>5.7) wave[1] = 0;
		else wave[1] = 1;

以下是stm32所有的代码

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "key.h"
#include "OLED.h"
#include "LED.h"
#include "math.h"
#include "arm_math.h"
#include "arm_const_structs.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

float max[2];
uint16_t idx[2];
uint16_t freq,freq_last;
float FFT_input[4096],FFT_output[2048];
float freq_change[2048];
uint16_t fre[2048];
uint16_t cnt;
float v_max;
uint8_t wave[2];
uint8_t tx_data[6];

uint8_t flag;

uint8_t rx_data[2048];
uint8_t wave_form[2048];

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
char message[50];
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_TIM2_Init();
  MX_TIM4_Init();
  MX_TIM3_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

	HAL_UART_Receive_IT(&huart2,rx_data,2048);

	OLED_Init();
	OLED_PrintString(0,0,"Init Success",&font16x16,OLED_COLOR_NORMAL);
	OLED_ShowFrame();
	HAL_Delay(500);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {	
		
			for (int i = 0; i < 2048; i++)
			{
				FFT_input[i * 2] = wave_form[i];
				FFT_input[i * 2 + 1] = 0;
			}

		arm_cfft_f32(&arm_cfft_sR_f32_len2048, FFT_input, 0, 1);	
		arm_cmplx_mag_f32(FFT_input, FFT_output, 2048); 				
		FFT_output[0] /= 2048;
		for (int i = 1; i < 2048; i++)
		{
			FFT_output[i] /= 1024;
		}
		
		for (int i=35; i<1000;i++)
		{
			freq = (int)(((float)i*1000000/2048/5000)+0.5);
			if(freq==freq_last)
			{
				v_max = FFT_output[i]*FFT_output[i]+v_max;
			}
			else
			{
				v_max = sqrt(v_max);
				freq_change[cnt] = v_max;
				fre[cnt] = freq;
				freq_last=freq;
				cnt++;
			}
		}
		v_max=0;
		cnt=0;
		
		for (int i = 0; i < 25; i++)
		{
			printf("%d,%.2f\n",fre[i],freq_change[i]);
		}
		
		for(int i=0;i<100;i++)
		{
			if(freq_change[i]>max[0])
			{
				max[1]=max[0];
				idx[1]=idx[0];
				max[0]=freq_change[i];
				idx[0]=2.5*(fre[i]-1);
			}
			else if(freq_change[i]>max[1] && freq_change[i]<max[0])
			{
				max[1]=freq_change[i];
				idx[1]=2.5*(fre[i]-1);
			}

		}
		
		if(max[0]>5.7) wave[0] = 0;		//正弦波
		else wave[0] = 1;							//三角波
		if(max[1]>5.7) wave[1] = 0;
		else wave[1] = 1;
		
		if(idx[0]>idx[1])
		{
			tx_data[0]=0xff;
			tx_data[1]=wave[1];
			tx_data[2]=idx[1];
			tx_data[3]=wave[0];
			tx_data[4]=idx[0];
			tx_data[5]=0xfe;
		}
		else
		{
			tx_data[0]=0xff;
			tx_data[1]=wave[0];
			tx_data[2]=idx[0];
			tx_data[3]=wave[1];
			tx_data[4]=idx[1];
			tx_data[5]=0xfe;				
		}
		

		HAL_UART_Transmit(&huart2,tx_data,6,HAL_MAX_DELAY);

		OLED_NewFrame();

		sprintf(message,"%d : %d  %.2f",wave[0],idx[0],max[0]);	  		
	  OLED_PrintString(0,0,message,&font16x16,OLED_COLOR_NORMAL);
		sprintf(message,"%d : %d  %.2f",wave[1],idx[1],max[1]);	  		
	  OLED_PrintString(0,20,message,&font16x16,OLED_COLOR_NORMAL);
		
	  OLED_ShowFrame();
		
		for(uint8_t i=0;i<2;i++)
		{
			max[i]=0;
			idx[i]=0;
			wave[i]=0;
		}
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 6;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{
	if (huart->Instance == USART2) 
	{
			for(int i=0;i<2048;i++)
			{
				wave_form[i]=rx_data[i];
			}
		
		HAL_UART_Receive_IT(&huart2,rx_data,2048);
	}
}


/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

3.stm32串口发送

由于A波的频率始终小于B波,所以我们要先判断那个是A波哪个是B波,然后通过串口发送给FPGA

if(idx[0]>idx[1])
{
	x_data[0]=0xff;
	tx_data[1]=wave[1];
	tx_data[2]=idx[1];
	tx_data[3]=wave[0];
	tx_data[4]=idx[0];
	tx_data[5]=0xfe;
}
else
{
	tx_data[0]=0xff;
	tx_data[1]=wave[0];
	tx_data[2]=idx[0];
	tx_data[3]=wave[1];
	tx_data[4]=idx[1];
	tx_data[5]=0xfe;				
}
		

HAL_UART_Transmit(&huart2,tx_data,6,HAL_MAX_DELAY);

第三部分(FPGA得到波形与频率后生成波形)

需要一个DDS模块,使用ROM存储正弦波和三角波的点

module dds(
    input clk,
    input rst,
    input wave1,        //A波波形
    input wave2,        //B波波形
    input [31:0] freq1,    //A波频率
    input [31:0] freq2,    //B波频率
    input [9:0] phase1,    //A波相位
    input [9:0] phase2,    //B波相位
    input [9:0] de_phase,    //相位偏移
    output [13:0]dataout1,    //A'波
    output [13:0]dataout2,    //B'波
    output [13:0]dataout2_delay    //B'波偏移
);
 
//波形数据:
reg [13:0] wavedata1,wavedata2,wavedata3;
//波形信号:
wire [13:0] sindata1,sindata2,sindata3;
wire [13:0] tridata1,tridata2,tridata3;

//相位寄存器:
reg [31:0]frechange1,frechange2; 
 
always @(posedge clk or negedge rst) begin
   if(!rst)
   begin
       frechange1 <= 32'd0; 
       frechange2 <= 32'd0; 
   end
   else
   begin
       frechange1 <= frechange1 + freq1;
       frechange2 <= frechange2 + freq2;
   end
end
//相位累加器:
reg [9:0]romaddr1,romaddr2,romaddr3;
always @(posedge clk or negedge rst) begin
   if(!rst)
   begin
       romaddr1 <= 10'd0;
       romaddr2 <= 10'd0;
   end
   else
   begin
       romaddr1 <= frechange1[31:22] + phase1;
       romaddr2 <= frechange2[31:22] + phase2;
       romaddr3 <= romaddr2 + de_phase;
   end
end
 

ROM_sin romsin1 (
  .clka(clk),
  .addra(romaddr1),
  .douta(sindata1)
);
 
ROM_tri romtri1 (
  .clka(clk),
  .addra(romaddr1),
  .douta(tridata1)
); 
 
ROM_sin romsin2 (
  .clka(clk),
  .addra(romaddr2),
  .douta(sindata2)
);
 
ROM_tri romtri2 (
  .clka(clk),
  .addra(romaddr2),
  .douta(tridata2)
);  
 
ROM_sin romsin3 (
  .clka(clk),
  .addra(romaddr3),
  .douta(sindata3)
);
 
ROM_tri romtri3 (
  .clka(clk),
  .addra(romaddr3),
  .douta(tridata3)
); 

always @(*) begin
	case(wave1)
		1'b0: wavedata1<= sindata1;	
		1'b1: wavedata1<= tridata1;	
		default: wavedata1<= sindata1;
	endcase
end

always @(*) begin
	case(wave2)
		1'b0: wavedata2<= sindata2;	
		1'b1: wavedata2<= tridata2;	
		default: wavedata2<= sindata2;
	endcase
end

always @(*) begin
	case(wave2)
		1'b0: wavedata3<= sindata3;	
		1'b1: wavedata3<= tridata3;	
		default: wavedata3<= sindata3;
	endcase
end

assign dataout1 = wavedata1;
assign dataout2 = wavedata2;
assign dataout2_delay = wavedata3;
 
endmodule

dds ddsA(
.clk(clk),
.rst(rst),
.wave1(wave1),
.wave2(wave2),
.freq1(freq1*32'd85899),
.freq2(freq2*32'd85899),
.phase1(A_phase[21:12]),
.phase2(B_phase[21:12]),
.de_phase((((phase0+phase)*91)>>5)),
.dataout1(da1_data),
.dataout2(da2_data_start),
.dataout2_delay(da2_data)
); 

第四部分(FPGA锁相)

1.鉴相

对AB两路信号与输入的C信号进行鉴相处理(即相乘再过一个低通滤波器,乘法器和低通滤波器都是使用的VIVADO的ip核)

mult_mix mult_mix_A (
  .CLK(clk),  // input wire CLK
  .A(ADC_signed),      // input wire [11 : 0] A
  .B(DAC_A),      // input wire [13 : 0] B
  .P(mix_A)      // output wire [25 : 0] P
);        

LPF LPF_A (
  .aclk(clk),                              // input wire aclk
  .s_axis_data_tvalid(1'b1),  // input wire s_axis_data_tvalid
  .s_axis_data_tdata(A_filter),    // input wire [23 : 0] s_axis_data_tdata
  .m_axis_data_tdata(A_filter_out)    // output wire [23 : 0] m_axis_data_tdata
);

mult_mix mult_mix_B (
  .CLK(clk),  // input wire CLK
  .A(ADC_signed),      // input wire [11 : 0] A
  .B(DAC_B),      // input wire [13 : 0] B
  .P(mix_B)      // output wire [25 : 0] P
);        

LPF LPF_B (
  .aclk(clk),                              // input wire aclk
  .s_axis_data_tvalid(1'b1),  // input wire s_axis_data_tvalid
  .s_axis_data_tdata(B_filter),    // input wire [23 : 0] s_axis_data_tdata
  .m_axis_data_tdata(B_filter_out)    // output wire [23 : 0] m_axis_data_tdata
);

2.环路滤波

环路滤波器就相当于是一个PI电路(即差距和积分电路,只需要调节它的Kp和Ki参数使得波形不抖动就算调节成功)

Loop_filter Loop_filter_A(
.clk(clk),
.rst(rst),
.i_pd(A_filter_out),
.o_frequency_df(A_phase)
);

Loop_filter Loop_filter_B(
.clk(clk),
.rst(rst),
.i_pd(B_filter_out),
.o_frequency_df(B_phase)
);
module Loop_filter(
input clk,
input rst,
input signed [23:0] i_pd,
output signed [23:0] o_frequency_df
);

reg signed [23:0] sum_d;
wire signed [23:0] pd_c2, pd_c1,sum;
    
assign pd_c1 = {{3{i_pd[23]}},i_pd[23:3]}; //c1
assign pd_c2 = {{12{i_pd[23]}},i_pd[23:12]}; //c2
    
always@(posedge clk or negedge rst)
begin
    if(!rst)
        sum_d <= 0;
    else
        sum_d <= sum; 
end
        
assign sum = pd_c2 + sum_d;
assign o_frequency_df = sum_d + pd_c1;

endmodule

3.反馈

将输出的phase信号反馈到DDS模块上

.phase1(A_phase[21:12]),
.phase2(B_phase[21:12]),

第五部分(DAC输出)

.dataout1(da1_data),
.dataout2_delay(da2_data)
assign da1_clk = clk;
assign da1_wrt = clk;
assign da2_clk = clk;
assign da2_wrt = clk;

第六部分(移相)

通过前五个部分已经可以实现除开移相的所有功能

接下来我们要使用按键来控制A'和B‘的相位差并且能在数码管上显示

1.按键消抖

module key
(
input clk,
input reset,
input [3:0] key,
output [3:0] key_num
);
    
reg[31:0] timer;    
reg[3:0] key_first; 
reg[3:0] key_second; 
reg[3:0] key_now;
  
assign key_num=key_now;  
  
always@(posedge clk or negedge reset)
begin
    if(reset==0)
    begin
        key_now<=4'b0000;
        key_first<=4'b1111;
        key_second<=4'b1111;
        timer<=32'd0;
    end    
    else
    begin
        if(key!=4'b1111)
        begin
            key_first<=key;            
            timer<=timer+32'd1; 
        end    
        else
        begin
            timer<=32'd0;
            if(key_first==key_second)
            begin
                key_now<=~key_first;
                key_second<=0;
            end
            else
                key_now<=0;    
        end                
        if(timer==32'd999_999)
            key_second<=key;                                 
    end   
end       
       
endmodule

2.按键设置相位差

需要用前三个按键将相位手动调零,然后按下第四个按键表示调零完毕,再通过前三个按键设置相位差

key key_inst
(
.clk(clk),
.reset(rst),
.key(key),
.key_num(key_num)
);

always@(posedge clk or negedge rst)
begin
    if(!rst)
    begin
        phase<=0;
        phase0<=0;
    end
    else
    begin
        if(key_num == 4'b0001)
        begin
            phase<=phase+1;
        end
        else if(key_num == 4'b0010)
        begin
            phase<=phase+5;
        end
        else if(key_num == 4'b0100)
        begin
            phase<=phase+30;
        end
        else if(key_num == 4'b1000)
        begin
            phase0<=phase;
            phase<=0;
        end
        if(phase0 == 0)
        begin
            if(phase>360)
                phase<=phase-360;
        end
        else
        begin
            if(phase>180)
                phase<=phase-180;
        end
    end
end 

3.数码管显示相位

module nixie(
input clk,
input rst,
input [7:0] data,

output [7:0] SMG_Data,
output [5:0] Scan_Sig
    );
    
reg [5:0] sig;    
assign Scan_Sig = sig;    

reg [7:0] num;
reg [31:0] timer;

reg clk_low;
reg [9:0] count;
always@(posedge clk or negedge rst)
begin
    if(!rst)
    begin
        count<=0;
        clk_low<=0;
    end
    else
    begin
        count<=count+1;
        if(count==49)
        begin
            count<=0;
            clk_low <= ~clk_low;
        end   
    end  
end
    
always@(posedge clk_low or negedge rst)
begin
    if(!rst)
    begin
        num<=8'd0;
        timer<=0;
    end
    else
    begin
        timer<=timer+1;
        if(timer==50)
        begin
            sig=6'b011111;
            num = 8'h11;
        end
        else if(timer==100)
        begin
            sig=6'b101111;
            num = 8'h11;
        end
        else if(timer==150)
        begin
            sig=6'b110111;
            num = 8'h11;
        end
        else if(timer==200)
        begin
            sig=6'b111011;
            num = 8'h11;
        end
        else if(timer==250)
        begin
            sig=6'b111101;
            num = 8'h11;
        end
        else if(timer==300)
        begin
            sig=6'b111110;
            num = 8'h11;
            timer<=0;
        end
        if(sig == 6'b011111)
        begin
            num <= ~(8'h73);
        end
        else if(sig == 6'b101111)
        begin
            num <= ~(8'h74);   
        end
        else if(sig == 6'b110111)
        begin
           num <= ~(8'h40);   
        end
        else if(sig == 6'b111011)
        begin
           case(data%1000/100)
            1:
                num<=~(8'h06);
            2:
                num<=~(8'h5b);
            3:
                num<=~(8'h4f);   
            4:
                num<=~(8'h66);  
            5:
                num<=~(8'h6d);
            6:
                num<=~(8'h7d);
            7:
                num<=~(8'h07);
            8:
                num<=~(8'h7f);
            9:
                num<=~(8'h6f);
            0:
                num<=~(8'h3f);
            endcase  
        end
        else if(sig == 6'b111101)
        begin
           case(data%100/10)
            1:
                num<=~(8'h06);
            2:
                num<=~(8'h5b);
            3:
                num<=~(8'h4f);   
            4:
                num<=~(8'h66);  
            5:
                num<=~(8'h6d);
            6:
                num<=~(8'h7d);
            7:
                num<=~(8'h07);
            8:
                num<=~(8'h7f);
            9:
                num<=~(8'h6f);
            0:
                num<=~(8'h3f);
            endcase    
        end
        else if(sig == 6'b111110)
        begin
            case(data%10)
            1:
                num<=~(8'h06);
            2:
                num<=~(8'h5b);
            3:
                num<=~(8'h4f);   
            4:
                num<=~(8'h66);  
            5:
                num<=~(8'h6d);
            6:
                num<=~(8'h7d);
            7:
                num<=~(8'h07);
            8:
                num<=~(8'h7f);
            9:
                num<=~(8'h6f);
            0:
                num<=~(8'h3f);
            endcase    
        end
    end
end    

assign SMG_Data = num;
   
endmodule
nixie nixie_inst(
.clk(clk),
.rst(rst),
.data(phase),

.SMG_Data(SMG_Data),
.Scan_Sig(Scan_Sig)
    );

第七部分(FPGA代码总结)

以下是top模块的所有代码

module top(
input clk,
input rst,
input [11:0] ad9238_data_ch0,   
input rx_pin,
input [3:0] key,

output [7:0] SMG_Data,
output [5:0] Scan_Sig,
output tx_pin,
output ad9238_clk_ch0,          
output da1_clk,                 
output da1_wrt,                 
output [13:0] da1_data,
output da2_clk,                 
output da2_wrt,                 
output [13:0] da2_data   
    );

reg [7:0] phase,phase0;
wire [13:0] da2_data_start;
wire signed [11:0] ADC_signed  = ad9238_data_ch0 - 12'd2047;
wire signed [13:0] DAC_A  = da1_data - 14'd8191;
wire signed [13:0] DAC_B  = da2_data_start - 14'd8191;

wire signed [25:0] mix_A,mix_B;
wire signed [23:0] A_filter = mix_A>>2,B_filter = mix_B>>2;    
wire signed [23:0] A_filter_out,B_filter_out,A_phase,B_phase;  
reg clk_1M_reg;    
reg [7:0] clk_1M_cnt;
wire clk_1M = clk_1M_reg;
wire wave1,wave2;
wire [7:0] freq1,freq2;
wire [7:0] ADC_send = ad9238_data_ch0>>4;
wire [2:0] N = (freq1&&freq2) ? (freq2/freq1) : 1;

always@(posedge clk or negedge rst)
begin
    if(!rst)
    begin
        clk_1M_cnt<=0;
        clk_1M_reg<=0;
    end
    else
    begin
        clk_1M_cnt<=clk_1M_cnt+1;    
        if(clk_1M_cnt==24)
        begin
            clk_1M_cnt<=0;
            clk_1M_reg<=~clk_1M_reg;
        end               
    end
end   

assign ad9238_clk_ch0 = clk_1M;
assign da1_clk = clk;
assign da1_wrt = clk;
assign da2_clk = clk;
assign da2_wrt = clk;


stm32_communication stm32_communication(
.clk(clk),
.rst(rst),
.clk_1M(clk_1M),
.ADC(ADC_send),
.rx_pin(rx_pin),

.wave1(wave1),
.wave1_freq(freq1),
.wave2(wave2),
.wave2_freq(freq2),
.tx_pin(tx_pin)
    );

dds ddsA(
.clk(clk),
.rst(rst),
.wave1(wave1),
.wave2(wave2),
.freq1(freq1*32'd85899),
.freq2(freq2*32'd85899),
.phase1(A_phase[21:12]),
.phase2(B_phase[21:12]),
.de_phase((((phase0+phase)*91)>>5)),
.dataout1(da1_data),
.dataout2(da2_data_start),
.dataout2_delay(da2_data)
);  

mult_mix mult_mix_A (
  .CLK(clk),  // input wire CLK
  .A(ADC_signed),      // input wire [11 : 0] A
  .B(DAC_A),      // input wire [13 : 0] B
  .P(mix_A)      // output wire [25 : 0] P
);        

LPF LPF_A (
  .aclk(clk),                              // input wire aclk
  .s_axis_data_tvalid(1'b1),  // input wire s_axis_data_tvalid
  .s_axis_data_tdata(A_filter),    // input wire [23 : 0] s_axis_data_tdata
  .m_axis_data_tdata(A_filter_out)    // output wire [23 : 0] m_axis_data_tdata
);


Loop_filter Loop_filter_A(
.clk(clk),
.rst(rst),
.i_pd(A_filter_out),
.o_frequency_df(A_phase)
);

mult_mix mult_mix_B (
  .CLK(clk),  // input wire CLK
  .A(ADC_signed),      // input wire [11 : 0] A
  .B(DAC_B),      // input wire [13 : 0] B
  .P(mix_B)      // output wire [25 : 0] P
);        

LPF LPF_B (
  .aclk(clk),                              // input wire aclk
  .s_axis_data_tvalid(1'b1),  // input wire s_axis_data_tvalid
  .s_axis_data_tdata(B_filter),    // input wire [23 : 0] s_axis_data_tdata
  .m_axis_data_tdata(B_filter_out)    // output wire [23 : 0] m_axis_data_tdata
);


Loop_filter Loop_filter_B(
.clk(clk),
.rst(rst),
.i_pd(B_filter_out),
.o_frequency_df(B_phase)
);

wire [3:0] key_num;

key key_inst
(
.clk(clk),
.reset(rst),
.key(key),
.key_num(key_num)
);

nixie nixie_inst(
.clk(clk),
.rst(rst),
.data(phase),

.SMG_Data(SMG_Data),
.Scan_Sig(Scan_Sig)
    );
    
always@(posedge clk or negedge rst)
begin
    if(!rst)
    begin
        phase<=0;
        phase0<=0;
    end
    else
    begin
        if(key_num == 4'b0001)
        begin
            phase<=phase+1;
        end
        else if(key_num == 4'b0010)
        begin
            phase<=phase+5;
        end
        else if(key_num == 4'b0100)
        begin
            phase<=phase+30;
        end
        else if(key_num == 4'b1000)
        begin
            phase0<=phase;
            phase<=0;
        end
        if(phase0 == 0)
        begin
            if(phase>360)
                phase<=phase-360;
        end
        else
        begin
            if(phase>180)
                phase<=phase-180;
        end
    end
end    
    
//ila ila (
//	.clk(clk), // input wire clk
//	.probe0(mix_B), // input wire [25:0]  probe0  
//	.probe1(B_filter), // input wire [23:0]  probe1 
//	.probe2(B_filter_out), // input wire [23:0]  probe2 
//	.probe3(B_phase[23:15]) // input wire [8:0]  probe3
//);

endmodule

后记

完整代码:

【免费】2023年电赛H题(信号分离装置)-FPGA+stm32解法资源-CSDN下载

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐