一、AD9954模塊簡介
AD9954是一款直接數字頻率合成器(DDS),采用先進技術內置一個高速高性能DAC,構成完整的數字可編程、高頻合成器能夠產生高達150MHz的頻率捷變模擬輸出正弦波。它能夠實現快速跳頻,同時還具有精密頻率調諧(0.01Hz或更高分辨率)和相位諧波(0.022°間隔)默認程序1hz可調用戶如需更高精度需自行修改程序通過一個高速串行I/0端口可以進行編程。該器件內置靜態RAM支持多種模式下的靈活掃頻功能,并且支持用戶定義的線性掃描工作模式同時內置一個片內高速比較器,適合要求方波輸出的應用。借助片內振蕩器和PLL電路,用戶可以用多種方法產生器件的系統時鐘AD9954的額定工作溫度范圍為擴展工業溫度范圍。
特性
- 模塊供電:DC 5V
- 通訊協議:SPI串行
- 系統主頻:400MHz(MAX)
- DAC分辨率位數:14位
- 相位累加器位數:32位
- 輸出信號:正弦波,方波;正弦波帶150MHz低通濾波器,方波耦合輸出
- 輸出通道:2通道差分,相位差180°,高頻輸出由于有濾波器,相位會偏移
- 信號特點:正弦波無耦合輸出;輸出自帶直流分量,接入射頻設備請加隔直流器,也可直接使用示波器測量
- 正弦波,方波最高主頻輸出:1Hz-140MHz(正弦波),1Hz-120MHz(方波),10MHz以上需要示波器輸入阻抗為50歐
- 輸出幅度:正弦波200mVpp,方波1.8Vpp,正弦波隨著頻率增加幅度減小,方波隨著頻率增加波 形變化
- 輸出阻抗:75歐
模塊應用
- 頻率信號發生,正弦波、方波信號發生,傳感器激勵

二、模塊接口說明

| UPD | 上升沿將內部緩沖存儲器的內容傳輸到 I/O 寄存器 |
|---|---|
| PS0,PS1 | 輸入引腳用于選擇內部相位/頻率配置文件之一。這些引腳上的變化會觸發將所選內部緩沖存儲器的內容傳輸到 I/O 寄存器 |
| OSK | 輸入引腳用于控制編程后形狀關鍵控 (OSK) 功能的方向 |
| SDIO | 串行數據 I/O |
| SCK | 串行時鐘 |
| CS | 片選 |
| SDO | 串行數據輸出 |
| IOSY | 串行端口控制器異步高電平有效復位。當此引腳為高電平時,當前 I/O 操作立即終止,一旦 IOSYNC 返回低電平,即可開始新的 I/O 操作。 |
| RST | 硬件復位 |
| PWR | 輸入引腳用作外部掉電控制 |
三、功能框圖和時序圖說明

功能框圖說明
REFCLK輸入
AD9954 支持多種方式生成內部系統時鐘。芯片內部集成了振蕩器電路,可通過在 REFCLK 引腳外接晶體來產生低頻參考時鐘;同時也支持直接由外部時鐘源驅動 REFCLK 引腳。為了在低頻參考時鐘條件下仍獲得較高的 DDS 運算速率和 DAC 采樣率,AD9954 內部集成了基于 PLL 的參考時鐘倍頻器,可對 REFCLK 進行倍頻后作為系統時鐘使用。
在對相位噪聲要求較高的應用中,建議使用轉換速率高、抖動低、穩定性好的外部時鐘直接驅動 REFCLK,并旁路內部倍頻器,以獲得最佳頻譜性能。
倍頻器
板載鎖相環 (PLL) 允許對參考時鐘 (REFCLK) 頻率進行倍頻。倍頻系數通過 CFR2<7:3> 設置。當編程值為 0x04 至 0x14(十進制 4 至 20)范圍內的值時,PLL 會將 REFCLK 輸入頻率乘以編程值。用戶在編程時必須考慮 PLL 的指定最大頻率。如果更改倍頻系數,用戶必須預留時間讓 PLL 鎖定(約 1 毫秒)。當該字段編程為其他值時,PLL 被旁路并關閉,REFCLK 直接作為系統時鐘輸入。
頻率累加器
用于線性掃描模式;從起始頻率 (F0) 到終止頻率 (F1) 的轉換并非瞬時完成,而是以掃描或斜坡方式實現。這種頻率斜坡是通過步進 F0 和 F1 之間的中間頻率來實現的。線性掃描模塊使用下降和上升增量頻率調諧字、下降和上升增量頻率斜坡速率以及頻率累加器。線性掃描使能位 CFR1<21> 用于使能線性掃描模塊。線性掃描無停留位用于設置掃描過程中達到終止頻率時要執行的操作。
DDS核心
DDS 的輸出頻率 (fO) 是系統時鐘頻率 (SYSCLK)、頻率調諧字 (FTW) 的值以及相位累加器容量(本例中為 232)的函數。具體關系如下,其中 fs 定義為 SYSCLK 的頻率。
fO = (FTW)(fS)/232,其中 0 ≤ FTW ≤ 231
每個系統時鐘周期,FTW 的值都會加到相位累加器中先前存儲的值上。然后,將相位累加器的輸出值與用戶定義的 14 位相位偏移值 (POW) 相加。最后,通過 cos(x) 功能模塊將該和的最高 19 位轉換為幅度值。為了降低 DDS 內核的功耗,會截斷最低有效位 (LSB)。這種截斷不會降低頻率分辨率。在某些應用中,需要能夠強制輸出信號為零相位。簡單地將 FTW 設置為 0 并不能實現這一點;它只會使內核停留在其當前的相位值。系統提供了一個控制位,用于強制相位累加器輸出為零。上電復位后,相位累加器清零功能默認處于使能狀態,但該控制位需通過第一次 I/O UPDATE 才會真正生效。因此,在上電后未執行 I/O UPDATE 之前,相位累加器保持在零相位狀態。
DAC輸出
與許多DAC不同,AD9954的DAC輸出參考的是AVDD,而非AGND。兩個互補輸出提供組合的滿量程輸出電流(IOUT)。差分輸出可降低DAC輸出端可能存在的共模噪聲,從而提高信噪比。滿量程電流由連接在DAC_RSET引腳和DAC接地引腳(引腳49,裸露的電極片)之間的外部電阻(RSET)控制。滿量程電流與電阻值成正比,公式為:
RSET = (39.19 / Iout) Ω
組合DAC輸出的最大滿量程輸出電流為15 mA。將輸出限制在最大10 mA可獲得最佳的無雜散動態范圍(SFDR)性能。DAC 輸出必須保持在 AVDD ±0.5 V 的合規范圍內,超出該范圍將導致失真顯著增加,甚至可能損壞輸出級。實際應用中應通過合理的負載與偏置設計,確保 DAC 輸出始終工作在該合規范圍之內。
時序與串行接口說明
AD9954 提供一個靈活的同步串行接口,可方便地與多種微控制器或微處理器連接。該接口兼容常見同步串行協議,包括 Motorola 6905/11 SPI? 和 Intel? 8051 SSR。
串行接口支持:
- MSB 優先或 LSB 優先數據格式
- 單引腳雙向 SDIO(2 線接口)
- SDIO + SDO 分離(3 線接口)
接口配置由 CFR1 中的相關位控制。可選的 IOSYNC 與 CS 引腳進一步提升了系統集成的靈活性。
AD9954 的串行通信以 寄存器為單位,而非字節為單位。串口控制器在接收到指令字節后,會自動解析目標寄存器地址并完成整個寄存器寬度的數據傳輸。一個完整的通信周期分為兩個階段:
指令階段:在前 8 個 SCLK 上升沿寫入指令字節,用于指定讀/寫方向及寄存器地址。
數據階段:隨后的 SCLK 周期用于傳輸寄存器數據,傳輸位數由目標寄存器的位寬決定。
所有輸入數據在 SCLK 上升沿采樣,輸出數據在 SCLK 下降沿更新。相關時序如圖 25~圖 28 所示。
MSB/LSB 數據傳輸
AD9954 串口支持 MSB 優先或 LSB 優先的數據格式。此功能由 LSB 優先位 CFR1<8> 控制。對于 MSB 優先操作,串口控制器首先生成(指定寄存器的)最高有效字節地址,然后生成下一個較低有效字節地址,直到 I/O 操作完成。所有寫入(讀取)AD9954 的數據都必須采用 MSB 優先順序。如果 LSB 模式處于活動狀態,則串口控制器首先生成最低有效字節地址,然后生成下一個較高有效字節地址,直到 I/O 操作完成。所有寫入(讀取)AD9954 的數據都必須采用 LSB 優先的格式。
示例操作
例如,考慮將幅度比例因子 (ASF) 寄存器的值寫入滿量程的 0.5。首先,計算 0.5 的二進制等效值。由于 ASF 為 16 位寬,其十六進制等效值為 0x80。接下來,對于 MSB 優先的格式,發送指令字節 0x02(ASF 的串口地址為 00010(b))。根據該指令,內部控制器輪詢此內存位置的寄存器,并注意到 ASF 為 2 字節寬。串口控制器的狀態機設置為 16,并等待 SCLK 上的 16 個上升沿和 SDIO 線上的 16 位數據。發送 SCLK 上的 16 個上升沿,以及 SDIO 線上的二進制數據 10000000 00000000。要以 LSB 優先格式寫入幅度比例因子寄存器,其過程與 MSB 優先格式相同;但是,數據需要逐字進行按位反轉。指令字節為 0x40。幅度比例因子寄存器的二進制數據為 00000000 00000001。
四、主要寄存器說明
指令字節
指令字節包含以下信息。
R/W——指令字節的第 7 位定義在寫入指令字節后發生的是讀取還是寫入數據傳輸。邏輯高電平表示讀取操作,邏輯 0 表示寫入操作。
X, X——指令字節的第 6 位和第 5 位無關緊要。
A4, A3, A2, A1, A0——指令字節的第 4 位、第 3 位、第 2 位、第 1 位和第 0 位確定在通信周期的數據傳輸階段訪問哪個寄存器。寄存器的地址可以在寄存器映射表的第一列中找到(參見下表)。
寄存器映射表及說明
寄存器映射表列于表 12 和表 13 中。當前活動的寄存器映射表取決于線性掃描使能位的狀態;根據器件的工作模式,某些寄存器會被重新映射。具體來說,寄存器 0x??07、寄存器 0x??08、寄存器 0x??09 和寄存器 0x??0A 會受到影響。由于線性掃描操作的優先級高于 RAM 操作,Analog Devices 公司建議,當使用位 CFR1<21> 啟用線性掃描時,應使用位 CFR1<31> 禁用 RAM,以節省功耗。每個寄存器的序列地址采用十六進制格式。尖括號 <> 用于引用特定位或位范圍。例如,<3> 表示位 3,<7:3> 表示從位 7 到位 3(含位 7 和位 3)的位范圍。注意,RAM使能位CFR1<31>僅激活RAM本身,并不激活RAM段控制字。
前7個寄存器為固定映射(與模式無關)

寄存器映射 - 當線性掃描使能位為False時(CFR1<21> = 0)

寄存器映射 - 當線性掃描使能位為True時 (CFR1<21> = 1)
功能控制寄存器1 (CFR1) (0X00):用于控制 AD9954 的各種功能、特性和模式。其中:
CFR1<31>:0(默認):關閉 RAM,進入單頻/線性掃頻模式。1:開啟 RAM,可用于 FSK/PSK 或非線性調制模式。用于多頻調制場景。
CFR1<30>:0(默認):如果 CFR1<31> 被置位,則 RAM 輸出驅動相位累加器(提供 FTW)。1:如果 CFR1<31> 被置位,則 RAM 輸出驅動相位偏移加法器(POW)。
CFR1<21>:0:不進行線性掃頻 → 直接用 FTW0 單頻輸出。1:進入線性掃頻模式,需要配合 FTW0、FTW1、NLSCW、PLSCW 使用。線性掃頻是在頻率之間做連續過渡的功能。
功能控制寄存器2 (CFR2) (0X01):用于控制 AD9954 的各種功能、特性和模式,主要與芯片的模擬部分相關。其中:
CFR2<11>:0(默認):高速同步增強功能關閉。1:高速同步增強功能開啟。當 SYNC_CLK > 50 MHz (SYSCLK > 200 MSPS) 時,若使用自動同步功能,則應設置此位。
CFR2<7:3>:參考時鐘倍頻器控制位。此 5 位字控制時鐘倍頻器 (PLL) 模塊的輸出倍頻值。
CFR2<2>:0(默認):VCO 工作頻率范圍為 100 MHz 至 250 MHz。1:VCO 工作頻率范圍為 250 MHz 至 400 MHz。
幅度比例因子寄存器 (ASF) (0X02)
ASF 寄存器存儲 2 位自動斜坡速率值和 14 位幅度比例因子,用于輸出整形鍵控 (OSK) 操作。在自動 OSK 操作中,ASF<15:14> 指示 OSK 模塊每次增量或減量需要執行多少個幅度步長。ASF<13:0> 設置 OSK 內部乘法器可達到的最大值。在手動 OSK 模式下,ASF<15:14> 無效。ASF<13:0> 直接提供輸出比例因子。如果使用CFR1<25> 禁用 OSK,則此寄存器對設備操作沒有影響。
幅度斜坡速率寄存器 (ARR)(0x03):ARR 寄存器存儲自動 OSK 模式下使用的 8 位幅度斜坡速率。
頻率調諧字 0寄存器 (FTW0)(0x04):頻率調諧字是一個 32 位寄存器,用于控制 DDS 內核相位累加器的累加速率。
相位偏移字寄存器 (POW)(0x05):相位偏移字是一個 14 位寄存器,用于存儲相位偏移值。
頻率調諧字 1寄存器 (FTW1)(0x06):頻率調諧字是一個 32 位寄存器,用于設置線性掃描操作中的上限頻率。
正負線性掃描控制字寄存器 (PLSCW / NLSCW)(0x07~0x08)
當啟用線性掃頻位時,寄存器0x07提供負線性掃頻控制字(NLSCW),而寄存器0x08提供正線性掃頻控制字(PLSCW)。每個線性掃頻控制字包含一個32位的增量頻率調諧字(FDFTW和RDFTW)和一個8位的掃頻斜率字(FSRRW和RSRRW)。
負線性掃頻控制字(NLSCW):用于控制負向線性掃頻操作的相關參數,包括起始頻率和終止頻率之間的頻率差(增量頻率調諧字)以及掃頻的斜率(掃頻斜率字)。這些參數決定了掃頻的速率和方向。
正線性掃頻控制字(PLSCW):用于控制正向線性掃頻操作的參數,包括起始頻率和終止頻率之間的頻率差和掃頻的斜率。
NLSCW 和 PLSCW 本身并不定義起始頻率或終止頻率,而是用于定義線性掃頻過程中每一步的頻率增量(ΔFTW)以及頻率更新的時間間隔。線性掃頻的起始頻率由 FTW0 指定,終止頻率由 FTW1 指定。
五、STM32F103驅動AD9954發生器模塊
準備工作
STM32F103C8T6最小系統板,AD9954發生器模塊,OLED屏幕,EC11旋轉編碼器,按鍵和導線若干。
接線說明
| STM32F103C8T6 | AD9954 |
|---|---|
| 3V3 | 3V3 |
| GND | GND |
| PA3 | UPD |
| PA4 | PS1 |
| PA5 | PS0 |
| PA6 | OSK |
| PA7 | SDIO |
| PA11 | PWR |
| PA12 | IOSY |
| PA15 | SDO |
| PB0 | SCLK |
| PB1 | CS |
| PB10 | RES |
| PB8 | OLED -> SCL |
| PB9 | OLED -> SDA |
| PA0 | EC11旋轉編碼器 -> A,調節頻率增加 |
| PA1 | EC11旋轉編碼器 -> B,調節頻率減少 |
| PA2 | EC11旋轉編碼器 -> S,移位調節 |
| PB14 | 按鍵1,切換幅值或相位調節 |
| PB13,15 | 按鍵2,3,調節幅值或相位逐步加減 |
| PA8,PB12 | 按鍵4,5,調節幅值或相位快速加減 |

代碼示例
AD9954.c
#include "AD9954.h"
#include "delay.h"
//系統頻率fosc(外部晶振頻率),系統頻率=fs
#define fosc 20 //晶振頻率 20Mhz
#define PLL_MULTIPLIER 20 //PLL倍頻數(4--20)
#define fs (fosc*PLL_MULTIPLIER) //系統時鐘頻率
double fH_Num=10.73741824;
//double fH_Num=11.2204;
//double fH_Num=11.3671588397205;//
//double fH_Num = 11.3025455157895;//頻率轉換系數:2^32/系統時鐘頻率
/************************************************************
** 函數名稱 :void AD9954_GPIO_Init(void)
** 函數功能 :初始化控制AD9954需要用到的IO口
** 入口參數 :無
** 出口參數 :無
** 函數說明 :無
**************************************************************/
void AD9954_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_11|GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度為50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度為50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //設置成上拉輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);
AD9954_RES=0;
AD9954_CS =0;
AD9954_SCLK =0;
AD9954_SDIO=0;
AD9954_OSK=0;
PS0=0;
PS1=0;
IOUPDATE=0;
AD9954_IOSY=0;
AD9954_PWR=0;
delay_ms(10);
}
/*********************************************************************************************************
** 函數名稱 :void AD9954_RESET(void)
** 函數功能 :復位AD9954
** 入口參數 :無
** 出口參數 :無
** 函數說明 :不復位也可以
*********************************************************************************************************/
void AD9954_RESET(void)
{
AD9954_RES = 1;
delay_ms(10);
AD9954_RES = 0;
AD9954_CS = 0;
AD9954_SCLK = 0;
AD9954_CS = 1;
}
/*********************************************************************************************************
** 函數名稱 :void UPDATE(void)
** 函數功能 :產生一個更新信號,更新AD9954內部寄存器,
** 入口參數 :無
** 出口參數 :無
** 函數說明 :可以不加任何延時
*********************************************************************************************************/
void UPDATE(void)
{
IOUPDATE = 1;
delay_us(10);
IOUPDATE = 0;
}
/*********************************************************************************************************
** 函數名稱 :void AD9954_Send_Byte(uint8_t dat)
** 函數功能 :向AD9954發送一個字節的內容
** 入口參數 :待發送字節
** 出口參數 :無
** 函數說明 :AD9954的傳輸速度最大為25M,所以不加延時也可以
*********************************************************************************************************/
void AD9954_Send_Byte(uint8_t dat)
{
uint8_t i;
for (i = 0;i< 8;i++)
{
AD9954_SCLK = 0;
delay_us(10);
if (dat & 0x80)
{
AD9954_SDIO = 1;
}
else
{
AD9954_SDIO = 0;
}
AD9954_SCLK = 1;
delay_us(10);
dat < <= 1;
}
}
/*********************************************************************************************************
** 函數名稱 :uint8_t AD9954_Read_Byte(void)
** 函數功能 :讀AD9954一個字節的內容
** 入口參數 :無
** 出口參數 :讀出的一個字節數據
** 函數說明 :
*********************************************************************************************************/
uint8_t AD9954_Read_Byte(void)
{
uint8_t i,dat=0;
for (i = 0;i< 8;i++)
{
AD9954_SCLK = 0;
delay_us(2);
dat|=AD9954_SDO;
AD9954_SCLK = 1;
delay_us(2);
dat < <= 1;
}
return dat;
}
/************************************************************
** 函數名稱 :void AD9954_Write_nByte(uint8_t RegAddr,uint8_t *Data,uint8_t Len)
** 函數功能 :向AD9954指定的寄存器寫數據
** 入口參數 :RegAddr: 寄存器地址
*Data: 數據起始地址
Len: 要寫入的字節數
** 出口參數 :無
** 函數說明 :無
**************************************************************/
void AD9954_Write_nByte(uint8_t RegAddr,uint8_t *Data,uint8_t Len)
{
uint8_t t=0;
AD9954_Send_Byte(RegAddr);
for(t=0;t< Len;t++)
{
AD9954_Send_Byte(Data[t]);
}
}
/*********************************************************************************************************
** 函數名稱 :uint32_t AD9954_Read_nByte(uint8_t ReadAddr,uint8_t Len)
** 函數功能 :讀AD9954寄存器數據
** 入口參數 :ReadAddr:要讀出的寄存器地址
Len:要讀出數據的長度1-4
** 出口參數 :讀出的數據
** 函數說明 :
*********************************************************************************************************/
uint32_t AD9954_Read_nByte(uint8_t ReadAddr,uint8_t Len)
{
uint8_t t=0;
uint32_t temp=0;
AD9954_CS=1;
AD9954_Send_Byte(ReadAddr);
for(t=0;t< Len;t++)
{
temp< <=8;
temp+=AD9954_Read_Byte();
}
AD9954_CS=1;
return temp;
}
/************************************************************
** 函數名稱 :uint32_t Get_FTW(double Real_fH)
** 函數功能 :頻率數據轉換
** 入口參數 :Freq,需要轉換的頻率,0-140000000hz
** 出口參數 :頻率數據值
** 函數說明 :
**************************************************************/
uint32_t Get_FTW(double Real_fH)
{
return (uint32_t)(fH_Num*Real_fH);
}
/*********************************************************************************************************
** 函數名稱 :void AD9954_Init(void))
** 函數功能 :初始化AD9954的管腳和最簡單的內部寄存器的配置,
** 入口參數 :無
** 出口參數 :無
** 函數說明 :板上的晶振為20MHz,最大采用了20倍頻,為400M
*********************************************************************************************************/
void AD9954_Init(void)
{
uint8_t CFR1_data[4]={0,0,0,0};
uint8_t CFR2_data[3]={0,0,0};
AD9954_GPIO_Init();
AD9954_RESET();
delay_ms(300);
AD9954_CS = 0;
CFR1_data[0]=0X02;//此處:0x02- >OSK使能;0X00- >OSK關閉。在OSK模式使能的前提下,幅度寄存器(0X02)生效
//見英文數據手冊,page 31 :Amplitude Scale Factor (ASF)部分
//In manual OSK
//mode, ASF< 15:14 > has no effect. ASF< 13:0 > provide the output
//scale factor directly. If the OSK is disabled using CFR1< 25 >,
//this register has no effect on device operation.
CFR1_data[1]=0X00;
CFR1_data[2]=0X00;
CFR1_data[3]=0x00;//比較器啟用,方波輸出;0x40,比較器禁用方波無輸出
AD9954_Write_nByte(CFR1,CFR1_data,4);//數據寫入控制功能寄存器1
CFR2_data[0]=0X00;
CFR2_data[1]=0X00;
if(fs >400)
;//系統頻率超過芯片最大值
else if(fs >=250)
CFR2_data[2]=PLL_MULTIPLIER< 3|0x04|0X03;
else CFR2_data[2]=PLL_MULTIPLIER< 3;
AD9954_Write_nByte(CFR2,CFR2_data,3);//數據寫入控制功能寄存器2
AD9954_CS=1;
}
/*********************************************************************************************************
** 函數名稱 :void AD9954_Set_Fre(double fre)
** 函數功能 :設置AD9954當前的頻率輸出,采用的是單一頻率輸出
** 入口參數 :fre:欲設置的頻率值 0-140000000hz
** 出口參數 :無
** 函數說明 :因為采用的浮點數進行計算,轉換過程中會出現誤差,通過調整可以精確到0.1Hz以內
*********************************************************************************************************/
void AD9954_Set_Fre(double fre)//single tone
{
uint8_t date[4] ={0x00,0x00,0x00,0x00}; //中間變量
uint32_t Temp=0;
Temp=Get_FTW(fre);
date[0] =(uint8_t)(Temp > > 24);
date[1] =(uint8_t)(Temp > > 16);
date[2] =(uint8_t)(Temp > > 8);
date[3] =(uint8_t)Temp;
AD9954_CS = 0;
AD9954_Write_nByte(FTW0,date,4);//寫頻率控制字
AD9954_CS=1;
UPDATE();
}
/*********************************************************************************************************
** 函數名稱 :void AD9954_Set_Amp(uint16_t Ampli)
** 函數功能 :設置AD9954輸出幅度
** 入口參數 :Ampli:0-16383,最大峰峰值約500mv
** 出口參數 :無
** 函數說明 :
*********************************************************************************************************/
void AD9954_Set_Amp(uint16_t Ampli)
{
uint8_t date[2] ={0x00,0x00};
AD9954_CS = 0;
date[0]=(uint8_t)(Ampli > > 8);
date[1]=(uint8_t)Ampli;
AD9954_Write_nByte(ASF,date,2);
AD9954_CS = 1;
UPDATE();
}
/************************************************************
** 函數名稱 :void AD9954_Set_Phase(uint8_t Channel,uint16_t Phase)
** 函數功能 :設置通道的輸出相位
** 入口參數 :Phase: 輸出相位,范圍:0~16383(對應角度:0°~360°)
** 出口參數 :無
** 函數說明 :無
**************************************************************/
void AD9954_Set_Phase(uint16_t Phase)//寫相位
{
uint8_t date[2] ={0x00,0x00};
AD9954_CS = 0;
date[0]=(uint8_t)(Phase > > 8);
date[1]=(uint8_t)Phase;
AD9954_Write_nByte(POW0,date,2);
AD9954_CS = 1;
UPDATE();
}
/*********************************************************************************************************
** 函數名稱 :void AD9954_SetFSK(double f1,double f2,double f3,double f4,uint16_t Ampli)
** 函數功能 :四相FSK信號輸出參數設置
** 入口參數 :f1:頻率1 0-140000000hz
** f2:頻率2
** f3:頻率3
** f4:頻率4
** Ampli幅度:0-16383,最大峰峰值約500mv
** 出口參數 :無
** 隱含控制 PS0: 0 1 0 1
** 管腳參數: PS1: 0 0 1 1
** 對應控制 RAM段: 0 1 2 3
** 函數說明 :在四個RAM區各設置了一個頻率值,通過改變PS0和PS1的電平選擇對應的RAM端輸出相應的頻率值來實現FSK,也可以實現二項的FSK;
** 通過設置控制PS0,PS1管腳的電平就可以將二進制的編碼轉化為FSK信號輸出
*********************************************************************************************************/
void AD9954_SetFSK(double f1,double f2,double f3,double f4,uint16_t Ampli)
{
uint32_t FTW_Vau=0;
uint8_t fdata[4]={0,0,0,0};
uint8_t CFR1_data[4]={0,0,0,0};
uint8_t data[5]={0,0,0,0,0};
AD9954_CS = 0;
data[0]=0x00; //低8位 斜率=0x0000
data[1]=0x00; //高8位 斜率=0x0000
data[2]=0x00; //終止地址:0x0000 低8位
data[3]=0x00; //0:1終止地址:高2位,2:7起始地址低6位:0x000;
data[4]=0x00; //0:3起始地址高4位 5:7,RAM0工作于模式0; 4:不停留位沒有激活
AD9954_Write_nByte(RSCW0,data,5);
data[0]=0x00; //低8位 斜率=0x0000
data[1]=0x00; //高8位 斜率=0x0000
data[2]=0x01; //終止地址:0x0001 低8位
data[3]=0x04; //0:1終止地址:高2位,2:7起始地址低6位:0x0001;
data[4]=0x00; //0:3起始地址高4位 5:7,RAM1工作于模式0; 4:不停留位沒有激活
AD9954_Write_nByte(RSCW1,data,5);
data[0]=0x00; //低8位 斜率=0x0000
data[1]=0x00; //高8位 斜率=0x0000
data[2]=0x02; //終止地址:0x0002 低8位
data[3]=0x08; //0:1終止地址:高2位,2:7起始地址低6位:0x0002;
data[4]=0x00; //0:3起始地址高4位 5:7,RAM2工作于模式0; 4:不停留位沒有激活
AD9954_Write_nByte(RSCW2,data,5);
data[0]=0x00; //低8位 斜率=0x0000
data[1]=0x00; //高8位 斜率=0x0000
data[2]=0x03; //終止地址:0x0003 低8位
data[3]=0x0c; //0:1終止地址:高2位,2:7起始地址低6位:0x0003;
data[4]=0x00; //0:3起始地址高4位 5:7,RAM3工作于模式0; 4:不停留位沒有激活
AD9954_Write_nByte(RSCW3,data,5);
AD9954_CS = 1;
UPDATE();
AD9954_CS = 0;
PS1=0;PS0=0;
FTW_Vau=Get_FTW(f1);
fdata[0]=FTW_Vau >>24;
fdata[1]=FTW_Vau >>16;
fdata[2]=FTW_Vau >>8;
fdata[3]=FTW_Vau;
AD9954_Write_nByte(RAM,fdata,4);
PS1=0;PS0=1;
FTW_Vau=Get_FTW(f2);
fdata[0]=FTW_Vau >>24;
fdata[1]=FTW_Vau >>16;
fdata[2]=FTW_Vau >>8;
fdata[3]=FTW_Vau;
AD9954_Write_nByte(RAM,fdata,4);
PS1=1;PS0=0;
FTW_Vau=Get_FTW(f3);
fdata[0]=FTW_Vau >>24;
fdata[1]=FTW_Vau >>16;
fdata[2]=FTW_Vau >>8;
fdata[3]=FTW_Vau;
AD9954_Write_nByte(RAM,fdata,4);
PS1=1;PS0=1;
FTW_Vau=Get_FTW(f4);
fdata[0]=FTW_Vau >>24;
fdata[1]=FTW_Vau >>16;
fdata[2]=FTW_Vau >>8;
fdata[3]=FTW_Vau;
AD9954_Write_nByte(RAM,fdata,4);
AD9954_CS = 1;
UPDATE();
AD9954_CS = 0;
CFR1_data[0]=0X82;//打開RAM控制位驅動FTW
CFR1_data[1]=0X00;
CFR1_data[2]=0X00;
CFR1_data[3]=0x00;//比較器啟用,方波輸出;0x40,比較器禁用方波無輸出
AD9954_Write_nByte(CFR1,CFR1_data,4);//數據寫入控制功能寄存器1
AD9954_CS = 1;
UPDATE();
AD9954_Set_Amp(Ampli);//設置幅度
}
/*********************************************************************************************************
** 函數名稱 :void AD9954_SetPSK(uint16_t Phase1,uint16_t Phase2,uint16_t Phase3,uint16_t Phase4,double fre,uint16_t Ampli)
** 函數功能 :四相PSK信號輸出參數設置
** 入口參數 :Phase1:相位1 范圍:0-16383 對應0-360度
** Phase2:相位2
** Phase3:相位3
** Phase4:相位4
** fre:頻率 0-140000000hz
** Ampli幅度:0-16383,最大峰峰值約500mv
** 出口參數 :無
** 隱含控制 PS0: 0 1 0 1
** 管腳參數: PS1: 0 0 1 1
** 對應控制 RAM段: 0 1 2 3
** 函數說明 :在四個RAM區各設置了一個頻率值,通過改變PS0和PS1的電平選擇對應的RAM端輸出相應的頻率值來實現PSK,也可以實現二項的PSK;
** 通過設置控制PS0,PS1管腳的電平就可以將二進制的編碼轉化為PSK信號輸出
*********************************************************************************************************/
void AD9954_SetPSK(uint16_t Phase1,uint16_t Phase2,uint16_t Phase3,uint16_t Phase4,double fre,uint16_t Ampli)
{
uint8_t pdata[4]={0,0,0,0};
uint8_t CFR1_data[4]={0,0,0,0};
uint8_t data[5]={0,0,0,0,0};
AD9954_CS = 0;
data[0]=0x00; //低8位 斜率=0x0000
data[1]=0x00; //高8位 斜率=0x0000
data[2]=0x00; //終止地址:0x0000 低8位
data[3]=0x00; //0:1終止地址:高2位,2:7起始地址低6位:0x000;
data[4]=0x00; //0:3起始地址高4位 5:7,RAM0工作于模式0; 4:不停留位沒有激活
AD9954_Write_nByte(RSCW0,data,5);
data[0]=0x00; //低8位 斜率=0x0000
data[1]=0x00; //高8位 斜率=0x0000
data[2]=0x01; //終止地址:0x0001 低8位
data[3]=0x04; //0:1終止地址:高2位,2:7起始地址低6位:0x0001;
data[4]=0x00; //0:3起始地址高4位 5:7,RAM1工作于模式0; 4:不停留位沒有激活
AD9954_Write_nByte(RSCW1,data,5);
data[0]=0x00; //低8位 斜率=0x0000
data[1]=0x00; //高8位 斜率=0x0000
data[2]=0x02; //終止地址:0x0002 低8位
data[3]=0x08; //0:1終止地址:高2位,2:7起始地址低6位:0x0002;
data[4]=0x00; //0:3起始地址高4位 5:7,RAM2工作于模式0; 4:不停留位沒有激活
AD9954_Write_nByte(RSCW2,data,5);
data[0]=0x00; //低8位 斜率=0x0000
data[1]=0x00; //高8位 斜率=0x0000
data[2]=0x03; //終止地址:0x0003 低8位
data[3]=0x0c; //0:1終止地址:高2位,2:7起始地址低6位:0x0003;
data[4]=0x00; //0:3起始地址高4位 5:7,RAM3工作于模式0; 4:不停留位沒有激活
AD9954_Write_nByte(RSCW3,data,5);
AD9954_CS = 1;
UPDATE();
Phase1< <=2;
Phase2< <=2;
Phase3< <=2;
Phase4< <=2;
AD9954_CS = 0;
PS1=0;PS0=0;
pdata[0]=(uint8_t)(Phase1 >>8);
pdata[1]=(uint8_t)Phase1;
pdata[2]=0x00;
pdata[3]=0x00;
AD9954_Write_nByte(RAM,pdata,4);
PS1=0;PS0=1;
pdata[0]=(uint8_t)(Phase2 >>8);
pdata[1]=(uint8_t)Phase2;
pdata[2]=0x00;
pdata[3]=0x00;
AD9954_Write_nByte(RAM,pdata,4);
PS1=1;PS0=0;
pdata[0]=(uint8_t)(Phase3 >>8);
pdata[1]=(uint8_t)Phase3;
pdata[2]=0x00;
pdata[3]=0x00;
AD9954_Write_nByte(RAM,pdata,4);
PS1=1;PS0=1;
pdata[0]=(uint8_t)(Phase4 >>8);
pdata[1]=(uint8_t)Phase4;
pdata[2]=0x00;
pdata[3]=0x00;
AD9954_Write_nByte(RAM,pdata,4);
AD9954_CS = 1;
UPDATE();
AD9954_CS = 0;
CFR1_data[0]=0Xc2;//打開RAM控制位驅動POW相位
CFR1_data[1]=0X00;
CFR1_data[2]=0X00;
CFR1_data[3]=0x00;//比較器啟用,方波輸出;0x40,比較器禁用方波無輸出
AD9954_Write_nByte(CFR1,CFR1_data,4);//數據寫入控制功能寄存器1
AD9954_CS = 1;
UPDATE();
AD9954_Set_Amp(Ampli);//設置幅度
AD9954_Set_Fre(fre);
}
/*********************************************************************************************************
** 函數名稱 :void AD9954_Set_LinearSweep(double Freq_Low,double Freq_High,double UpStepFreq,
** uint8_t UpStepTime,double DownStepFreq, uint8_t DownStepTime,uint8_t mode)
** 函數功能 :線性掃描輸出模式
** 函數說明 :使頻率按預置的模式線性掃描上去,詳細參見官方PDF
** 入口參數 :Freq_Low:起始頻率 0-140000000hz
** Freq_High:終止頻率; 0-140000000hz
** UpStepFreq:向上掃頻步進, 0-140000000hz
** UpStepTime:向上掃頻的步進間隔時間;1-255
** DownStepFreq:向下掃頻步進, 0-140000000hz
** DownStepTime:向下掃頻的步進間隔時間;1-255
** mode:線性掃描無停留功能,No_Dwell不停留,輸出掃頻到終止頻率回到起始頻率;Dwell停留,輸出掃頻到終止頻率后保持在終止頻率。
** 出口參數 :無
** 函數說明 :需要保證,Freq_Low< Freq_High
** 步進間隔時間 T = StepTime*10 ;例:UpStepTime=100,則向上掃頻的步進間隔時間T=1000nS=1us
** 掃頻總時間=總掃描頻點數*T
** PS0腳控制掃頻方向,PS0=1向上掃頻,PS0=0向下掃頻
*********************************************************************************************************/
void AD9954_Set_LinearSweep(double Freq_Low,double Freq_High,double UpStepFreq, uint8_t UpStepTime,double DownStepFreq, uint8_t DownStepTime,uint8_t mode)//linear sweep mode
{
uint8_t date[5] ={0x00,0x00,0x00,0x00,0x00}; //中間變量
uint8_t CFR1_data[4] ={0x00,0x00,0x00,0x00};
uint32_t Temp=0;
PS1=0;PS0=0;
AD9954_CS=0;
CFR1_data[0]=0x00;//31-24
CFR1_data[1]=0x20;//23-16
CFR1_data[2]=0x00;
CFR1_data[3]=0x00|mode;//比較器啟用,方波輸出;0x40,比較器禁用方波無輸出
AD9954_Write_nByte(CFR1,CFR1_data,4);//數據寫入控制功能寄存器1
Temp=Get_FTW(Freq_Low);
date[0] =(uint8_t)(Temp > > 24);
date[1] =(uint8_t)(Temp > > 16);
date[2] =(uint8_t)(Temp > > 8);
date[3] =(uint8_t)Temp;
AD9954_Write_nByte(FTW0,date,4);//寫頻率控制字
Temp=Get_FTW(Freq_High);
date[0] =(uint8_t)(Temp > > 24);
date[1] =(uint8_t)(Temp > > 16);
date[2] =(uint8_t)(Temp > > 8);
date[3] =(uint8_t)Temp;
AD9954_Write_nByte(FTW1,date,4);//寫頻率控制字
Temp=Get_FTW(DownStepFreq);
date[0] =DownStepTime;//下降的掃描斜率
date[1] =(uint8_t)(Temp > > 24);
date[2] =(uint8_t)(Temp > > 16);
date[3] =(uint8_t)(Temp > > 8);
date[4] =(uint8_t)Temp;//下降的頻率增量
AD9954_Write_nByte(NLSCW,date,5);
Temp=Get_FTW(UpStepFreq);
date[0] =UpStepTime;//上升的掃描斜率
date[1] =(uint8_t)(Temp > > 24);
date[2] =(uint8_t)(Temp > > 16);
date[3] =(uint8_t)(Temp > > 8);
date[4] =(uint8_t)Temp;//上升的頻率增量
AD9954_Write_nByte(PLSCW,date,5);
AD9954_CS=1;
UPDATE();
}
main.c
#include "stm32_config.h"
#include "stdio.h"
#include "key.h"
#include "Encoder.h"
#include "OLED.h"
#include "ad9954.h"
#include "timer.h"
uint8_t KeyNum, key;
uint32_t last_value = 140000000;
uint32_t Fre = 1000;
uint32_t Amp = 16383;
uint32_t Phase = 0;
int main(void)
{
MY_NVIC_PriorityGroup_Config(NVIC_PriorityGroup_2); //設置中斷分組
delay_init(72); //初始化延時函數
Key_Init();
Timer_Init();
OLED_Init();
Encoder_Init();
AD9954_Init(); //初始化控制AD9954需要用到的IO口,及寄存器
delay_ms(100);
OLED_ShowString(0,5,"AD9954",16,1);
// OLED_ShowChinese(70,5,0,16,1);
// OLED_ShowChinese(86,5,1,16,1);
OLED_ShowString(95,150,"Hz",16,1);
OLED_Refresh();
// AD9954_Set_LinearSweep(100000,500000,1,200,1,200,Dwell); //掃頻,Dwell停留,輸出掃頻到終止頻率后保持在終止頻率。No_Dwell不停留,輸出掃頻到終止頻率后回到起始頻率;
//起始100000Hz,終止500000Hz,上掃頻步進1hz,上掃頻時間約800ms;下掃頻步進1hz,下掃頻時間約800ms;掃頻時間計算參考函數注解
while(1)
{
Encoder_Value_Update();
Encoder_Display();
Fre = Encoder_GetValue();
if (Fre >= last_value)
{
Fre = last_value;
}
KeyNum += Key_GetNum();
if(KeyNum > 2) KeyNum = 1;
switch (KeyNum)
{
case 1: // 調節幅值
if(Amp >= 16383) Amp = 16383;
OLED_ShowChinese(70,5,0,16,1);
OLED_ShowChinese(86,5,1,16,1);
Amp += Key_GetValue();
break;
case 2: // 調節相位
if(Phase >= 16383) Phase = 16383;
OLED_ShowChinese(70,5,2,16,1);
OLED_ShowChinese(86,5,3,16,1);
Phase += Key_GetValue();
break;
}
AD9954_Set_Fre(Fre);//設置輸出頻率1000Hz
AD9954_Set_Amp(Amp);//設置幅度,范圍0~16383 (對應幅度約:0~500mv)
AD9954_Set_Phase(Phase);//設置相位,范圍0~16383(對應角度:0°~360°)
OLED_ShowNum(20, 150, Fre, 9, 16, 1);
OLED_ShowNum(10, 175, Amp, 5, 16, 1);
OLED_ShowNum(70, 175, Phase, 5, 16, 1);
OLED_Refresh();
delay_ms(10);
//掃頻
// PS0=1;//PS0控制掃頻方向;高電平:從起始值掃到結束值
// delay_ms(500);
// PS0=0;//低電平:從結束值掃到起始值
// delay_ms(500);
}
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
key++;
if(key > 20)
{
Key_Loop();
key = 0;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
效果展示

雙向線性掃頻模式
六、注意事項與常見問題
注意事項
(1)模塊為低功耗模塊,供電電源不超過5.5V。
(2)由于模塊是高精度器件,為了避免不必要的干擾,建議使用線性電源供電。
(3)輸出信號建議使用SMA轉BNC的線直接示波器觀測效果,接觸不良或劣質的線材可能導致信號衰減或者噪聲過大。
(4)如需簡單測試模塊功能,建議搭配本店控制板使用,先給DDS模塊供電,再給控制板供電即可產生波形,長按中間鍵切換功能。
常見問題
Q:模塊的主頻和輸出幅度可以調節嗎?
A:模塊的主頻是輸入時鐘和程序一起決定的,模塊可以外部輸入時鐘,板載默認時鐘為20MHz,程序控制倍頻為20倍,即默認主頻為 400MHz,可以通過修改輸入時鐘和倍頻數改變主頻,輸出幅度可以通過修改14位幅度寄存器控制輸出幅度。
Q:模塊可以實現掃頻么?方波占空比可調嗎?
A:模塊可以實現掃頻。提供的例程可支持掃頻。模塊方波幅度和占空比都不能調節,正弦波頻率、幅度可以調節。
Q:可以做AM等調制嗎?
A:可以通過改變幅度寄存器實現低速的AM調制,并且具有多種掃頻模式,默認代碼是軟件單音掃頻,其他模式需要自行編程。
審核編輯 黃宇
-
DDS
+關注
關注
22文章
687瀏覽量
156767 -
信號發生器
+關注
關注
28文章
1713瀏覽量
113576 -
STM32F103
+關注
關注
34文章
497瀏覽量
68005
發布評論請先 登錄
多個AD9954同步:怎么使得這兩個信號同時起震也就是同向
AD9954調制基帶板和DDS不同源頻譜很差
基于AD9954的多模式調制器的設計
基于AD9954的正弦信號發生器
dds信號發生器功能及原理
基于FPGA的DDS信號發生器設計方案解析
DDS函數信號發生器是什么_DDS函數信號發生器原理及使用方法
高集成度DDS器件AD9954的特點及在數字調制系統設計中的應用
基于STM32F103驅動AD9833模塊 DDS信號發生器輸出正弦波/三角波/方波可編程信號
基于STM32F103驅動AD9954 高速DDS信號發生器模塊輸出波形信號
評論