本文利用FPGA控制AD9833,實(shí)現(xiàn)信號(hào)發(fā)生器的功能。本文將對(duì)AD9833的手冊(cè)進(jìn)行詳細(xì)的解讀,并對(duì)其配置方法進(jìn)行解析,最后在Verilog中進(jìn)行編碼,將代碼燒錄置FPGA中,F(xiàn)PGA通過(guò)外部引腳控制AD9833輸出所需要的正弦波、方波和三角波。三種波形能夠輸出的頻率范圍為0~12.5Mhz。
前言
AD9833是一種低功率可編程波形發(fā)生器,能夠產(chǎn)生正弦、三角形和方波輸出。在各種類型的傳感、驅(qū)動(dòng)和時(shí)域反射測(cè)量應(yīng)用中,都需要產(chǎn)生波形。輸出頻率和相位是軟件可編程的,允許易于調(diào)整。不需要任何外部組件。頻率寄存器為28位;以25MHz的時(shí)鐘速率,可以達(dá)到0.1 Hz的分辨率。類似地,使用1MHz的時(shí)鐘速率,AD9833可以被調(diào)諧到0.004 Hz的分辨率。
AD9833是通過(guò)三線串行接口寫入的。該串行接口以時(shí)鐘速率高達(dá)40MHz,并與DSP和微控制器標(biāo)準(zhǔn)兼容。該設(shè)備的電源供電范圍為2.3V至5.5V。
一、AD9833數(shù)據(jù)手冊(cè)分析
博主將首先分析AD9833的數(shù)據(jù)手冊(cè),并列出博主認(rèn)為手冊(cè)中需要著重注意的點(diǎn),以便于后續(xù)代碼的提出。
1.1 AD9833特性分析
在AD9833的規(guī)格中,我們可以知道,其
V
o
u
t
V_{out}
Vout? 也就是最大輸出電壓可以達(dá)到0.65V,其具體的表達(dá)式如下:
V
O
U
T
=
V
R
E
F
×
18
×
R
LOAD
/
R
S
E
T
×
(
1
+
(
S
I
N
(
2
π
(
F
R
E
Q
R
E
G
×
f
M
C
L
K
×
t
/
2
28
+
P
H
A
S
E
R
E
G
/
2
12
)
)
)
)
V_{\mathsf{OUT}}=V_{\mathsf{REF}}\times18\times\mathsf{R}_\text{LOAD}/{ \mathsf{R}_{\mathsf{SET}}}\times(1+(\mathsf{SIN}(2\pi(\mathsf{FREQREG}\times\mathbf{f}_{\mathsf{MCLK}}\times\mathbf{t}_{/2}28+\mathsf{PHASEREG}_{/2}12))))
VOUT?=VREF?×18×RLOAD?/RSET?×(1+(SIN(2π(FREQREG×fMCLK?×t/2?28+PHASEREG/2?12))))
即:輸出電壓的大小跟參考電壓和負(fù)載電阻密切相關(guān),同時(shí)隨著設(shè)置波形頻率的變化而變化。
另外,AD9833的VDD的范圍為2.3V-5.5V,也就是說(shuō)你需要提供一定數(shù)值的電源電壓。
1.2 AD9833時(shí)鐘分析
在手冊(cè)中,我們可以看到AD9833的時(shí)鐘圖如圖1所示:
在圖1中,我們需要著重關(guān)注的是AD9833的MCLK周期最小為40ns,也就是說(shuō)你需要提供25Mhz的激勵(lì)時(shí)鐘信號(hào),用于驅(qū)動(dòng)AD9833進(jìn)行內(nèi)部數(shù)據(jù)操作。
觀察圖2,我們可知:如何需要寫入AD9833的控制字,我們首先需要將FSYNC拉低,在SCLK操作時(shí)鐘的周期性變化下,將SDATA也就是操作字逐一寫入。需要注意的是,SCLK的操作時(shí)鐘周期最小需要25ns,高低電平的維持時(shí)間最小需要10ns,在最后一個(gè)下降沿?cái)?shù)據(jù)寫入后需要在10ns-20ns
的時(shí)間內(nèi)將FSYNC的電平拉高,否則寫入無(wú)效。
1.3 AD9833引腳分析
AD9833的引腳圖如圖3所示:
在AD9833的引腳中,MCLK為激勵(lì)時(shí)鐘,我們采用25Mhz;FSYNC在拉低后進(jìn)行寫入操作,隨著SCLK的電平變化將SDATA的值讀入。另外,VDD和AGND之間應(yīng)連接一個(gè)0.1uF和一個(gè)10uF的解耦電容。
1.4 AD9833操作原理分析
要想講清楚AD9833的控制方式,我們需要重點(diǎn)觀察其操作字是如何定義的。
在上述的16個(gè)控制位中,博主將講解需要著重觀察的控制位,其他控制位請(qǐng)讀者自行查看手冊(cè)。
- B28
當(dāng)B28 = 1時(shí)允許連續(xù)兩次寫入將完整單詞加載到頻率寄存器中。第一次寫包含頻率單詞的14個(gè)LSB,下一次寫將包含14個(gè)MSB。每個(gè)16位字的前兩位定義了該字被加載到的頻率寄存器,因此,對(duì)于這兩個(gè)連續(xù)的寫操作,前兩位應(yīng)該是相同的。
當(dāng)B28 = 0時(shí),28位頻率寄存器作為兩個(gè)14位寄存器運(yùn)行,一個(gè)包含14個(gè)MSB,另一個(gè)包含14個(gè)LSB。這意味著頻率詞的14個(gè)MSB可以獨(dú)立于14個(gè)LSB進(jìn)行改變,反之亦然。為了改變14個(gè)MSB或14個(gè)LSB,需要對(duì)適當(dāng)?shù)念l率地址進(jìn)行一次寫入??刂莆籇12(HLB)通知AD9833,要改變的位是14個(gè)MSB還是14個(gè)LSB。
博主在后文中將B28 = 1,也就是連續(xù)寫入兩個(gè)16位字對(duì)頻率寄存器進(jìn)行更改。 - RESET
RESET = 1將內(nèi)部寄存器重置為0,這對(duì)應(yīng)于中度的模擬輸出。
RESET = 0將禁用重置。
需要注意的是,RESET將不重置相位、頻率和控制寄存器。另外,為了避免AD9833在初始化的時(shí)候出現(xiàn)虛假的DAC輸出,需要在進(jìn)行寫入操作時(shí)也就是B28 = 1時(shí)將RESET位置1。 - MODE
MODE位與OPBITEN(D5)一起使用。這個(gè)位的功能是控制芯片上DAC連接到VOUT時(shí)VOUT引腳的輸出。
當(dāng)MODE = 1時(shí)三角波將從DAC中輸出。
當(dāng)MODE = 0時(shí)正弦波將輸出。
接下來(lái)我們將利用代碼來(lái)詳細(xì)論述操作字的寫入流程。
二、FPGA控制代碼
我們將利用Verilog語(yǔ)言編寫FPGA的代碼,并用FPGA控制AD9833的SCLK、SDATA、FSYNC引腳,進(jìn)行寫入操作。
2.1 主函數(shù)
主函數(shù)中主要包含了各個(gè)模塊,并將模塊之間的變量聯(lián)系起來(lái)。
module Signal_Generate(
input sys_clk,
input sys_rst_n,
input key0, // 按鍵檢測(cè)切換波形狀態(tài)
input key1,
output MCP_CS, // MCP使能標(biāo)志 低電平有效
output SCK, // MCP輸入信號(hào)狀態(tài) 低電平信號(hào)變化 下降沿讀信號(hào)
output SI, // MCP輸入信號(hào)
output AD_FSYNC // AD使能標(biāo)志
);
// parameter define
parameter CLK_FREQ = 26'd50_000_000; // MCP模塊的驅(qū)動(dòng)時(shí)鐘頻率
parameter MCP_FREQ = 18'd25_000_000; // MCP的SCK時(shí)鐘頻率
// wire define
wire MCP_CLK; // MCP時(shí)鐘信號(hào)
wire locked;
wire [15:0] TxData; // 寫入AD的操作數(shù)
wire TxData_en; // 開始寫入標(biāo)志位
wire TxData_done; // 寫入完成標(biāo)志位
wire [ 7:0] counter_rem; // 實(shí)時(shí)觀察寫入情況
wire [ 7:0] counter_rem_driver; // 實(shí)時(shí)觀察驅(qū)動(dòng)情況
//***************************************************
//**** main code ****
//***************************************************
// 例化按鍵消抖模塊
key_debounce u_key0_debounce(
.clk (sys_clk),
.rst_n (sys_rst_n),
.key (key0),
.key_value (key0_value), // 按下后為低電平 輸出
.key_flag (key0_flag) // 按下后標(biāo)志位拉高 輸出
);
key_debounce u_key1_debounce(
.clk (sys_clk),
.rst_n (sys_rst_n),
.key (key1),
.key_value (key1_value), // 按下后為低電平 輸出
.key_flag (key1_flag) // 按下后標(biāo)志位拉高 輸出
);
// AD根據(jù)操作數(shù)寫入16bits模塊
AD_Write u_AD_Write(
.clk (sys_clk),
.rst_n (sys_rst_n),
.TxData (TxData), // 寫入16位二進(jìn)制操作數(shù)
.TxData_en (TxData_en), // 開始寫入標(biāo)志位 輸入
.TxData_done(TxData_done), // 寫入完成標(biāo)志位 輸出
.counter_rem(counter_rem), // 實(shí)時(shí)檢查寫入位置
.AD_SCK (SCK), // AD操作時(shí)鐘
.AD_FSYNC (AD_FSYNC), // AD使能標(biāo)志位
.AD_SI (SI) // AD寫入數(shù)據(jù)
);
// AD驅(qū)動(dòng)模塊
AD_Driver u_AD_Driver(
.clk (sys_clk),
.rst_n (sys_rst_n),
.key0_value (key0_value),
.key0_flag (key0_flag),
.key1_value (key1_value),
.key1_flag (key1_flag),
.counter_rem_driver (counter_rem_driver), // 實(shí)時(shí)檢查驅(qū)動(dòng)位置
.TxData_done (TxData_done), // 寫入完成標(biāo)志位 輸入
.TxData (TxData), // 寫入操作數(shù)
.TxData_en (TxData_en) // 開始寫入標(biāo)志位 輸出
);
// ILA檢測(cè)模塊
ila_0 u_ila_0(
.clk (sys_clk), // input wire clk
.probe0 (AD_FSYNC), // input wire [0:0] probe0
.probe1 (SCK), // input wire [0:0] probe1
.probe2 (SI), // input wire [0:0] probe2
.probe3 (TxData_en), // input wire [0:0] probe3
.probe4 (TxData_done), // input wire [0:0] probe4
.probe5 (TxData), // input wire [15:0] probe5
.probe6 (counter_rem_driver) // input wire [7:0] probe6
);
endmodule
接下來(lái),我將對(duì)函數(shù)的主要功能進(jìn)行介紹。
- key_debounce
此函數(shù)的主要功能是對(duì)外部按鍵KEY0和KEY1是否按下進(jìn)行判斷,當(dāng)KEY0按下后,將進(jìn)行波形變換操作,當(dāng)KEY1按下后,將進(jìn)行頻率變換操作。后文會(huì)有提及。 - AD_Write
此函數(shù)主要功能是將一個(gè)16位的操作字根據(jù)一定的時(shí)序?qū)懭氲紸D9833中,在寫入完成后將TxData_done
置位,AD_Driver接收到置位信息后,將后續(xù)需要寫入的操作字賦值給TxData
中,并將開始寫入標(biāo)志位TxData_en
置位。 - AD_Driver
此函數(shù)的主要功能是根據(jù)當(dāng)前狀態(tài)變更狀態(tài)字,以及控制AD9833需要輸出的波形和頻率。 - ILA
檢測(cè)模塊ILA用于實(shí)時(shí)檢測(cè)。
2.2 按鍵檢測(cè)模塊
按鍵檢測(cè)模塊通過(guò)延時(shí)消抖來(lái)檢測(cè)按鍵值變化是否有效。
module key_debounce(
input clk,
input rst_n,
input key, // 外部輸入按鍵值
output reg key_value, // 消抖后的按鍵值
output reg key_flag // 消抖后的按鍵值有效標(biāo)志
);
reg [19:0] cnt;
reg key_reg;
// 按鍵值消抖
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt <= 20'd0;
key_reg <= 1'b1;
end
else begin
key_reg <= key;
if(key_reg != key) begin // 檢測(cè)到按鍵值變化
cnt <= 20'd100_0000; // 開啟延時(shí)
end
else begin
if(cnt > 20'd0) // 延時(shí)過(guò)程
cnt <= cnt - 1'b1;
else
cnt <= 20'd0;
end
end
end
// 輸出最終值
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
key_value <= 1'b1; // 沒有按下時(shí)默認(rèn)為高電平
key_flag <= 1'b0; // 標(biāo)志位為無(wú)效標(biāo)志
end
// 計(jì)時(shí)器遞減到1時(shí)輸出按鍵值
else if(cnt == 20'd1) begin
key_value <= key; // 將消抖后的數(shù)值保存
key_flag <= 1'b1; // 標(biāo)志位為有效標(biāo)志
end
else begin
key_value <= key_value; // 計(jì)時(shí)器為結(jié)束則保持原有數(shù)值
key_flag <= 1'b0;
end
end
endmodule
KEY0和KEY1在復(fù)位狀態(tài)下為高電平,當(dāng)按鍵按下后變更為低電平。在此模塊中,我們用key_reg
寄存器來(lái)存儲(chǔ)上一時(shí)刻KEY的狀態(tài),當(dāng)檢測(cè)到其與當(dāng)前時(shí)刻的KEY狀態(tài)不一致時(shí)進(jìn)行100_0000個(gè)時(shí)鐘周期的延時(shí),也就是20ns*100_0000=20ms的延時(shí),如果按鍵狀態(tài)在該時(shí)間內(nèi)為發(fā)生變化說(shuō)明按下有效。將key_value
和key_flag
位變更。
2.3 操作寫入模塊
此模塊,用于將操作字根據(jù)一定的時(shí)序?qū)懭搿?/p>
module AD_Write(
input clk,
input rst_n,
input [15:0] TxData, // 寫入16位二進(jìn)制操作數(shù)
input TxData_en, // 開始寫入標(biāo)志位
output reg TxData_done, // 寫入完成標(biāo)志位
output counter_rem, // 實(shí)時(shí)檢查寫入位置
output reg AD_SCK, // AD操作時(shí)鐘
output reg AD_FSYNC, // AD使能標(biāo)志位
output reg AD_SI // AD寫入數(shù)據(jù)
);
// reg define
reg [15:0] data; // 寫入的16位操作數(shù)
reg [ 7:0] counter; // 寫入時(shí)序
reg tx_en; // 保存寫入標(biāo)志位
// wire define
//***************************************************
//**** main code ****
//***************************************************
assign counter_rem = counter;
// 使能后頻數(shù)計(jì)數(shù)器
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
counter <= 8'd0;
TxData_done <= 1'b0;
tx_en <= 1'b0;
end
else begin
// 接收到發(fā)送信號(hào)
if(TxData_en) begin
tx_en <= 1'b1; // 保存開始寫入標(biāo)志位
end
else begin
if(tx_en) begin // 數(shù)據(jù)發(fā)送時(shí)使能計(jì)數(shù)器
if(counter < 8'd33) begin
counter <= counter + 1'b1;
TxData_done <= 1'b0;
end else begin // 在counter計(jì)數(shù)到完成操作后重置
counter <= 8'd0;
tx_en <= 1'b0; // 結(jié)束發(fā)送
TxData_done <= 1'b1; // 置位操作完成位
end
end
else begin
counter <= 8'd0;
TxData_done <= 1'b0;
tx_en <= tx_en;
end
end
end
end
// Control the AD_SCK, AD_FSYNC, and DAT pins based on the TxData input
// AD在SCK為高電平時(shí)改變狀態(tài) 在SCK下降沿時(shí)寫入數(shù)據(jù)
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
AD_SCK <= 1;
AD_FSYNC <= 1;
AD_SI <= 0;
end else begin
// 開始發(fā)送16bits數(shù)據(jù)
if(tx_en) begin
case(counter)
// 準(zhǔn)備工作
8'd0: begin
data <= TxData; // 寄存數(shù)據(jù)
AD_SCK <= 1; // FSYNC拉低時(shí)SCK為高
AD_FSYNC <= 0; // 使能發(fā)送
AD_SI <= 0; // 默認(rèn)
end
// first 16bits
8'd1: begin
AD_SCK <= 1;
AD_SI <= data[15]; // SI取數(shù)據(jù)最高位
end
8'd2: begin
AD_SCK <= 0;
end
8'd3: begin
AD_SCK <= 1;
AD_SI <= data[14];
end
8'd4: begin
AD_SCK <= 0;
end
8'd5: begin
AD_SCK <= 1;
AD_SI <= data[13];
end
8'd6: begin
AD_SCK <= 0;
end
8'd7: begin
AD_SCK <= 1;
AD_SI <= data[12];
end
8'd8: begin
AD_SCK <= 0;
end
8'd9: begin
AD_SCK <= 1;
AD_SI <= data[11];
end
8'd10: begin
AD_SCK <= 0;
end
8'd11: begin
AD_SCK <= 1;
AD_SI <= data[10];
end
8'd12: begin
AD_SCK <= 0;
end
8'd13: begin
AD_SCK <= 1;
AD_SI <= data[9];
end
8'd14: begin
AD_SCK <= 0;
end
8'd15: begin
AD_SCK <= 1;
AD_SI <= data[8];
end
8'd16: begin
AD_SCK <= 0;
end
8'd17: begin
AD_SCK <= 1;
AD_SI <= data[7];
end
8'd18: begin
AD_SCK <= 0;
end
8'd19: begin
AD_SCK <= 1;
AD_SI <= data[6];
end
8'd20: begin
AD_SCK <= 0;
end
8'd21: begin
AD_SCK <= 1;
AD_SI <= data[5];
end
8'd22: begin
AD_SCK <= 0;
end
8'd23: begin
AD_SCK <= 1;
AD_SI <= data[4];
end
8'd24: begin
AD_SCK <= 0;
end
8'd25: begin
AD_SCK <= 1;
AD_SI <= data[3];
end
8'd26: begin
AD_SCK <= 0;
end
8'd27: begin
AD_SCK <= 1;
AD_SI <= data[2];
end
8'd28: begin
AD_SCK <= 0;
end
8'd29: begin
AD_SCK <= 1;
AD_SI <= data[1];
end
8'd30: begin
AD_SCK <= 0;
end
8'd31: begin
AD_SCK <= 1;
AD_SI <= data[0]; // SI取數(shù)據(jù)最低位
end
8'd32: begin
AD_SCK <= 0; // 寫入最后一位數(shù)據(jù)
end
// the end
8'd33: begin
AD_SCK <= 1;
AD_FSYNC <= 1;
AD_SI <= 0;
end
default: begin
AD_SCK <= 1;
AD_FSYNC <= 1;
AD_SI <= 0;
end
endcase
end
else begin
AD_SCK <= 1;
AD_FSYNC <= 1;
AD_SI <= 0;
end
end
end
endmodule
當(dāng)檢測(cè)到操作寫入信號(hào)TxData_en
被置位時(shí),將模塊內(nèi)寄存器tx_en
置位,用于保存置位信號(hào),因?yàn)?code>TxData_en將在一個(gè)時(shí)鐘周期后被拉低。
當(dāng)置位信號(hào)保存完成后,將開始寫入操作,counter
作為寫入的寄存器用于寄存當(dāng)前寫入的位置。當(dāng)counter
為0時(shí),將需要寫入的數(shù)據(jù)保存到data
中,并將FSYNC
拉低,表示我們將要開始寫入操作。注意:在FSYNC
拉低時(shí),我們需要確保SCK
為高電平,否則FSYNC
的拉低無(wú)效。FSYNC
拉低后,我們?cè)?code>SCK為高電平時(shí),變更SI
為需要寫入數(shù)據(jù)的位次,保持一個(gè)時(shí)鐘周期20ns后,將SCK
拉低,AD9833在SCK
為下降沿時(shí)將SI
的數(shù)據(jù)讀入。以此往復(fù)直至寫入完成的操作字。
在寫入完成后,我們需要在10ns-20ns
的時(shí)間內(nèi)將FSYNC
拉高,否則寫入無(wú)效。并將TxData_done
置位,表示寫入完成了,可以進(jìn)行后續(xù)操作。
2.4 驅(qū)動(dòng)操作模塊
驅(qū)動(dòng)模塊,主要對(duì)寫入的操作字進(jìn)行變更,通過(guò)選擇合適的波形和頻率控制AD9833輸出。
module AD_Driver(
input clk,
input rst_n,
input key0_value,
input key0_flag,
input key1_value,
input key1_flag,
output [ 7:0] counter_rem_driver,
input TxData_done, // 寫入完成標(biāo)志位 輸入
output reg [15:0] TxData, // 寫入操作數(shù) 輸出
output reg TxData_en // 開始寫入標(biāo)志位 輸出
);
// local parameter define
localparam [15:0] reset_add = 16'h0100;
localparam [15:0] write_freq = 16'h2100;
// 為了避免在AD9833被初始化時(shí)出現(xiàn)虛假的DAC輸出
// 復(fù)位位應(yīng)該被設(shè)置為1 直到部件準(zhǔn)備好開始生成輸出為止
// fMck=25Mhz
// (fMclk/2^28/fwanted)^(-1)=FREQREG; fwanted(min)=0.0931, fwanted(max)=25M
localparam [15:0] write_freq_lsb_3M = 16'h70b7; // 輸出3M信號(hào)
localparam [15:0] write_freq_msb_3M = 16'h47ae;
localparam [15:0] write_freq_lsb_1M = 16'h6592; // 輸出1M信號(hào)
localparam [15:0] write_freq_msb_1M = 16'h428f;
localparam [15:0] write_freq_lsb_1k = 16'h69f1; // 輸出1k信號(hào)
localparam [15:0] write_freq_msb_1k = 16'h4000;
localparam [15:0] write_phase_c0 = 16'hc000; // 相位配置
localparam [15:0] write_sin = 16'h2000; // 正弦波
localparam [15:0] write_traingle = 16'h2002; // 三角波
localparam [15:0] write_square = 16'h2028; // 方波
// reg define
reg [ 7:0] counter; // 寫入操作開始后的位置
reg [31:0] delay_counter; // 開始寫入操作前的延遲
reg delay_start; // 延遲開始標(biāo)志位
reg delay_end; // 延遲結(jié)束標(biāo)志位
reg [ 2:0] waveform_select; // 選擇波形
reg [ 2:0] freq_select; // 選擇頻率
reg [15:0] write_waveform; // 寫入的波形類型
reg [15:0] write_freq_lsb_c0; // 寫入頻率數(shù)據(jù)的低位
reg [15:0] write_freq_msb_c0; // 寫入頻率數(shù)據(jù)的高位
// wire define
//***************************************************
//**** main code ****
//***************************************************
assign counter_rem_driver = counter;
// 開始延遲計(jì)數(shù)器
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
delay_counter <= 32'b0;
delay_start <= 1'b1;
delay_end <= 1'b0;
waveform_select <= 2'd0;
freq_select <= 2'd0;
end
else begin
// 初始化和波形頻率選擇后根據(jù)delay_start開啟延遲
if(delay_start) begin
if(delay_counter < 10'd1000) begin
delay_counter = delay_counter + 1'b1;
end
else begin
delay_counter <= 32'b0;
delay_start <= 1'b0;
// 將delay_end作為延遲結(jié)束的標(biāo)志 置1只存在一個(gè)周期
delay_end <= 1'b1;
end
end
// 根據(jù)按鍵調(diào)整波形和頻率
else begin
// key0按下調(diào)整輸出波形
if((key0_flag == 1) && (key0_value == 0)) begin
waveform_select <= waveform_select + 1'd1;
delay_start <= 1'b1;
delay_counter <= 32'b0;
delay_end <= 1'b0;
end
// key1按下調(diào)整輸出頻率
else if((key1_flag == 1) && (key1_value == 0)) begin
freq_select <= freq_select + 1'd1;
delay_start <= 1'b1;
delay_counter <= 32'b0;
delay_end <= 1'b0;
end
else begin
// default波形和頻率不變化
waveform_select <= waveform_select;
freq_select <= freq_select;
delay_counter <= 32'b0;
delay_end <= 1'b0;
end
end
end
end
// 切換波形種類
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
write_waveform <= write_sin;
end
else begin
case(waveform_select)
2'd0: begin
write_waveform <= write_sin;
end
2'd1: begin
write_waveform <= write_traingle;
end
2'd2: begin
write_waveform <= write_square;
end
default: begin
write_waveform <= write_sin;
end
endcase
end
end
// 切換頻率
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
write_freq_lsb_c0 <= write_freq_lsb_1M;
write_freq_msb_c0 <= write_freq_msb_1M;
end
else begin
case(freq_select)
2'd0: begin
write_freq_lsb_c0 <= write_freq_lsb_1M;
write_freq_msb_c0 <= write_freq_msb_1M;
end
2'd1: begin
write_freq_lsb_c0 <= write_freq_lsb_3M;
write_freq_msb_c0 <= write_freq_msb_3M;
end
2'd2: begin
write_freq_lsb_c0 <= write_freq_lsb_1k;
write_freq_msb_c0 <= write_freq_msb_1k;
end
default: begin
write_freq_lsb_c0 <= write_freq_lsb_1M;
write_freq_msb_c0 <= write_freq_msb_1M;
end
endcase
end
end
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
TxData <= 16'd0;
TxData_en <= 1'b0;
counter <= 8'd12;
end
else begin
// delay_end被置位后 將counter的值歸零 開始寫入操作數(shù)
// 否則寫入操作會(huì)在結(jié)束處不斷循環(huán)
if(delay_end) begin
counter <= 8'd0;
end
else begin
case(counter)
// 重置寄存器
8'd0: begin
TxData <= reset_add;
TxData_en <= 1'b1;
counter <= counter + 1'b1;
end
8'd1: begin
TxData <= TxData;
TxData_en <= 1'b0;
counter <= counter;
if(TxData_done) begin
counter <= counter + 1'b1;
end
end
// 選擇數(shù)據(jù)一次寫入
8'd2: begin
TxData <= write_freq;
TxData_en <= 1'b1;
counter <= counter + 1'b1;
end
8'd3: begin
TxData <= TxData;
TxData_en <= 1'b0;
counter <= counter;
if(TxData_done) begin
counter <= counter + 1'b1;
end
end
// 寫入頻率寄存器低14位
8'd4: begin
TxData <= write_freq_lsb_c0;
TxData_en <= 1'b1;
counter <= counter + 1'b1;
end
8'd5: begin
TxData <= TxData;
TxData_en <= 1'b0;
counter <= counter;
if(TxData_done) begin
counter <= counter + 1'b1;
end
end
// 寫入頻率寄存器高14位
8'd6: begin
TxData <= write_freq_msb_c0;
TxData_en <= 1'b1;
counter <= counter + 1'b1;
end
8'd7: begin
TxData <= TxData;
TxData_en <= 1'b0;
counter <= counter;
if(TxData_done) begin
counter <= counter + 1'b1;
end
end
// 寫入相位寄存器12位
// 不確定相位寄存器是否同時(shí)寫入 在圖例中相位寄存器無(wú)任何寫入的使能標(biāo)志位
8'd8: begin
TxData <= write_phase_c0;
TxData_en <= 1'b1;
counter <= counter + 1'b1;
end
8'd9: begin
TxData <= TxData;
TxData_en <= 1'b0;
counter <= counter;
if(TxData_done) begin
counter <= counter + 1'b1;
end
end
// 選擇波形輸出器
8'd10: begin
TxData <= write_waveform;
TxData_en <= 1'b1;
counter <= counter + 1'b1;
end
8'd11: begin
TxData <= TxData;
TxData_en <= 1'b0;
counter <= counter;
if(TxData_done) begin
counter <= counter + 1'b1;
end
end
// 結(jié)束 將使能位TxData_en拉低
8'd12: begin
TxData <= 16'd0;
TxData_en <= 1'b0;
counter <= counter;
end
default: begin
counter <= counter;
end
endcase
end
end
end
endmodule
FPGA重置后,delay_start
置位,經(jīng)過(guò)一定的延時(shí)后,開始初始化寫入1Mhz的正弦波信號(hào)。寫入的過(guò)程如下:
- 重置寄存器
- 選擇數(shù)據(jù)一次寫入
- 寫入頻率寄存器低14位
- 寫入頻率寄存器高14位
- 寫入相位寄存器12位
- 選擇波形輸出
- 循環(huán)等待按鍵按下重置上述流程
當(dāng)檢測(cè)到按鍵按下時(shí),即key_flag
和key_value
變化時(shí),波形選擇寄存器和頻率選擇寄存器會(huì)發(fā)生變化。以此來(lái)選擇正弦波、三角波、方波和1M、3M和1K的頻率信號(hào)。
三、結(jié)果展示
FPGA引腳輸出。
圖5是FPGA的引腳輸出狀態(tài)??梢钥吹?code>FSYNC為低電平時(shí)開始寫入操作,TxData
為寫入操作字,SI
逐一讀取寫入位,跟隨著SCK
的變化寫入。
3M的正弦波。
可以觀察到周期是333ns,也就是3M,輸出頻率很精準(zhǔn)。另外是436mV的峰峰值(經(jīng)過(guò)外部運(yùn)放放大后的,放大倍數(shù)為6.1倍),不超過(guò)手冊(cè)中的650mV。
1K的正弦波。
其余波形和頻率,博主忘記拍了=.=
,但確實(shí)完整輸出了三角波和方波(只要按一下按鍵就行)。就不重新連了,有點(diǎn)懶。
最后的最后,展示一下AD9833在原理圖中的連接圖。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-777017.html
總結(jié)
本文,首先分析了AD9833的芯片手冊(cè),根據(jù)其芯片手冊(cè)的內(nèi)容,我們用Verilog語(yǔ)言編寫了控制程序,并燒錄至FPGA中用于控制AD9833。最后得到不同波形和頻率的輸出結(jié)果。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-777017.html
到了這里,關(guān)于基于AD9833的信號(hào)發(fā)生器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!