基于STM32F103 并行驅動AD9851模塊 DDS函數(shù)信號發(fā)生器輸出正弦波/方波信號

一、AD9851模塊簡介

??AD9851是一款高度集成的器件,采用先進的DDS技術,再加上內(nèi)部高速,高性能的D/A轉換器和比較器,形成一個數(shù)字可編程頻率合成器和時鐘發(fā)生器功能。當參考準確的時鐘源時,AD9851產(chǎn)生穩(wěn)定的頻率并進行相位可編程的數(shù)字化模擬輸出正弦波。該正弦波可以直接用作頻率源,或內(nèi)部轉換為方波敏捷時鐘生成器應用程序。 AD9851的創(chuàng)新高速DDS內(nèi)核接受32位頻率調(diào)諧字,導致輸出調(diào)諧分辨率約為系統(tǒng)時鐘為180MHz時為0.04Hz。AD9851包含獨特的 6XREFCLK乘法器電路消除了需要一個高速參考振蕩器。 6XREFCLK乘法器對SFDR和相位噪聲特性的影響最小。
特性

  • 通訊協(xié)議:SPI串行/并行
  • 180MHz時鐘頻率,可選6位參考時鐘
  • DAC分辨率:10位
  • 相位累加器:32位
  • 輸出信號:正弦波,方波。正弦波帶65MHz低通濾波器,方波耦合輸出
  • 輸出通道:2通道差分。相位差180度,高頻輸出由于有濾波器,相位會偏移
  • 信號特點:正弦波無耦合輸出。輸出帶自帶直流分量,接入射頻設備請加隔直器也可直接使用示波器測量
  • 輸出正弦波/方波最高主頻:1Hz-65M/30MHz,方波10MHz以上需要示波器輸入阻抗為50歐,方波占空比可調(diào)
  • 輸出幅度:正弦波1000mVpp,方波5Vpp,正弦波隨頻率增加幅度減小,方波隨著頻率增加波形變化
  • 輸出阻抗:75歐

二、AD9851引腳說明

D0-D7 8 位數(shù)據(jù)輸入。用于加載 32 位頻率字和 8 位相位/控制字的數(shù)據(jù)端口。D7 = MSB,D0 = LSB。D7也用作 40 位串行數(shù)據(jù)字的輸入引腳。
W_CLK 串行時鐘輸入。上升沿將并行或串行頻率/相位/控制字異步加載到 40 位輸入寄存器中。
FQ_UD 頻率更新。上升沿異步傳輸 40 位輸入寄存器的內(nèi)容,以供 DDS 內(nèi)核處理。當已知輸入寄存器的內(nèi)容僅包含有效且允許的數(shù)據(jù)時,應發(fā)出 FQ_UD。
RSET 主復位引腳,高電平有效。
OUT DAC差分輸出

三、功能框圖和時序圖分析

時序簡單分析:

  1. 復位
    RESET 拉高 → 相位累加器清零,默認進入 并行模式,PLL 關閉。
  2. 并行方式
    每次通過 W0–W4 裝載 40 位數(shù)據(jù)(8 位一組),W0 含控制字與相位字,W1–W4 為頻率調(diào)諧字。
    WCLK 上升沿鎖存數(shù)據(jù),最后 FQ_UD 上升沿觸發(fā)更新。
  3. 串行方式
    首先在并行方式下寫入特殊碼 xxxxx011 → 切換至串行。
    串行移入 40 位數(shù)據(jù),LSB 先行,最后 FQ_UD 上升沿更新。
  4. 延遲
    頻率更新延遲:約 18 個 SYSCLK 周期。
    相位更新延遲:約 13 個 SYSCLK 周期。

四、并行/串行裝載 40位控制字分配

??并行裝載:W0 是“控制 + 相位”字;W1~W4 是 32 位頻率調(diào)諧字(FTW,W1 放 MSB)。其中W0位定義為:
????D7…D3:Phase[4:0](D7 是相位 MSB,D3 是相位 LSB,步進 11.25°)
????D2:低功耗
????D1:邏輯 0(僅在“請求進入串行模式”時臨時使用;進入后必須再寫回 0)
????D0:6× REFCLK 倍頻使能


??串行裝載:40-bit 一次性移入,先 32 位頻率,再控制,再相位。


進入串行模式需要留意的地方:
??上電復位后默認并行模式。在并行端口寫入 W0 時,把 D1 置 1(僅用于“請求串行”),D0 按你是否要啟用 ×6 設置;隨后按手冊 Figure 17 的時序切換到串行移位口。進入后務必再把并口 W0 的 D1 寫回 0。串行移位是按位 LSB-first;若用 MCU 的 SPI(通常 MSB-first),要么“反相/反序”配置 SPI,要么對每個字節(jié)做逐字節(jié)位反轉再發(fā)。


五、STM32F103驅動AD9851

準備工作

??STM32F103ZET6開發(fā)板、AD9851模塊、OLED顯示屏、EC11旋轉編碼器。

接線說明

STM32F103ZET6 AD9851模塊
PA3 FQ
PA4 CLK
PA6 REST
PC0 D0
PC1 D1
PC2 D2
PC3 D3
PC4 D4
PC5 D5
PC6 D6
PC7 D7
PA0 旋轉編碼器-A ,用于調(diào)節(jié)輸出頻率
PA1 旋轉編碼器-B ,用于調(diào)節(jié)輸出頻率
PA2 旋轉編碼器-S,移位調(diào)節(jié)
PB8 OLED-SCL
PB9 OLED-SDA
5V 5V
GND 共地

其中,當使用串行驅動時,DO、D1、D2腳需輸入(110)固定電平,D3-6可以懸空不接,D7用作40位串行數(shù)據(jù)輸入引腳。

示例代碼

AD9851.c

//***************************************************//
//函數(shù)1:           ad9851_reset()                    //
//函數(shù)2:           ad9851_reset_serial()             //
//函數(shù)3:           ad9851_wr_parrel(unsigned char w0,double frequence)//
//函數(shù)4:           ad9851_wr_serial(unsigned char w0,double frequence)//
//***************************************************//
//                  子程序說明                       //
//***************************************************//
//函數(shù)1:  ad9851_reset()
//        復位ad9851,之后為并口寫入模式        
//函數(shù)2:  ad9851_reset_serial()
//        復位ad9851,之后為串口寫入模式
//函數(shù)3:  ad9851_wr_parrel(unsigned char w0,double frequence)
//        并口寫ad9851數(shù)據(jù),w0為ad9851中w0的數(shù)據(jù),frequence
//        為寫入的頻率    
//函數(shù)4:  ad9851_wr_serial(unsigned char w0,double frequence)
//        串口寫ad9851數(shù)據(jù),w0為ad9851中w0的數(shù)據(jù),frequence
//        為寫入的頻率    
//需定義的位:
         //ad9851_w_clk    ;
         //ad9851_fq_up    ;
         //ad9851_rest     ;
         //ad9851_bit_data ;
//例:
         //sbit ad9851_w_clk    =P2^2;
         //sbit ad9851_fq_up    =P2^1;
         //sbit ad9851_rest     =P2^0;
         //sbit ad9851_bit_data =P1^7;
//***************************************************//
//                 寫數(shù)據(jù)說明                        //
//***************************************************//
//寫數(shù)據(jù)例:
//       ad9851_reset()
//       wr_lcd02_data(unsigned char x)
//       ad9851_wr_parrel(0x01,1000)
//       ad9851_wr_serial(0x01,1000)
//***************************************************//
//---------------------------------------------------//
//                   程序                            //
//---------------------------------------------------//
# include <AD9851.h>
# include <stdio.h>

u8 AD9851_FD=0x00; //倍頻數(shù)
void (*_AD9851_Setfq)(u8 w0,double frequence);
//P1為8位數(shù)據(jù)口
//***************************************************//
//              ad9851復位(并口模式)                 //
//---------------------------------------------------//
void ad9851_reset()
{
ad9851_w_clk=0;
ad9851_fq_up=0;
//rest信號
ad9851_rest=0;
ad9851_rest=1;
ad9851_rest=0;
}
//***************************************************//
//              ad9851復位(口模式)                 //
//---------------------------------------------------//
void ad9851_reset_serial()
{
ad9851_w_clk=0;
ad9851_fq_up=0;
//rest信號
ad9851_rest=0;
ad9851_rest=1;
ad9851_rest=0;
//w_clk信號
ad9851_w_clk=0;
ad9851_w_clk=1;
ad9851_w_clk=0;
//fq_up信號
ad9851_fq_up=0;
ad9851_fq_up=1;
ad9851_fq_up=0;
}
//***************************************************//
//          向ad9851中寫命令與數(shù)據(jù)(并口)             //
//---------------------------------------------------//
void ad9851_wr_parrel(u8 w0,double frequence)
{
u32 w;
long int y;
double x;
//計算頻率的HEX值
x=4294967295/180;//適合180M晶振/180為最終時鐘頻率(或30M六倍頻)
//如果時鐘頻率不為180MHZ,修改該處的頻率值,單位MHz ?。。?frequence=frequence/1000000;
frequence=frequence*x;
y=frequence;
//寫w0數(shù)據(jù)
w=w0;   
AD9851_DataBus=w|(w^0xff)<<16;     //w0
ad9851_w_clk=1;
ad9851_w_clk=0;
//寫w1數(shù)據(jù)
w=(y>>24);
AD9851_DataBus=w|(w^0xff)<<16;     //w0
ad9851_w_clk=1;
ad9851_w_clk=0;
//寫w2數(shù)據(jù)
w=(y>>16);
AD9851_DataBus=w|(w^0xff)<<16;     //w0
ad9851_w_clk=1;
ad9851_w_clk=0;
//寫w3數(shù)據(jù)
w=(y>>8);
AD9851_DataBus=w|(w^0xff)<<16;     //w0
ad9851_w_clk=1;
ad9851_w_clk=0;
//寫w4數(shù)據(jù)
w=(y>>=0);
AD9851_DataBus=w|(w^0xff)<<16;     //w0
ad9851_w_clk=1;
ad9851_w_clk=0;
//移入始能
ad9851_fq_up=1;
ad9851_fq_up=0;
}
//***************************************************//
//          向ad9851中寫命令與數(shù)據(jù)(串口)             //
//---------------------------------------------------//
void ad9851_wr_serial(u8 w0,double frequence)
{
unsigned char i,w;
long int y;
double x;
//計算頻率的HEX值
x=4294967295/125;//適合180M晶振/180為最終時鐘頻率(或30M六倍頻)
//如果時鐘頻率不為180MHZ,修改該處的頻率值,單位MHz  ?。。?frequence=frequence/1000000;
frequence=frequence*x;
y=frequence;
//寫w4數(shù)據(jù)
w=(y>>=0);
for(i=0;i<8;i++)
{
ad9851_bit_data=(w>>i)&0x01;
ad9851_w_clk=1;
ad9851_w_clk=0;
}
//寫w3數(shù)據(jù)
w=(y>>8);
for(i=0;i<8;i++)
{
ad9851_bit_data=(w>>i)&0x01;
ad9851_w_clk=1;
ad9851_w_clk=0;
}
//寫w2數(shù)據(jù)
w=(y>>16);
for(i=0;i<8;i++)
{
ad9851_bit_data=(w>>i)&0x01;
ad9851_w_clk=1;
ad9851_w_clk=0;
}
//寫w1數(shù)據(jù)
w=(y>>24);
for(i=0;i<8;i++)
{
ad9851_bit_data=(w>>i)&0x01;
ad9851_w_clk=1;
ad9851_w_clk=0;
}
//寫w0數(shù)據(jù)
w=w0;   
for(i=0;i<8;i++)
{
ad9851_bit_data=(w>>i)&0x01;
ad9851_w_clk=1;
ad9851_w_clk=0;
}
//移入始能
ad9851_fq_up=1;
ad9851_fq_up=0;
}
void AD9851_IO_Init(void)
{
   GPIO_InitTypeDef GPIO_InitStructure ; 
    
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC, ENABLE);  //使能PB,PE端口時鐘

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0| GPIO_Pin_1| GPIO_Pin_2| GPIO_Pin_3| GPIO_Pin_4| GPIO_Pin_5| GPIO_Pin_6| GPIO_Pin_7 ; 
    GPIO_Init(GPIOC ,&GPIO_InitStructure) ;
    
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_3|GPIO_Pin_4| GPIO_Pin_6; 
    GPIO_Init(GPIOA ,&GPIO_InitStructure) ;

}
void AD9851_Setfq(double fq)
{
    if(ad9851_ad9850) 
    {
        fq *= 1.44;
        AD9851_FD = 0;
    }
    _AD9851_Setfq(AD9851_FD,fq);
}
//***************************************************//
//                   測試程序1000Hz                  //
//---------------------------------------------------//
//輸入:mode  ad9851_parallel 并口    ad9851_serial 串口
//FD:0:不倍頻 1:2倍頻
void AD9851_Init(u8 mode,u8 FD)
{
    AD9851_IO_Init();
    AD9851_DataBus=0x00|(~0x00)<<16;
    
//  ad9851_reset_serial();
//  ad9851_wr_serial(0x00,1000000);
    if(mode==ad9851_parallel){_AD9851_Setfq=ad9851_wr_parrel;ad9851_reset();}
    else {_AD9851_Setfq=ad9851_wr_serial;ad9851_reset_serial();}
    if(FD==1)AD9851_FD=0x01;
//  AD9851_Setfq(1000000);
}

main.c

#include "stm32_config.h"
#include "stdio.h"
#include "Encoder.h"
#include "OLED.h"
#include "ad9851.h"

u32 SweepMinFre = 1000;
u32 SweepMaxFre = 1000000;

void SweepFre(void)  
{
    if(SweepMinFre > SweepMaxFre) SweepMinFre = 1000;
    SweepMinFre += SweepMinFre;
    AD9851_Setfq(SweepMinFre);
}

int main(void)
{
    MY_NVIC_PriorityGroup_Config(NVIC_PriorityGroup_2); //設置中斷分組
    delay_init(72); //初始化延時函數(shù)
    
    OLED_Init();
    Encoder_Init();
    delay_ms(300);
    
    AD9851_Init(ad9851_parallel, 1);
    AD9851_Setfq(1000);
//  ad9851_wr_serial(0,1000);
//  delay_ms(100);
    
    OLED_ShowString(40,5,"AD9851",16,1);
    OLED_ShowString(95,160,"Hz",16,1);
    OLED_Refresh();
    
    while(1)
    {   
        Encoder_Value_Update();
        Encoder_Display();
        
        uint32_t value = Encoder_GetValue();
        
        if(value > 65000000) value = 1000;
        AD9851_Setfq(value);
        OLED_ShowNum(20, 160, value, 9, 16, 1);
        OLED_Refresh();
        delay_ms(10);
        
//      SweepFre();
//      delay_ms(200);
    }
}

效果展示

注意事項和常見問題

注意事項
??(1)模塊為低功耗模塊,供電電源不超過5.2V。
??(2)由于模塊是高精度器件,為了避免不必要的干擾,建議使用線性電源供電。
??(3)輸出信號建議使用SMA轉BNC的線直接示波器觀測效果,接觸不良或劣質(zhì)的線材可能導致信號衰減或者噪聲過大。
??(4)配送的代碼僅為配套主控板使用,不提供單片機教程,額外功能需要自行開發(fā)。
??(5)如需簡單測試模塊功能,建議搭配本店控制板使用,先給DDS 模塊供電,再給控制板供電即可產(chǎn)生波形,長按中間鍵切換功能。

常見問題
??Q:AD9851模塊的2個輸出口是什么關系,可以設置成不同的頻率輸出嗎?
??A:AD9851模塊的2個輸出口不能設置成不同的頻率輸出。OUT1與 OUT1相位固定相差180°。
??Q:模快的主頻是多少?輸出幅度可以調(diào)?
??A:模塊的主頻是輸入時鐘和程序一起決定的,板載默認時鐘為30MHz,程序控制倍頻為6倍,即默認主頻為180MHz。輸出幅度是固定的,沒有辦法程控。
??Q:模塊可以實現(xiàn)掃頻么?方波占空比可調(diào)嗎?
??A:模塊可以實現(xiàn)掃頻。本店提供的代碼可支持掃頻。模塊方波占空比可以調(diào)節(jié)。
??Q:兩通道可以獨立調(diào)節(jié)嗎?可以做調(diào)制嗎?
??A:兩個通道固定相差180度,頻率高了由于濾波器作用可能相移,不可獨立調(diào)節(jié)。默認代碼是點頻信號,其他模式需要自行編程。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • """1.個性化消息: 將用戶的姓名存到一個變量中,并向該用戶顯示一條消息。顯示的消息應非常簡單,如“Hello ...
    她即我命閱讀 5,836評論 0 6
  • 為了讓我有一個更快速、更精彩、更輝煌的成長,我將開始這段刻骨銘心的自我蛻變之旅!從今天開始,我將每天堅持閱...
    李薇帆閱讀 2,281評論 1 4
  • 似乎最近一直都在路上,每次出來走的時候感受都會很不一樣。 1、感恩一直遇到好心人,很幸運。在路上總是...
    時間里的花Lily閱讀 1,789評論 1 3
  • 1、expected an indented block 冒號后面是要寫上一定的內(nèi)容的(新手容易遺忘這一點); 縮...
    庵下桃花仙閱讀 1,157評論 1 2
  • 一、工具箱(多種工具共用一個快捷鍵的可同時按【Shift】加此快捷鍵選取)矩形、橢圓選框工具 【M】移動工具 【V...
    墨雅丫閱讀 1,820評論 0 0

友情鏈接更多精彩內(nèi)容