FPGADDS信号发生器+串口调频(设置精确到1HZ)

时间:2020-09-16
本文章向大家介绍FPGADDS信号发生器+串口调频(设置精确到1HZ),主要包括FPGADDS信号发生器+串口调频(设置精确到1HZ)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

 

1)实验目的:FPGA 实现 DDS,可采用 IP 核/串口设置两种方式(二选一) , 实现任意波形、 频率发生器 。
2)实验平台:ALINIX黑金AX301开发板,芯片型号:ALTERA 公司的 Cyclone IV 系列 FPGA,型号为 EP4CE6F17C8, 芯片封装为FBGA,AN108ADDA模块。

 

3)实验原理:FPGA 程序要输出 8 位的正弦波数据给 AD/DA 模块, 使 AD/DA 模块的 DA 输出一个正弦波信号,这个正弦波信号通过 BNC 线又输入到 AD 电路, 程序读取 AD 的数据输出显示在 Signaltap 界面中。 在这里我们需要用到 FPGA 内部的 ROM 来存储正选波的数据。
3-1使用相应软件生成ROM的初始化.mif文件,本实验采用的数据长度为256,数据位宽为8(由AD/DA模块决定),生成后点击保存,存至相应的工程文件夹同一目录。

 

 3-2在工程中生成romIP核来存储数据,详细设置如下,注意最后一栏设置要生成_inst.v文件便于例化模块:

 

(由于本实验需要变换波形,所以存了3种波形数据,三角波、方波、正弦波)

3-2本实验采用按键更改波形AX301的按键电路特性为:按键没有按下的时候,连接到 FPGA 管脚的按键信号的电平为高,当有按键按下的时候,连接到 FPGA 管脚的此按键信号的电平被拉低。
按键模块大体思路为使用一个4位寄存器,存取按键的值,考虑到按键消抖问题使用双重锁存,led_r1为最终按键数据。代码如下。

 1 `timescale 1ns / 1ps
 2 module key_test
 3 (
 4         clk,       //system clock 50Mhz on board
 5         key,       //input four key signal,when the keydown,the value is 0
 6         led        //LED display ,when the siganl high,LED lighten
 7 );
 8 
 9 
10     input                 clk;      //system clock 50Mhz on board
11     input [3:0]           key;      //input four key signal,when the keydown,the value is 0
12     output[3:0]           led; 
13 
14 
15 
16 reg[3:0] led_r;           //define the first stage register , generate four D Flip-flop 
17 reg[3:0] led_r1;          //define the second stage register ,generate four D Flip-flop
18 always@(posedge clk)
19 begin
20     led_r <= ~key;        //first stage latched data
21 end
22 
23 always@(posedge clk)
24 begin
25     led_r1 <= led_r;      //second stage latched data
26 end
27 
28 assign led = led_r1;
29 
30 endmodule 
按键模块代码

3-3本实验使用串口改频率,黑金的例程分uart_rx和uart_tx为接收和发送模块,并使用uart_test作为前两模块的应用模块,串口收发的详解以及各个接口的作用详细见教程。附上代码,读者可尝试理解。

  1 module uart_rx
  2 #(
  3     parameter CLK_FRE = 50,      //clock frequency(Mhz)
  4     parameter BAUD_RATE = 115200 //serial baud rate
  5 )
  6 (
  7     input                        clk,              //clock input
  8     input                        rst_n,            //asynchronous reset input, low active 
  9     output reg[7:0]              rx_data,          //received serial data
 10     output reg                   rx_data_valid,    //received serial data is valid
 11     input                        rx_data_ready,    //data receiver module ready
 12     input                        rx_pin            //serial data input
 13 );
 14 //calculates the clock cycle for baud rate 
 15 localparam                       CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
 16 //state machine code
 17 localparam                       S_IDLE      = 1;
 18 localparam                       S_START     = 2; //start bit
 19 localparam                       S_REC_BYTE  = 3; //data bits
 20 localparam                       S_STOP      = 4; //stop bit
 21 localparam                       S_DATA      = 5;
 22 
 23 reg[2:0]                         state;
 24 reg[2:0]                         next_state;
 25 reg                              rx_d0;            //delay 1 clock for rx_pin
 26 reg                              rx_d1;            //delay 1 clock for rx_d0
 27 wire                             rx_negedge;       //negedge of rx_pin
 28 reg[7:0]                         rx_bits;          //temporary storage of received data
 29 reg[15:0]                        cycle_cnt;        //baud counter
 30 reg[2:0]                         bit_cnt;          //bit counter
 31 
 32 assign rx_negedge = rx_d1 && ~rx_d0;
 33 
 34 always@(posedge clk or negedge rst_n)
 35 begin
 36     if(rst_n == 1'b0)
 37     begin
 38         rx_d0 <= 1'b0;
 39         rx_d1 <= 1'b0;    
 40     end
 41     else
 42     begin
 43         rx_d0 <= rx_pin;
 44         rx_d1 <= rx_d0;
 45     end
 46 end
 47 
 48 
 49 always@(posedge clk or negedge rst_n)
 50 begin
 51     if(rst_n == 1'b0)
 52         state <= S_IDLE;
 53     else
 54         state <= next_state;
 55 end
 56 
 57 always@(*)
 58 begin
 59     case(state)
 60         S_IDLE:
 61             if(rx_negedge)
 62                 next_state <= S_START;
 63             else
 64                 next_state <= S_IDLE;
 65         S_START:
 66             if(cycle_cnt == CYCLE - 1)//one data cycle 
 67                 next_state <= S_REC_BYTE;
 68             else
 69                 next_state <= S_START;
 70         S_REC_BYTE:
 71             if(cycle_cnt == CYCLE - 1  && bit_cnt == 3'd7)  //receive 8bit data
 72                 next_state <= S_STOP;
 73             else
 74                 next_state <= S_REC_BYTE;
 75         S_STOP:
 76             if(cycle_cnt == CYCLE/2 - 1)//half bit cycle,to avoid missing the next byte receiver
 77                 next_state <= S_DATA;
 78             else
 79                 next_state <= S_STOP;
 80         S_DATA:
 81             if(rx_data_ready)    //data receive complete
 82                 next_state <= S_IDLE;
 83                 
 84                 /*************串口接收结束*******************
 85                 rx_data<=8'd0;
 86                 /*******************************************/
 87             else
 88                 next_state <= S_DATA;
 89         default:
 90             next_state <= S_IDLE;
 91     endcase
 92 end
 93 
 94 always@(posedge clk or negedge rst_n)
 95 begin
 96     if(rst_n == 1'b0)
 97         rx_data_valid <= 1'b0;
 98     else if(state == S_STOP && next_state != state)
 99         rx_data_valid <= 1'b1;
100     else if(state == S_DATA && rx_data_ready)
101         rx_data_valid <= 1'b0;
102 end
103 
104 always@(posedge clk or negedge rst_n)
105 begin
106     if(rst_n == 1'b0)
107         rx_data <= 8'd0;
108     else if(state == S_STOP && next_state != state)
109         rx_data <= rx_bits;//latch received data
110 end
111 
112 always@(posedge clk or negedge rst_n)
113 begin
114     if(rst_n == 1'b0)
115         begin
116             bit_cnt <= 3'd0;
117         end
118     else if(state == S_REC_BYTE)
119         if(cycle_cnt == CYCLE - 1)
120             bit_cnt <= bit_cnt + 3'd1;
121         else
122             bit_cnt <= bit_cnt;
123     else
124         bit_cnt <= 3'd0;
125 end
126 
127 
128 always@(posedge clk or negedge rst_n)
129 begin
130     if(rst_n == 1'b0)
131         cycle_cnt <= 16'd0;
132     else if((state == S_REC_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)
133         cycle_cnt <= 16'd0;
134     else
135         cycle_cnt <= cycle_cnt + 16'd1;    
136 end
137 //receive serial data bit data
138 always@(posedge clk or negedge rst_n)
139 begin
140     if(rst_n == 1'b0)
141         rx_bits <= 8'd0;
142     else if(state == S_REC_BYTE && cycle_cnt == CYCLE/2 - 1)
143         rx_bits[bit_cnt] <= rx_pin;
144     else
145         rx_bits <= rx_bits; 
146 end
147 endmodule 
uart_rx.v
  1 module uart_tx
  2 #(
  3     parameter CLK_FRE = 50,      //clock frequency(Mhz)
  4     parameter BAUD_RATE = 115200 //serial baud rate
  5 )
  6 (
  7     input                        clk,              //clock input
  8     input                        rst_n,            //asynchronous reset input, low active 
  9     input[7:0]                   tx_data,          //data to send
 10     input                        tx_data_valid,    //data to be sent is valid
 11     output reg                   tx_data_ready,    //send ready
 12     output                       tx_pin            //serial data output
 13 );
 14 //calculates the clock cycle for baud rate 
 15 localparam                       CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
 16 //state machine code
 17 localparam                       S_IDLE       = 1;
 18 localparam                       S_START      = 2;//start bit
 19 localparam                       S_SEND_BYTE  = 3;//data bits
 20 localparam                       S_STOP       = 4;//stop bit
 21 reg[2:0]                         state;
 22 reg[2:0]                         next_state;
 23 reg[15:0]                        cycle_cnt; //baud counter
 24 reg[2:0]                         bit_cnt;//bit counter
 25 reg[7:0]                         tx_data_latch; //latch data to send
 26 reg                              tx_reg; //serial data output
 27 assign tx_pin = tx_reg;
 28 always@(posedge clk or negedge rst_n)
 29 begin
 30     if(rst_n == 1'b0)
 31         state <= S_IDLE;
 32     else
 33         state <= next_state;
 34 end
 35 
 36 always@(*)
 37 begin
 38     case(state)
 39         S_IDLE:
 40             if(tx_data_valid == 1'b1)
 41                 next_state <= S_START;
 42             else
 43                 next_state <= S_IDLE;
 44         S_START:
 45             if(cycle_cnt == CYCLE - 1)
 46                 next_state <= S_SEND_BYTE;
 47             else
 48                 next_state <= S_START;
 49         S_SEND_BYTE:
 50             if(cycle_cnt == CYCLE - 1  && bit_cnt == 3'd7)
 51                 next_state <= S_STOP;
 52             else
 53                 next_state <= S_SEND_BYTE;
 54         S_STOP:
 55             if(cycle_cnt == CYCLE - 1)
 56                 next_state <= S_IDLE;
 57             else
 58                 next_state <= S_STOP;
 59         default:
 60             next_state <= S_IDLE;
 61     endcase
 62 end
 63 always@(posedge clk or negedge rst_n)
 64 begin
 65     if(rst_n == 1'b0)
 66         begin
 67             tx_data_ready <= 1'b0;
 68         end
 69     else if(state == S_IDLE)
 70         if(tx_data_valid == 1'b1)
 71             tx_data_ready <= 1'b0;
 72         else
 73             tx_data_ready <= 1'b1;
 74     else if(state == S_STOP && cycle_cnt == CYCLE - 1)
 75             tx_data_ready <= 1'b1;
 76 end
 77 
 78 
 79 always@(posedge clk or negedge rst_n)
 80 begin
 81     if(rst_n == 1'b0)
 82         begin
 83             tx_data_latch <= 8'd0;
 84         end
 85     else if(state == S_IDLE && tx_data_valid == 1'b1)
 86             tx_data_latch <= tx_data;
 87         
 88 end
 89 
 90 always@(posedge clk or negedge rst_n)
 91 begin
 92     if(rst_n == 1'b0)
 93         begin
 94             bit_cnt <= 3'd0;
 95         end
 96     else if(state == S_SEND_BYTE)
 97         if(cycle_cnt == CYCLE - 1)
 98             bit_cnt <= bit_cnt + 3'd1;
 99         else
100             bit_cnt <= bit_cnt;
101     else
102         bit_cnt <= 3'd0;
103 end
104 
105 
106 always@(posedge clk or negedge rst_n)
107 begin
108     if(rst_n == 1'b0)
109         cycle_cnt <= 16'd0;
110     else if((state == S_SEND_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)
111         cycle_cnt <= 16'd0;
112     else
113         cycle_cnt <= cycle_cnt + 16'd1;    
114 end
115 
116 always@(posedge clk or negedge rst_n)
117 begin
118     if(rst_n == 1'b0)
119         tx_reg <= 1'b1;
120     else
121         case(state)
122             S_IDLE,S_STOP:
123                 tx_reg <= 1'b1; 
124             S_START:
125                 tx_reg <= 1'b0; 
126             S_SEND_BYTE:
127                 tx_reg <= tx_data_latch[bit_cnt];
128             default:
129                 tx_reg <= 1'b1; 
130         endcase
131 end
132 
133 endmodule 
uart_tx.v

以下为顶层应用模块的代码,输入为时钟clk,复位信号rst_n,uart_rx为信号接收端口,uart_tx为信号发送端口,receive_data为存储接收到的数据,rxflag为数据接收标志位,接收数据完成置1,平常为0。

顶层为串口收发底层模块的例化。

  1 //注意每次只能接收8bit的数据并且保存,如果数据大于8位的话会直接进行数据更新
  2 
  3 module uart_test(
  4        clk,
  5        rst_n,
  6        uart_rx,
  7        uart_tx,
  8         receive_data,
  9         rxflag
 10 );
 11 
 12     output    [7:0] receive_data;
 13     output   rxflag;
 14     assign     receive_data=rx_data;
 15     assign   rxflag=rx_data_valid;
 16 
 17     input                        clk;
 18     input                        rst_n;
 19     input                        uart_rx;
 20     output                       uart_tx;
 21 
 22 parameter                        CLK_FRE = 50;//Mhz
 23 localparam                       IDLE =  0;
 24 localparam                       SEND =  1;   //send HELLO ALINX\r\n
 25 localparam                       WAIT =  2;   //wait 1 second and send uart received data
 26 reg[7:0]                         tx_data;
 27 reg[7:0]                         tx_str;
 28 reg                              tx_data_valid;
 29 wire                             tx_data_ready;
 30 reg[7:0]                         tx_cnt;
 31 wire[7:0]                        rx_data;
 32 wire                             rx_data_valid;
 33 wire                             rx_data_ready;
 34 reg[31:0]                        wait_cnt;
 35 reg[3:0]                         state;
 36 
 37 assign rx_data_ready = 1'b1;//always can receive data,
 38                             //if HELLO ALINX\r\n is being sent, the received data is discarded
 39 
 40 always@(posedge clk or negedge rst_n)
 41 begin
 42     if(rst_n == 1'b0)
 43     begin
 44         wait_cnt <= 32'd0;
 45         tx_data <= 8'd0;
 46         state <= IDLE;
 47         tx_cnt <= 8'd0;
 48         tx_data_valid <= 1'b0;
 49     end
 50     else
 51     case(state)
 52         IDLE:
 53             state <= SEND;
 54         SEND:
 55         begin
 56             wait_cnt <= 32'd0;
 57             tx_data <= tx_str; 
 58 
 59             if(tx_data_valid == 1'b1 && tx_data_ready == 1'b1 && tx_cnt < 8'd12)//Send 12 bytes data
 60             begin
 61                 tx_cnt <= tx_cnt + 8'd1; //Send data counter
 62             end
 63             else if(tx_data_valid && tx_data_ready)//last byte sent is complete
 64             begin
 65                 tx_cnt <= 8'd0;
 66                 tx_data_valid <= 1'b0;
 67                 state <= WAIT;
 68             end
 69             else if(~tx_data_valid)
 70             begin
 71                 tx_data_valid <= 1'b1;
 72             end
 73         end
 74         WAIT:
 75         begin
 76             wait_cnt <= wait_cnt + 32'd1;
 77 
 78             if(rx_data_valid == 1'b1)
 79             begin
 80                 tx_data_valid <= 1'b1;
 81                 tx_data <= rx_data;   // send uart received data 发送接收到的数据
 82             end
 83             else if(tx_data_valid && tx_data_ready)
 84             begin
 85                 tx_data_valid <= 1'b0;
 86             end
 87             //else if(wait_cnt >= CLK_FRE * 1000000) // wait for 1 second  and back to send state
 88             //state <= SEND;
 89         end
 90         default:
 91             state <= IDLE;
 92     endcase
 93 end
 94 
 95 //combinational logic
 96 //Send "HELLO ALINX\r\n"
 97 always@(*)
 98 begin
 99     case(tx_cnt)
100         8'd0 :  tx_str <= "H";
101         8'd1 :  tx_str <= "E";
102         8'd2 :  tx_str <= "L";
103         8'd3 :  tx_str <= "L";
104         8'd4 :  tx_str <= "O";
105         8'd5 :  tx_str <= " ";
106         8'd6 :  tx_str <= "A";
107         8'd7 :  tx_str <= "L";
108         8'd8 :  tx_str <= "I";
109         8'd9 :  tx_str <= "N";
110         8'd10:  tx_str <= "X";
111         8'd11:  tx_str <= "\r";
112         8'd12:  tx_str <= "\n";
113         default:tx_str <= 8'd0;
114     endcase
115 end
116 
117 uart_rx#//如果只要接收的话应该只需要这个模块就行
118 (
119     .CLK_FRE(CLK_FRE),
120     .BAUD_RATE(115200)
121 ) uart_rx_inst
122 (
123     .clk                        (clk                      ),
124     .rst_n                      (rst_n                    ),
125     .rx_data                    (rx_data                  ),
126     .rx_data_valid              (rx_data_valid            ),
127     .rx_data_ready              (rx_data_ready            ),
128     .rx_pin                     (uart_rx                  )
129 );
130 
131 uart_tx#
132 (
133     .CLK_FRE(CLK_FRE),
134     .BAUD_RATE(115200)
135 ) uart_tx_inst
136 (
137     .clk                        (clk                      ),
138     .rst_n                      (rst_n                    ),
139     .tx_data                    (tx_data                  ),
140     .tx_data_valid              (tx_data_valid            ),
141     .tx_data_ready              (tx_data_ready            ),
142     .tx_pin                     (uart_tx                  )
143 );
144 endmodule

3-4频率的控制使用相位累加器,具体原理可以参考底部模块。使用freqctrl1的最高8位用于频率控制以提高输出频率的精度,相位累加器代码如下:

 1 `timescale 1ns/1ps
 2 module addr_ctrl(
 3     input wire clk_50M,
 4     input wire rst_n,
 5     output wire [7:0] addr,
 6     
 7     
 8     input wire [31:0] freqctrl//频率控制字
 9     
10 );
11     reg [31:0] cnt;
12     assign addr =  cnt[31:24];
13     
14     always@(posedge clk_50M,negedge rst_n)
15     begin
16         if(rst_n==0)
17             cnt<=0;
18         else
19             cnt<=cnt+freqctrl;
20     
21     end
22 endmodule

3-4工程顶层模块

代码如下

  1 `timescale 1ns/1ps
  2 module adda_out(
  3     input clk,
  4     output wire [7:0] dacdata,
  5     output dac_clk,
  6     
  7     
  8     input    [3:0] key_in,
  9     
 10     
 11     input                         uart_rx,//串口通信相关
 12     output                        uart_tx
 13 
 14 );
 15     wire rst_n=key_in[0];
 16 
 17     wire [7:0] rom_address;//例化的输出只能为wire型
 18     assign dac_clk=clk;
 19 
 20     
 21     
 22 initial
 23 begin
 24 
 25     truefre=60'd0;
 26 
 27 end    
 28     
 29     
 30 /***********************************************/
 31     reg [3:0]   key;//检测按键是否按下
 32     wire[3:0]    flag;
 33     
 34 //按键状态锁存
 35 always@(negedge clk)
 36 begin
 37     if(flag==4'b1000)
 38     begin
 39     key<=4'b1000;
 40     end
 41     else if (flag==4'b0100)
 42     begin
 43     key<=4'b0100;
 44     end
 45     else if (flag==4'b0010)
 46     begin
 47     key<=4'b0010;
 48     end
 49 end    
 50 /***********波形选择*************************/
 51 wire [7:0] rom_data;
 52 wire [7:0] rom_datarec;//save rec
 53 wire [7:0] rom_datatri;//save tri
 54 reg [7:0] save_data;//存储选择的输出的波形
 55 assign dacdata =  save_data;//get rom data
 56 
 57 
 58 always @(negedge clk)
 59 begin
 60     if(key==4'b1000 )
 61     begin
 62         save_data<=rom_data;
 63     end
 64     else if(key==4'b0100 )
 65     begin
 66         save_data<=rom_datarec;
 67     end
 68         else if(key==4'b0010 )
 69     begin
 70         save_data<=rom_datatri;
 71     end
 72 end
 73 /**************频率控制***********************
 74 
 75 ***********串口通信相关************************/
 76 wire    [7:0]     receive_data;    //存储串口得到的数据
 77 reg [59:0] truefre;
 78 wire rxflag;//判断数据是否接收完毕
 79 //计算公式:fre=2^32*F(希望得到的频率)*TCLK(时钟源的周期,此处为20ns)
 80 
 81 
 82 always@(negedge clk)
 83 begin
 84     if(rxflag==1'b1)
 85     begin
 86         if( receive_data>=8'd48 && receive_data<=8'd57)
 87         begin
 88             truefre<=truefre*10+receive_data-8'd48;
 89         end
 90         else if(receive_data==8'd115)
 91         
 92         begin
 93             truefre<=truefre*8589934/100000;//注意数据溢出
 94         end
 95     
 96         else 
 97         
 98         begin
 99             truefre<=60'd0;
100         end
101 
102     end
103     
104     
105 end
106 /**************模块例化过程*******************/
107 
108 addr_ctrl addr_ctrl_inst(
109     .clk_50M(clk),
110     .rst_n(rst_n),
111     .addr(rom_address),
112     .freqctrl(truefre[31:0])
113 
114 );
115 
116 sin sin_inst(
117     .clock(clk),
118     .address(rom_address),
119     .q(rom_data)
120 
121 );
122 
123 
124 
125 rec rec_inst(
126     .clock(clk),
127     .address(rom_address),
128     .q(rom_datarec)
129 
130 
131 );
132 
133 tri_x tri_x_inst(
134     .clock(clk),
135     .address(rom_address),
136     .q(rom_datatri)
137 );
138 
139 key_test key_test_inst(        //key模块例化
140     .clk(clk),
141     .key(key_in),
142     .led(flag)
143 );
144 
145 uart_test uart_test_inst(
146     .clk(clk),
147     .rst_n(key_in[0]),
148     .uart_rx(uart_rx),
149     .uart_tx(uart_tx),
150     .receive_data(receive_data),
151     .rxflag(rxflag)
152 );
153 
154 
155 endmodule

主要注意点为:

1.truefre作为频率控制寄存器,设为60位主要考虑到 (88行和93行)数据相乘过大可能造成数据溢出,而设成的位数较多可以避免数据溢出,而调用时只需要将truefre的低32位接入相位累加器模块即可。

2.uart_test的模块例化,rxflag为数据接收的判断位,在82~102行为串口接收的数据处理,save_data[7:0]为接收到的数据单字节数据。

rxflag=1,确认接收到数据之后判断,如果为‘0’~‘9’接收到数字,则truefre*10并加上接收到的单字节字符,若接收到's',ASCII码为115则认一次接收数据结束,并重新设置频率。(当然也可以用典型的状态机实现)

如果接收到非以上几种情况则将之前的数据清空避免重复叠加。

4)实验结果:

成功实现2MHZ内精确的频率设置(2MHZ内精确到1HZ应该是没问题的,但是示波器2M时精确度的小数位数未设置所以不能直接观察到),并通过按键来实现3种频率的转换。以下为实际效果图。

 

 

 

参考的DDS原理博客:https://www.cnblogs.com/fendoudexiaohai/p/9504027.html

          https://www.cnblogs.com/fendoudexiaohai/archive/2004/01/13/9506170.html

 

$flag 上一页 下一页